在Xamarin.Forms中Effects的使用


Xamarin.Forms之Effects的使用

xamarin.forms


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

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

  1. public class ShadowEffect : PlatformEffect
  2. {
  3. protected override void OnAttached ()
  4. {
  5. UpdateSize ();
  6. UpdateColor ();
  7. UpdateOpacity ();
  8. }
  9. protected override void OnDetached ()
  10. {
  11. Container.Layer.ShadowOpacity = 0;
  12. }
  13. protected override void OnElementPropertyChanged (PropertyChangedEventArgs e)
  14. {
  15. Debug.WriteLine (e.PropertyName);
  16. if (e.PropertyName == ViewExtensions.HasShadowProperty.PropertyName) {
  17. UpdateOpacity ();
  18. } else if (e.PropertyName == ViewExtensions.ShadowColorProperty.PropertyName) {
  19. UpdateColor ();
  20. } else if (e.PropertyName == ViewExtensions.ShadowSizeProperty.PropertyName) {
  21. UpdateSize ();
  22. }
  23. }
  24. private void UpdateOpacity ()
  25. {
  26. Container.Layer.ShadowOpacity = ViewExtensions.GetHasShadow (Element) ? 1 : 0;
  27. }
  28. private void UpdateColor ()
  29. {
  30. var color = ViewExtensions.GetShadowColor (Element);
  31. Container.Layer.ShadowColor = color.ToCGColor ();
  32. }
  33. private void UpdateSize ()
  34. {
  35. Container.Layer.ShadowRadius = (nfloat)ViewExtensions.GetShadowSize (Element);
  36. }
  37. }

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

  1. public class ShadowEffect : PlatformEffect
  2. {
  3. protected override void OnAttached ()
  4. {
  5. Container.Layer.ShadowOpacity = 1;
  6. Container.Layer.ShadowColor = UIColor.Black.ToCGColor;
  7. Container.Layer.ShadowRadius = 6;
  8. }
  9. protected override void OnDetached ()
  10. {
  11. Container.Layer.ShadowOpacity = 0;
  12. }
  13. }

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

ShadowEffect继承自PlatformEffect,位于特定平台的项目中. 即将custom renderers,PlatformEffects的实现是位于特定平台的项目中,然而Effect API是完全跨平台的,只不过在特定平台中使用不同的参数实现了 PlatformEffect .一个主要的不同点就是, 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非常简单:

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

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

  1. public static class ViewEffects
  2. {
  3. public static readonly BindableProperty HasShadowProperty =
  4. BindableProperty.CreateAttached ("HasShadow", typeof (bool), typeof (ViewEffects), false, propertyChanged: OnHasShadowChanged);
  5. private static void OnHasShadowChanged (BindableObject bindable, object oldValue, object newValue)
  6. {
  7. var view = bindable as View;
  8. if (view == null)
  9. return;
  10. var hasShadow = (bool)newValue;
  11. if (hasShadow) {
  12. view.Effects.Add (new ShadowEffect ());
  13. } else {
  14. var toRemove = view.Effects.FirstOrDefault (e => e is ShadowEffect);
  15. if (toRemove != null)
  16. view.Effects.Remove (toRemove);
  17. }
  18. }
  19. public static readonly BindableProperty ShadowSizeProperty =
  20. BindableProperty.CreateAttached ("ShadowSize", typeof (double), typeof (ViewEffects), 0d);
  21. public static readonly BindableProperty ShadowColorProperty =
  22. BindableProperty.CreateAttached ("ShadowColor", typeof (Color), typeof (ViewEffects), Color.Default);
  23. public static void SetHasShadow (BindableObject view, bool hasShadow)
  24. {
  25. view.SetValue (HasShadowProperty, hasShadow);
  26. }
  27. public static bool GetHasShadow (BindableObject view)
  28. {
  29. return (bool)view.GetValue (HasShadowProperty);
  30. }
  31. public static void SetShadowSize (BindableObject view, double size)
  32. {
  33. view.SetValue (ShadowSizeProperty, size);
  34. }
  35. public static double GetShadowSize (BindableObject view)
  36. {
  37. return (double)view.GetValue (ShadowSizeProperty);
  38. }
  39. public static void SetShadowColor (BindableObject view, Color color)
  40. {
  41. view.SetValue (ShadowColorProperty, color);
  42. }
  43. public static Color GetShadowColor (BindableObject view)
  44. {
  45. return (Color)view.GetValue (ShadowColorProperty);
  46. }
  47. class ShadowEffect : RoutingEffect
  48. {
  49. public ShadowEffect () : base ("Xamarin.ShadowEffect")
  50. {
  51. }
  52. }
  53. }

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

Effect的使用方法:

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

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

  1. <Style TargetType="Button">
  2. <Style.Setters>
  3. <Setter Property="local:ViewExtensions.HasShadow" Value="True" />
  4. <Setter Property="local:ViewExtensions.ShadowColor" Value="#232343" />
  5. <Setter Property="local:ViewExtensions.ShadowSize" Value="5" />
  6. </Style.Setters>
  7. </Style>

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

如果使用Effect,我们可以直接写两个Effect,在官方控件

原文地址:http://www.cnblogs.com/yz1311/p/5176446.html

分享到