您的位置:首页 > Web前端

Xamarin.Forms之Effects的使用

2016-02-01 22:22 483 查看
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.

[b]简单用法:[/b]

给你的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
BindableProperty
s)和几个静态的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这种工具可以全局或者局部设置样式了
内容来自用户分享和网络整理,不保证内容的准确性,如有侵权内容,可联系管理员处理 点击这里给我发消息
标签: