しっぽを追いかけて

ぐるぐるしながら考えています

Unity と猫の話題が中心   掲載内容は個人の私見であり、所属組織の見解ではありません

Xamarin でタップするたびに外観を切り替えるコントロールを作る

前回 は GetureRecognizer と Setter を連携する Behavior を作ることで、タップに反応するコントロールを作りました

今回はさらに発展させて、タップのたびに外観が変わるような実装を試してみたいと思います

f:id:matatabi_ux:20150118205731p:plain

例によって修正箇所は上記のみ

まずは XAML

<?xml version="1.0" encoding="utf-8" ?>
<ContentPage xmlns="http://xamarin.com/schemas/2014/forms"
             xmlns:x="http://schemas.microsoft.com/winfx/2009/xaml"
             xmlns:b="clr-namespace:XamarinControl.Behaviors;assembly=XamarinControl"
             x:Class="XamarinControl.Views.TopPage">
  <BoxView 
    BackgroundColor="#FFD45D87"
    WidthRequest="200"
    HeightRequest="200"
    HorizontalOptions="Center"
    VerticalOptions="Center">
    <BoxView.Behaviors>
      <b:GestureRecognizeBehavior>
        <b:GestureRecognizeBehavior.GestureRecognizer>
          <TapGestureRecognizer NumberOfTapsRequired="1" />
        </b:GestureRecognizeBehavior.GestureRecognizer>
        <b:GestureRecognizeBehavior.Setters>
          <Setter Property="BoxView.BackgroundColor" Value="#FFE6855E"/>
          <Setter Property="BoxView.BackgroundColor" Value="#FFF9DB57"/>
          <Setter Property="BoxView.BackgroundColor" Value="#FF5EC84E"/>
          <Setter Property="BoxView.BackgroundColor" Value="#FF42AAC7"/>
          <Setter Property="BoxView.BackgroundColor" Value="#FF6A8CC7"/>
          <Setter Property="BoxView.BackgroundColor" Value="#FF9D73BB"/>
          <Setter Property="BoxView.BackgroundColor" Value="#FFD45D87"/>
        </b:GestureRecognizeBehavior.Setters>
      </b:GestureRecognizeBehavior>
    </BoxView.Behaviors>
  </BoxView>
</ContentPage>

Setters に BackgroundColor を切り替える複数の Setter を追加しています

さらに GestureRecognizeBehavior

/// <summary>
/// GestureRecognizer に反応する Behavior
/// </summary>
public class GestureRecognizeBehavior : Behavior<View>
{
    /// <summary>
    /// アタッチされた View
    /// </summary>
    private View bindable = null;

    /// <summary>
    /// 現在のインデックス
    /// </summary>
    private int index = 0;

    /// <summary>
    /// アタッチされた GestureRecognizer の BindableProperty
    /// </summary>
    public static readonly BindableProperty GestureRecognizerProperty =
        BindableProperty.Create<GestureRecognizeBehavior, TapGestureRecognizer>(p => p.GestureRecognizer, null);

    /// <summary>
    /// アタッチされた GestureRecognizer
    /// </summary>
    public TapGestureRecognizer GestureRecognizer
    {
        get { return (TapGestureRecognizer)this.GetValue(GestureRecognizerProperty); }
        set { this.SetValue(GestureRecognizerProperty, value); }
    }

    /// <summary>
    /// アタッチされた Setter のリストの BindableProperty
    /// </summary>
    public static readonly BindableProperty SettersProperty =
        BindableProperty.Create<GestureRecognizeBehavior, IList<Setter>>(p => p.Setters, new List<Setter>());

    /// <summary>
    /// アタッチされた Setter のリスト
    /// </summary>
    public IList<Setter> Setters
    {
        get { return (IList<Setter>)this.GetValue(SettersProperty); }
        set { this.SetValue(SettersProperty, value); }
    }

    /// <summary>
    /// Behavior がアタッチされた時の処理
    /// </summary>
    /// <param name="bindable">アタッチされた View</param>
    protected override void OnAttachedTo(View bindable)
    {
        base.OnAttachedTo(bindable);
        this.bindable = bindable;
        if (this.bindable == null || this.GestureRecognizer == null)
        {
            return;
        }
        this.GestureRecognizer.Tapped += this.OnGestured;
        this.bindable.GestureRecognizers.Add(this.GestureRecognizer);
    }

    /// <summary>
    /// GestureRecognizer のイベントハンドラ
    /// </summary>
    /// <param name="sender">イベント発行者</param>
    /// <param name="args">イベント引数</param>
    private void OnGestured(object sender, EventArgs args)
    {
        // アタッチされた View に Setter を反映
        if (index >= this.Setters.Count)
        {
            index %= this.Setters.Count;
        }
        var setter = this.Setters[index];
        this.bindable.SetValue(setter.Property, setter.Value);
        index++;
    }

    /// <summary>
    /// Behavior がデタッチされた時の処理
    /// </summary>
    /// <param name="bindable"></param>
    protected override void OnDetachingFrom(View bindable)
    {
        if (this.bindable != null && this.GestureRecognizer != null)
        {
            this.bindable.GestureRecognizers.Remove(this.GestureRecognizer);
            this.GestureRecognizer.Tapped -= this.OnGestured;
            this.GestureRecognizer = null;
            this.bindable = null;
        }
        base.OnDetachingFrom(bindable);
    }
}

主な変更箇所は下記です

    /// <summary>
    /// GestureRecognizer のイベントハンドラ
    /// </summary>
    /// <param name="sender">イベント発行者</param>
    /// <param name="args">イベント引数</param>
    private void OnGestured(object sender, EventArgs args)
    {
        // アタッチされた View に Setter を反映
        if (index >= this.Setters.Count)
        {
            index %= this.Setters.Count;
        }
        var setter = this.Setters[index];
        this.bindable.SetValue(setter.Property, setter.Value);
        index++;
    }

Behavior が保持している index をもとに対応する Setter を拾って設定しているだけですね

これを実行すると

f:id:matatabi_ux:20150121100706g:plain

タップで色が切り替わるようになりました