Quantcast
Channel: かずきのBlog@hatena
Viewing all articles
Browse latest Browse all 1387

左右にスワイプするとにょきっとメニューが生えてくるものをUWPで(WP8.1でもWinStoreAppでも同じ)

$
0
0

こんな感じのUserControlを用意します。

<UserControl x:Class="App26.SwipeControl"xmlns="http://schemas.microsoft.com/winfx/2006/xaml/presentation"xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml"xmlns:local="using:App26"xmlns:d="http://schemas.microsoft.com/expression/blend/2008"xmlns:mc="http://schemas.openxmlformats.org/markup-compatibility/2006"mc:Ignorable="d"d:DesignHeight="300"d:DesignWidth="400"ManipulationMode="TranslateX,System"><Grid x:Name="Root"Background="White"><VisualStateManager.VisualStateGroups><VisualStateGroup x:Name="VisualStateGroup"><VisualState x:Name="NormalVisualState"><Storyboard><DoubleAnimation Duration="0:0:0.5"To="0"Storyboard.TargetProperty="(FrameworkElement.Width)"Storyboard.TargetName="Left"EnableDependentAnimation="True"><DoubleAnimation.EasingFunction><CircleEase EasingMode="EaseOut" /></DoubleAnimation.EasingFunction></DoubleAnimation><DoubleAnimation Duration="0:0:0.5"To="0"Storyboard.TargetProperty="(FrameworkElement.Width)"Storyboard.TargetName="Right"EnableDependentAnimation="True"><DoubleAnimation.EasingFunction><CircleEase EasingMode="EaseOut" /></DoubleAnimation.EasingFunction></DoubleAnimation></Storyboard></VisualState><VisualState x:Name="LeftVisualState"><Storyboard><DoubleAnimation Duration="0:0:0.5"To="100"Storyboard.TargetProperty="(FrameworkElement.Width)"Storyboard.TargetName="Left"EnableDependentAnimation="True"><DoubleAnimation.EasingFunction><CircleEase EasingMode="EaseOut" /></DoubleAnimation.EasingFunction></DoubleAnimation><DoubleAnimation Duration="0:0:0.5"To="0"Storyboard.TargetProperty="(FrameworkElement.Width)"Storyboard.TargetName="Right"EnableDependentAnimation="True"><DoubleAnimation.EasingFunction><CircleEase EasingMode="EaseOut" /></DoubleAnimation.EasingFunction></DoubleAnimation></Storyboard></VisualState><VisualState x:Name="RightVisualState"><Storyboard><DoubleAnimation Duration="0:0:0.5"To="0"Storyboard.TargetProperty="(FrameworkElement.Width)"Storyboard.TargetName="Left"EnableDependentAnimation="True"><DoubleAnimation.EasingFunction><CircleEase EasingMode="EaseOut" /></DoubleAnimation.EasingFunction></DoubleAnimation><DoubleAnimation Duration="0:0:0.5"To="100"Storyboard.TargetProperty="(FrameworkElement.Width)"Storyboard.TargetName="Right"EnableDependentAnimation="True"><DoubleAnimation.EasingFunction><CircleEase EasingMode="EaseOut" /></DoubleAnimation.EasingFunction></DoubleAnimation></Storyboard></VisualState></VisualStateGroup></VisualStateManager.VisualStateGroups><Grid.ColumnDefinitions><ColumnDefinition Width="Auto" /><ColumnDefinition /><ColumnDefinition Width="Auto" /></Grid.ColumnDefinitions><Rectangle x:Name="Left"Grid.Column="0"Fill="Red"Width="0"></Rectangle><Rectangle x:Name="Right"Grid.Column="2"Fill="Green"Width="0"></Rectangle><TextBlock Grid.Column="1"Text="Hello world"Style="{ThemeResource BodyTextBlockStyle}"Foreground="Black"/></Grid></UserControl>

アニメーションの定義が長いけど、幅を100にしたり0にしたり状態に応じて調整してるだけです。DoubleAnimationだけなので、よく見るとシンプル。UserControlのContentには左右のメニューがわりにRectangleを置いています。

あとは、コードビハインドでさくっとManipulationDeltaイベントを処理してやるだけ。

using Reactive.Bindings.Extensions;
using System;
using System.Linq;
using System.Reactive.Linq;
using Windows.UI.Xaml;
using Windows.UI.Xaml.Controls;
using Windows.UI.Xaml.Input;

// ユーザー コントロールのアイテム テンプレートについては、http://go.microsoft.com/fwlink/?LinkId=234236 を参照してくださいnamespace App26
{
    publicsealedpartialclass SwipeControl : UserControl
    {
        privateconststring NormalState = "NormalVisualState";
        privateconststring LeftState = "LeftVisualState";
        privateconststring RightState = "RightVisualState";

        public SwipeControl()
        {
            this.InitializeComponent();

            VisualStateManager.GoToState(this, NormalState, true);
            Observable.FromEvent<ManipulationDeltaEventHandler, ManipulationDeltaRoutedEventArgs>(
                x => (_, e) => x(e),
                x => this.ManipulationDelta += x,
                x => this.ManipulationDelta -= x)
                .Where(x => Math.Abs(x.Delta.Translation.X) >= 10)
                .Throttle(TimeSpan.FromMilliseconds(100))
                .ObserveOnUIDispatcher()
                .Subscribe(this.SwipeExecute);
        }

        privatevoid SwipeExecute(ManipulationDeltaRoutedEventArgs e)
        {
            var currentState = VisualStateManager.GetVisualStateGroups(this.Root)
                .FirstOrDefault(x => x.Name == "VisualStateGroup")
                ?.CurrentState
                ?.Name ?? NormalState;

            switch (currentState)
            {
                case NormalState:
                    currentState = e.Delta.Translation.X < 0 ? RightState : LeftState;
                    break;
                case LeftState:
                    currentState = e.Delta.Translation.X < 0 ? NormalState : LeftState;
                    break;
                case RightState:
                    currentState = e.Delta.Translation.X < 0 ? RightState : NormalState;
                    break;
            }

            VisualStateManager.GoToState(this, currentState, true);
        }
    }
}

(RxとReactiveProperty使ってます。)

やってることは、現在のVisualStateと左右のどちらに指が移動したのかを見て次のVisualStateを決めているだけです。

実行すると初期状態はこんな感じ。

f:id:okazuki:20150630205138p:plain

右にスワイプするとこんな風になる(アニメーションしながらにょきっと出てくる)

f:id:okazuki:20150630205225p:plain

課題

指に追随する形で左右のメニューが出てくるようにするには、VisualStateで綺麗に区切る感じじゃなくて、もっと泥臭いコードが必要そう。要検討。


Viewing all articles
Browse latest Browse all 1387

Trending Articles



<script src="https://jsc.adskeeper.com/r/s/rssing.com.1596347.js" async> </script>