Xamarin.Forms之Effects的使用

Posted

tags:

篇首语:本文由小常识网(cha138.com)小编为大家整理,主要介绍了Xamarin.Forms之Effects的使用相关的知识,希望对你有一定的参考价值。

在 Xamarin.Forms 2.1.0-pre1 ,Xamarin.Forms新增了新的Effects API. Effects是一系列方法,为了给View的渲染器添加运行时改变. 

然而,我想强调的是, Effects天生被设计为高可复用的. 如果一个Effect能够解决一个难题, 它可能能够在你的整个APP中使用.如果你写了一个Effect来解决你的一个难题, 你能够分享它给其他遇到同样问题的人. 这篇文章尝试展示一种方式,能够帮助我们使分享Effects这件事变得很简单.

public class ShadowEffect : PlatformEffect
{
	protected override void OnAttached ()
	{
		UpdateSize ();
		UpdateColor ();
		UpdateOpacity ();
	}

	protected override void OnDetached ()
	{
		Container.Layer.ShadowOpacity = 0;
	}

	protected override void OnElementPropertyChanged (PropertyChangedEventArgs e)
	{
		Debug.WriteLine (e.PropertyName);
		if (e.PropertyName == ViewExtensions.HasShadowProperty.PropertyName) {
			UpdateOpacity ();
		} else if (e.PropertyName == ViewExtensions.ShadowColorProperty.PropertyName) {
			UpdateColor ();
		} else if (e.PropertyName == ViewExtensions.ShadowSizeProperty.PropertyName) {
			UpdateSize ();
		}
	}

	private void UpdateOpacity ()
	{
		Container.Layer.ShadowOpacity = ViewExtensions.GetHasShadow (Element) ? 1 : 0;
	}

	private void UpdateColor ()
	{
		var color = ViewExtensions.GetShadowColor (Element);
		Container.Layer.ShadowColor = color.ToCGColor ();
	}

	private void UpdateSize ()
	{
		Container.Layer.ShadowRadius = (nfloat)ViewExtensions.GetShadowSize (Element);
	}
}

  上面的代码实在是太多了,我们可以使用下面的方式:

public class ShadowEffect : PlatformEffect
{
	protected override void OnAttached ()
	{
		Container.Layer.ShadowOpacity = 1;
		Container.Layer.ShadowColor = UIColor.Black.ToCGColor;
		Container.Layer.ShadowRadius = 6;
	}

	protected override void OnDetached ()
	{
		Container.Layer.ShadowOpacity = 0;
	}
}

  

使用这种方式来写Effects非常简单,但是同时也导致我们无法方便的配置它和重用它.这种方式更像前面学习的 CustomRenderer .

ShadowEffect继承自PlatformEffect,位于特定平台的项目中. 即将custom renderers,PlatformEffects的实现是位于特定平台的项目中,然而Effect API是完全跨平台的,只不过在特定平台中使用不同的参数实现了 PlatformEffect<T, T> .一个主要的不同点就是, Effects 不包含它附加的Container/Control/Element的类型信息,这是因为它们能够被附加到任何的要素(Element).当Effect附加到一个不支持的要素(Element)时,会gracefully degrade或者抛出异常.

 

如果库中包含Effect,有两个重要的属性需要设置:

  • [assembly: ResolutionGroupName ("你的公司名称")] : 用于为你的Effects设置一个公司名称来防止与其它同名的Effects发生冲突.你可以在多个程序集中设置同一公司名称.
  • [assembly: ExportEffect (typeof (ShadowEffect), "ShadowEffect")] : 用于给你的Effect设置唯一ID,通过上面的公司名称和该唯一ID来定位Effect.

 

简单用法:

给你的View添加一个Effect非常简单:

var button = new Button { Text = "I have a shadow" };
button.Effects.Add (Effect.Resolve ("YourCompany.ShadowEffect"));

  

如果你没有为特定平台实现一个Effect. Effect.Resolve方法会返回一个非NULL值, 该值不会产生任何影响.这种设置对于只想某一平台而不是全部平台添加Effect非常的有用, 但是会有极小的内存损耗代价.

 

