Udostępnij za pośrednictwem


Xamarin.Forms Funkcja RoundEffect wielokrotnego użytku

Ważne

Nie trzeba już używać RoundEffect kontrolki do renderowania kontrolki jako okręgu. Najnowszą zalecaną metodą jest przycinanie kontrolki przy użyciu elementu EllipseGeometry. Aby uzyskać więcej informacji, zobacz Clip with a Geometry (Tworzenie wycinków za pomocą geometrii).

Funkcja RoundEffect upraszcza renderowanie dowolnej kontrolki pochodzącej z VisualElement okręgu. Ten efekt może służyć do tworzenia okrągłych obrazów, przycisków i innych kontrolek:

Zrzuty ekranu RoundEffect w systemach iOS i Android

Tworzenie udostępnionego elementu RoutingEffect

Klasa efektu musi zostać utworzona w projekcie udostępnionym, aby utworzyć efekt międzyplatformowy. Przykładowa aplikacja tworzy pustą RoundEffect klasę pochodzącą RoutingEffect z klasy :

public class RoundEffect : RoutingEffect
{
    public RoundEffect() : base($"Xamarin.{nameof(RoundEffect)}")
    {
    }
}

Ta klasa umożliwia projektowi udostępnionemu rozpoznawanie odwołań do efektu w kodzie lub XAML, ale nie zapewnia żadnych funkcji. Efekt musi mieć implementacje dla każdej platformy.

Implementowanie efektu systemu Android

Projekt platformy systemu Android definiuje klasę pochodzącą RoundEffect z PlatformEffectklasy . Ta klasa jest oznaczona atrybutami assembly , które umożliwiają Xamarin.Forms rozpoznawanie klasy efektu:

[assembly: ResolutionGroupName("Xamarin")]
[assembly: ExportEffect(typeof(RoundEffectDemo.Droid.RoundEffect), nameof(RoundEffectDemo.Droid.RoundEffect))]
namespace RoundEffectDemo.Droid
{
    public class RoundEffect : PlatformEffect
    {
        // ...
    }
}

Platforma Android używa koncepcji elementu OutlineProvider , aby zdefiniować krawędzie kontrolki. Przykładowy projekt zawiera klasę pochodzącą CornerRadiusProvider ViewOutlineProvider z klasy:

class CornerRadiusOutlineProvider : ViewOutlineProvider
{
    Element element;

    public CornerRadiusOutlineProvider(Element formsElement)
    {
        element = formsElement;
    }

    public override void GetOutline(Android.Views.View view, Outline outline)
    {
        float scale = view.Resources.DisplayMetrics.Density;
        double width = (double)element.GetValue(VisualElement.WidthProperty) * scale;
        double height = (double)element.GetValue(VisualElement.HeightProperty) * scale;
        float minDimension = (float)Math.Min(height, width);
        float radius = minDimension / 2f;
        Rect rect = new Rect(0, 0, (int)width, (int)height);
        outline.SetRoundRect(rect, radius);
    }
}

Ta klasa używa Width właściwości Xamarin.FormsElement i Height wystąpienia do obliczania promienia, który jest połowę najkrótszego wymiaru.

Po zdefiniowaniu RoundEffect dostawcy konspektu klasa może jej używać w celu zaimplementowania efektu:

public class RoundEffect : PlatformEffect
{
    ViewOutlineProvider originalProvider;
    Android.Views.View effectTarget;

    protected override void OnAttached()
    {
        try
        {
            effectTarget = Control ?? Container;
            originalProvider = effectTarget.OutlineProvider;
            effectTarget.OutlineProvider = new CornerRadiusOutlineProvider(Element);
            effectTarget.ClipToOutline = true;
        }
        catch (Exception ex)
        {
            Console.WriteLine($"Failed to set corner radius: {ex.Message}");
        }
    }

    protected override void OnDetached()
    {
        if(effectTarget != null)
        {
            effectTarget.OutlineProvider = originalProvider;
            effectTarget.ClipToOutline = false;
        }
    }
}

Metoda jest wywoływana OnAttached , gdy efekt jest dołączony do elementu. Istniejący OutlineProvider obiekt jest zapisywany, aby można go było przywrócić po odłączeniu efektu. Nowe wystąpienie obiektu CornerRadiusOutlineProvider jest używane jako OutlineProvider element i ClipToOutline jest ustawione na wartość true, aby przycinać przepełnianie elementów obramowaniem konspektu.

Metoda OnDetatched jest wywoływana, gdy efekt zostanie usunięty z elementu i przywróci oryginalną OutlineProvider wartość.

Uwaga

W zależności od typu Control elementu właściwość może lub nie może mieć wartości null. Control Jeśli właściwość nie ma wartości null, zaokrąglone rogi można zastosować bezpośrednio do kontrolki. Jeśli jednak ma wartość null, zaokrąglone narożniki muszą zostać zastosowane do Container obiektu. Pole effectTarget umożliwia zastosowanie efektu do odpowiedniego obiektu.

Implementowanie efektu systemu iOS

Projekt platformy systemu iOS definiuje klasę pochodzącą RoundEffect z PlatformEffectklasy . Ta klasa jest oznaczona atrybutami assembly , które umożliwiają Xamarin.Forms rozpoznawanie klasy efektu:

[assembly: ResolutionGroupName("Xamarin")]
[assembly: ExportEffect(typeof(RoundEffectDemo.iOS.RoundEffect), nameof(RoundEffectDemo.iOS.RoundEffect))]
namespace RoundEffectDemo.iOS
{
    public class RoundEffect : PlatformEffect
    {
        // ...
    }

W systemie iOS kontrolki mają Layer właściwość, która ma CornerRadius właściwość . Implementacja RoundEffect klasy w systemie iOS oblicza odpowiedni promień rogu i aktualizuje właściwość warstwy CornerRadius :

public class RoundEffect : PlatformEffect
{
    nfloat originalRadius;
    UIKit.UIView effectTarget;

    protected override void OnAttached()
    {
        try
        {
            effectTarget = Control ?? Container;
            originalRadius = effectTarget.Layer.CornerRadius;
            effectTarget.ClipsToBounds = true;
            effectTarget.Layer.CornerRadius = CalculateRadius();
        }
        catch (Exception ex)
        {
            Console.WriteLine($"Failed to set corner radius: {ex.Message}");
        }
    }

    protected override void OnDetached()
    {
        if (effectTarget != null)
        {
            effectTarget.ClipsToBounds = false;
            if (effectTarget.Layer != null)
            {
                effectTarget.Layer.CornerRadius = originalRadius;
            }
        }
    }

    float CalculateRadius()
    {
        double width = (double)Element.GetValue(VisualElement.WidthRequestProperty);
        double height = (double)Element.GetValue(VisualElement.HeightRequestProperty);
        float minDimension = (float)Math.Min(height, width);
        float radius = minDimension / 2f;

        return radius;
    }
}

Metoda CalculateRadius oblicza promień na podstawie minimalnego Xamarin.FormsElementwymiaru . Metoda OnAttached jest wywoływana, gdy efekt jest dołączony do kontrolki i aktualizuje właściwość warstwy CornerRadius . Ustawia ClipToBounds właściwość na true tak przepełnione elementy są przycięte do obramowań kontrolki. Metoda OnDetatched jest wywoływana, gdy efekt jest usuwany z kontrolki i odwraca te zmiany, przywracając oryginalny promień rogu.

Uwaga

W zależności od typu Control elementu właściwość może lub nie może mieć wartości null. Control Jeśli właściwość nie ma wartości null, zaokrąglone rogi można zastosować bezpośrednio do kontrolki. Jeśli jednak ma wartość null, zaokrąglone narożniki muszą zostać zastosowane do Container obiektu. Pole effectTarget umożliwia zastosowanie efektu do odpowiedniego obiektu.

Korzystanie z efektu

Po zaimplementowaniu efektu na różnych platformach można go używać za pomocą Xamarin.Forms kontrolek. Typowym zastosowaniem obiektu RoundEffect jest tworzenie obiektu cyklicznego Image . Poniższy kod XAML pokazuje efekt stosowany do Image wystąpienia:

<Image Source=outdoors"
       HeightRequest="100"
       WidthRequest="100">
    <Image.Effects>
        <local:RoundEffect />
    </Image.Effects>
</Image>

Efekt można również zastosować w kodzie:

var image = new Image
{
    Source = ImageSource.FromFile("outdoors"),
    HeightRequest = 100,
    WidthRequest = 100
};
image.Effects.Add(new RoundEffect());

Klasę RoundEffect można zastosować do dowolnej kontrolki pochodzącej z klasy VisualElement.

Uwaga

Aby efekt obliczał prawidłowy promień, kontrolka, która jest stosowana, musi mieć jawne ustalanie rozmiaru. W związku z HeightRequest tym należy zdefiniować właściwości i WidthRequest . Jeśli kontrolka, której dotyczy problem, pojawi się w obiekcie StackLayout, jej HorizontalOptions właściwość nie powinna używać jednej z wartości Rozwiń , takich jak LayoutOptions.CenterAndExpand lub nie będzie miała dokładnych wymiarów.