Xamarin.Forms Efeito reutilizável RoundEffect
Importante
Não é mais necessário usar um RoundEffect
para renderizar um controle como um círculo. A última abordagem recomendada é cortar o controle usando um EllipseGeometry
arquivo . Para obter mais informações, consulte Clipe com uma geometria.
O RoundEffect simplifica a renderização de qualquer controle derivado de VisualElement
como um círculo. Esse efeito pode ser usado para criar imagens circulares, botões e outros controles:
Criar um RoutingEffect compartilhado
Uma classe de efeito deve ser criada no projeto compartilhado para criar um efeito entre plataformas. O aplicativo de exemplo cria uma classe vazia RoundEffect
que deriva da RoutingEffect
classe:
public class RoundEffect : RoutingEffect
{
public RoundEffect() : base($"Xamarin.{nameof(RoundEffect)}")
{
}
}
Essa classe permite que o projeto compartilhado resolva as referências ao efeito em código ou XAML, mas não fornece nenhuma funcionalidade. O efeito deve ter implementações para cada plataforma.
Implementar o efeito Android
O projeto da plataforma Android define uma RoundEffect
classe que deriva de PlatformEffect
. Essa classe é marcada com assembly
atributos que permitem Xamarin.Forms resolver a classe de efeito:
[assembly: ResolutionGroupName("Xamarin")]
[assembly: ExportEffect(typeof(RoundEffectDemo.Droid.RoundEffect), nameof(RoundEffectDemo.Droid.RoundEffect))]
namespace RoundEffectDemo.Droid
{
public class RoundEffect : PlatformEffect
{
// ...
}
}
A plataforma Android usa o conceito de an OutlineProvider
para definir as bordas de um controle. O projeto de exemplo inclui uma CornerRadiusProvider
classe que deriva da ViewOutlineProvider
classe:
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);
}
}
Essa classe usa as Width
propriedades e Height
da Xamarin.FormsElement
instância para calcular um raio que é metade da dimensão mais curta.
Depois que um provedor de estrutura de tópicos é definido, a RoundEffect
classe pode consumi-lo para implementar o efeito:
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;
}
}
}
O OnAttached
método é chamado quando o efeito é anexado a um elemento. O objeto existente OutlineProvider
é salvo para que possa ser restaurado quando o efeito for desanexado. Uma nova instância do CornerRadiusOutlineProvider
é usada como o OutlineProvider
e ClipToOutline
é definida como true para cortar elementos transbordantes para as bordas da estrutura de tópicos.
O OnDetatched
método é chamado quando o efeito é removido de um elemento e restaura o valor original OutlineProvider
.
Observação
Dependendo do tipo de elemento, a Control
propriedade pode ou não ser nula. Se a Control
propriedade não for nula, os cantos arredondados poderão ser aplicados diretamente ao controle. No entanto, se for nulo, os cantos arredondados devem ser aplicados ao Container
objeto. O effectTarget
campo permite que o efeito seja aplicado ao objeto apropriado.
Implementar o efeito iOS
O projeto da plataforma iOS define uma RoundEffect
classe que deriva de PlatformEffect
. Essa classe é marcada com assembly
atributos que permitem Xamarin.Forms resolver a classe de efeito:
[assembly: ResolutionGroupName("Xamarin")]
[assembly: ExportEffect(typeof(RoundEffectDemo.iOS.RoundEffect), nameof(RoundEffectDemo.iOS.RoundEffect))]
namespace RoundEffectDemo.iOS
{
public class RoundEffect : PlatformEffect
{
// ...
}
No iOS, os controles têm uma Layer
propriedade, que tem uma CornerRadius
propriedade. A RoundEffect
implementação de classe no iOS calcula o raio de canto apropriado e atualiza a propriedade da CornerRadius
camada:
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;
}
}
O CalculateRadius
método calcula um raio com base na dimensão mínima do Xamarin.FormsElement
. O OnAttached
método é chamado quando o efeito é anexado a um controle e atualiza a propriedade da CornerRadius
camada. Ele define a propriedade para true
que os ClipToBounds
elementos transbordantes sejam cortados nas bordas do controle. O OnDetatched
método é chamado quando o efeito é removido de um controle e reverte essas alterações, restaurando o raio de canto original.
Observação
Dependendo do tipo de elemento, a Control
propriedade pode ou não ser nula. Se a Control
propriedade não for nula, os cantos arredondados poderão ser aplicados diretamente ao controle. No entanto, se for nulo, os cantos arredondados devem ser aplicados ao Container
objeto. O effectTarget
campo permite que o efeito seja aplicado ao objeto apropriado.
Consumir o efeito
Uma vez que o efeito é implementado em todas as plataformas, ele pode ser consumido por Xamarin.Forms controles. Uma aplicação comum do RoundEffect
é tornar um Image
objeto circular. O XAML a seguir mostra o efeito que está sendo aplicado a uma Image
instância:
<Image Source=outdoors"
HeightRequest="100"
WidthRequest="100">
<Image.Effects>
<local:RoundEffect />
</Image.Effects>
</Image>
O efeito também pode ser aplicado no código:
var image = new Image
{
Source = ImageSource.FromFile("outdoors"),
HeightRequest = 100,
WidthRequest = 100
};
image.Effects.Add(new RoundEffect());
A RoundEffect
classe pode ser aplicada a qualquer controle derivado de VisualElement
.
Observação
Para que o efeito calcule o raio correto, o controle ao qual ele é aplicado deve ter dimensionamento explícito. Portanto, as HeightRequest
propriedades e WidthRequest
devem ser definidas. Se o controle afetado aparecer em um StackLayout
, sua HorizontalOptions
propriedade não deve usar um dos valores Expand , como LayoutOptions.CenterAndExpand
ou ele não terá dimensões precisas.