ぴーさんログ

だいたいXamarin.Formsのブログ

【Xamarin.Forms 2.1.0(プレビュー)】Effects

Xamarin.Forms 2.1.0 で Effects という新しい概念が追加される予定です。 (個人的な感想として、BehaiviorsやStylesの概念をCutstomRendererに持ち込んだ物がEffectsと捉えるとしっくりきます。)

「Buttonコントロールに枠線を付けたい」といった場合、従来はCustomRendererでプラットフォームごとのViewに手を加えるのが基本的なアプローチでした。 (iOS版のボタンに枠線を付けたかっただけなのに!?)

Effectsを使えばそのようなことがより簡単に、もっと使い回しの効く形で実現できるようになります。

サンプル

早速、枠線を付ける簡単なEffectを作成してみましょう。(iOS用です、iOSのプロジェクト内に書いてください)

using System;
using Xamarin.Forms;
using Xamarin.Forms.Platform.iOS;
using XFApp13.iOS;

[assembly: ResolutionGroupName ("YourCompany")]
[assembly: ExportEffect (typeof (BorderEffect), "BorderEffect")]

namespace XFApp13.iOS
{
    public class BorderEffect : PlatformEffect
    {
        protected override void OnAttached()
        {
            Control.Layer.BorderWidth = 1.0f;
            Control.Layer.BorderColor = Color.Black.ToCGColor();
        }

        protected override void OnDetached()
        {
            Control.Layer.BorderWidth = 0.0f;
        }
    }
}

PlatformEffect を継承して新しいEffectを作ります。 OnAttachedOnDetached の2つは必ず実装しなければなりません。

以下のプロパティを駆使してコントロールに素敵な効果を加えましょう。

  • Container - ViewRenderer (今回の例ではXamarin.Forms.Platform.iOS.ButtonRenderer)
  • Control - ネイティブ側のコントロール (今回の例ではUIKit.UiButton)
  • Element - Xamarin.Formsのコントロール (今回の例ではButton)

共通コードからEffectのインスタンスを得るため、ここで2つの属性をセットしておく必要があります。

  • [assembly: ResolutionGroupName ("YourCompany")] : Effect式別名の名前空間となります。複数アセンブリで同じ名前を使用することができます。
  • [assembly: ExportEffect (typeof (BorderEffect), "BorderEffect")] : Effect毎のユニークなIDをエクスポートします。

使い方

共通コード側でViewにEffectを追加します。

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

EffectのインスタンスEffect.Resolve staticメソッドで作成します。ここで指定する名前はResolutionGroupName属性とExportEffect属性で指定した名前を結合した物になります。

ちなみにXAMLで書くとこうです。

<Button Text="I hava a border">
    <Button.Effects>
        <Effect x:FactoryMethod="Resolve" >
            <x:Arguments>
                <x:String>YourCompany.BorderEffect</x:String>
            </x:Arguments>
        </Effect>
    </Button.Effects>
</Button>

RoutingEffect

Effect.Resolve の代わりに RoutingEffect を使うと共通コードでタイプセーフにEffectを扱うことができます。

public class BorderEffect : RoutingEffect
{
    public BorderEffect() : base("YourCompany.BorderEffect")
    {
    }
}

この場合、利用側のコードはこうなります。

var button = new Button { Text = "I have a border" };
button.Effects.Add( new BorderEffect() );

最後に

本記事ではEffectsの最低限基本的な使い方を解説しました。簡単のため枠線の幅、色などのパラメーターを全て決め打ちしていますが、本当はもっとパラーメータ設定可能的であるべきです。

Jason Smith氏がAttached Propertyを組み合わせたより実践的な使い方を解説していらっしゃるので、是非そちらも合わせてお読みください。

Using Effects - Xamarin.Forms Complete

参考

Xamarin.Forms 2.1.0-pre2 Released - Xamarin Forums

Using Effects - Xamarin.Forms Complete