Bagikan melalui


Xamarin.Forms RoundEffect yang Dapat Digunakan Kembali

Penting

Tidak perlu lagi menggunakan RoundEffect untuk merender kontrol sebagai lingkaran. Pendekatan terbaru yang direkomendasikan adalah mengklip kontrol menggunakan EllipseGeometry. Untuk informasi selengkapnya, lihat Klip dengan Geometri.

RoundEffect menyederhanakan penyajian kontrol apa pun yang berasal dari VisualElement sebagai lingkaran. Efek ini dapat digunakan untuk membuat gambar melingkar, tombol, dan kontrol lainnya:

Cuplikan layar RoundEffect di iOS dan Android

Membuat Perutean BersamaEffect

Kelas efek harus dibuat di proyek bersama untuk membuat efek lintas platform. Aplikasi sampel membuat kelas kosong RoundEffect yang berasal dari RoutingEffect kelas :

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

Kelas ini memungkinkan proyek bersama untuk menyelesaikan referensi efek dalam kode atau XAML tetapi tidak menyediakan fungsionalitas apa pun. Efeknya harus memiliki implementasi untuk setiap platform.

Menerapkan efek Android

Proyek platform Android mendefinisikan RoundEffect kelas yang berasal dari PlatformEffect. Kelas ini ditandai dengan assembly atribut yang memungkinkan Xamarin.Forms untuk menyelesaikan kelas efek:

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

Platform Android menggunakan konsep OutlineProvider untuk menentukan tepi kontrol. Proyek sampel mencakup CornerRadiusProvider kelas yang berasal dari ViewOutlineProvider kelas :

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);
    }
}

Kelas ini menggunakan properti Xamarin.FormsElement dan Height instans Width untuk menghitung radius yang setengah dari dimensi terpendek.

Setelah penyedia kerangka didefinisikan RoundEffect , kelas dapat menggunakannya untuk mengimplementasikan efek:

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;
        }
    }
}

Metode OnAttached ini dipanggil ketika efek dilampirkan ke elemen. Objek yang OutlineProvider ada disimpan sehingga dapat dipulihkan ketika efek dilepaskan. Instans CornerRadiusOutlineProvider baru digunakan sebagai OutlineProvider dan ClipToOutline diatur ke true untuk mengklip elemen yang meluap ke batas kerangka.

Metode OnDetatched ini dipanggil ketika efek dihapus dari elemen dan memulihkan nilai asli OutlineProvider .

Catatan

Bergantung pada jenis elemen, Control properti mungkin atau mungkin tidak null. Control Jika properti tidak null, sudut bulat dapat diterapkan langsung ke kontrol. Namun, jika null, sudut bulat harus diterapkan ke Container objek. Bidang effectTarget memungkinkan efek diterapkan ke objek yang sesuai.

Menerapkan efek iOS

Proyek platform iOS mendefinisikan RoundEffect kelas yang berasal dari PlatformEffect. Kelas ini ditandai dengan assembly atribut yang memungkinkan Xamarin.Forms untuk menyelesaikan kelas efek:

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

Di iOS, kontrol memiliki Layer properti , yang memiliki CornerRadius properti . Implementasi RoundEffect kelas pada iOS menghitung radius sudut yang sesuai dan memperbarui properti lapisan 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;
    }
}

Metode CalculateRadius menghitung radius berdasarkan dimensi Xamarin.FormsElementminimum . Metode OnAttached ini dipanggil ketika efek dilampirkan ke kontrol, dan memperbarui properti lapisan CornerRadius . Ini mengatur ClipToBounds properti agar true elemen yang meluap dipotong ke batas kontrol. Metode OnDetatched ini dipanggil ketika efek dihapus dari kontrol dan membalikkan perubahan ini, memulihkan radius sudut asli.

Catatan

Bergantung pada jenis elemen, Control properti mungkin atau mungkin tidak null. Control Jika properti tidak null, sudut bulat dapat diterapkan langsung ke kontrol. Namun, jika null, sudut bulat harus diterapkan ke Container objek. Bidang effectTarget memungkinkan efek diterapkan ke objek yang sesuai.

Mengonsumsi efek

Setelah efek diimplementasikan di seluruh platform, efek tersebut dapat dikonsumsi oleh Xamarin.Forms kontrol. Aplikasi umum dari RoundEffect membuat objek melingkar Image . XAML berikut menunjukkan efek yang diterapkan ke Image instans:

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

Efeknya juga dapat diterapkan dalam kode:

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

Kelas RoundEffect dapat diterapkan ke kontrol apa pun yang berasal dari VisualElement.

Catatan

Agar efek menghitung radius yang benar, kontrol yang diterapkannya harus memiliki ukuran eksplisit. Oleh karena itu, HeightRequest properti dan WidthRequest harus didefinisikan. Jika kontrol yang terpengaruh muncul dalam StackLayout, propertinya HorizontalOptions tidak boleh menggunakan salah satu nilai Perluas seperti LayoutOptions.CenterAndExpand atau tidak akan memiliki dimensi yang akurat.