public static class ViewEffects
{
	public static readonly BindableProperty HasShadowProperty =
		BindableProperty.CreateAttached ("HasShadow", typeof (bool), typeof (ViewEffects), false, propertyChanged: OnHasShadowChanged);

	private static void OnHasShadowChanged (BindableObject bindable, object oldValue, object newValue)
	{
		var view = bindable as View;
		if (view == null)
			return;

		var hasShadow = (bool)newValue;
		if (hasShadow) {
			view.Effects.Add (new ShadowEffect ());
		} else {
			var toRemove = view.Effects.FirstOrDefault (e => e is ShadowEffect);
			if (toRemove != null)
				view.Effects.Remove (toRemove);
		}
	}

	public static readonly BindableProperty ShadowSizeProperty =
		BindableProperty.CreateAttached ("ShadowSize", typeof (double), typeof (ViewEffects), 0d);

	public static readonly BindableProperty ShadowColorProperty =
		BindableProperty.CreateAttached ("ShadowColor", typeof (Color), typeof (ViewEffects), Color.Default);

	public static void SetHasShadow (BindableObject view, bool hasShadow)
	{
		view.SetValue (HasShadowProperty, hasShadow);
	}

	public static bool GetHasShadow (BindableObject view)
	{
		return (bool)view.GetValue (HasShadowProperty);
	}

	public static void SetShadowSize (BindableObject view, double size)
	{
		view.SetValue (ShadowSizeProperty, size);
	}

	public static double GetShadowSize (BindableObject view)
	{
		return (double)view.GetValue (ShadowSizeProperty);
	}

	public static void SetShadowColor (BindableObject view, Color color)
	{
		view.SetValue (ShadowColorProperty, color);
	}

	public static Color GetShadowColor (BindableObject view)
	{
		return (Color)view.GetValue (ShadowColorProperty);
	}

	class ShadowEffect : RoutingEffect
	{
		public ShadowEffect () : base ("Xamarin.ShadowEffect")
		{
			
		}
	}
}

  上面看上去有很多的代码,实际上只有三个附加属性(attached BindablePropertys)和几个静态的getter和 setter.唯一有点复杂的代码是OnHasShadowChanged,它里面根据附加属性的值来简单的添加或者移除Effect. 最后,代码中使用了RoutingEffect而不是直接调用Effect.Resolve方法,只是为了使分离过程更加简单,因为该方法并没有获取特定平台的类型信息的编译时间.

Effect的使用方法:

<Button local:ViewEffects.HasShadow="True" 
        local:ViewEffects.ShadowColor="#222222" 
        local:ViewEffects.ShadowSize="4" />

或者更好的方式,在Style中使用Effect,这样你可以将Effect应用到任何/全部的Button上:

<Style TargetType="Button">
  <Style.Setters>
    <Setter Property="local:ViewExtensions.HasShadow" Value="True" />
    <Setter Property="local:ViewExtensions.ShadowColor" Value="#232343" />
    <Setter Property="local:ViewExtensions.ShadowSize" Value="5" />
  </Style.Setters>
</Style>

  

 

 

原文地址:http://xfcomplete.net/general/2016/01/20/using-effects/

 

个人理解(16/2/1):由于Forms中官方的控件的属性非常的少,很多时候,我们需要用到更多的属性,在Effects出现之前,我们只能使用CustomRenderer来在特定平台中重写某一个控件的渲染类(ViewRenderer),譬如如果想给控件View_A添加属性Pro_A,就要继承View_A来写一个子类,另外在特定平台中写Renderer,使用的时候还需要在xaml中引用<vewis:ExtendView_A

如果使用Effect,我们可以直接写两个Effect,在官方控件<View_A   的基础上添加Effect就可以实现,而且该Effect完全是可以通用的,只要该View支持该属性,该Effect完全可以使用在不同的View中去,更别谈有Style这种工具可以全局或者局部设置样式了

 

以上是关于Xamarin.Forms之Effects的使用的主要内容,如果未能解决你的问题,请参考以下文章

XamarinForm Effects 调用事件

Xamarin.Forms之MessagingCenter

Xamarin.Forms之异步

Xamarin.Forms之探索笔记

Xamarin.Forms之Button

Xamarin.Forms之UserDialogs 重制版本