web-dev-qa-db-ja.com

プログラムでScrollViewerを(スムーズに)アニメーション化する

Windows Phone8.1ランタイムでScrollViewersの垂直オフセットをスムーズにアニメーション化する方法はありますか?

ScrollViewer.ChangeView()メソッドを使用しようとしましたが、disableAnimationパラメーターをtrueまたはfalseに設定しても、垂直オフセットの変更はアニメーション化されません。

次に例を示します。myScrollViewer.ChangeView(null, myScrollViewer.VerticalOffset + p, null, false);オフセットはアニメーションなしで変更されます。

また、垂直オフセットメディエーターを使用してみました。

/// <summary>
/// Mediator that forwards Offset property changes on to a ScrollViewer
/// instance to enable the animation of Horizontal/VerticalOffset.
/// </summary>
public sealed class ScrollViewerOffsetMediator : FrameworkElement
{
    /// <summary>
    /// ScrollViewer instance to forward Offset changes on to.
    /// </summary>
    public ScrollViewer ScrollViewer
    {
        get { return (ScrollViewer)GetValue(ScrollViewerProperty); }
        set { SetValue(ScrollViewerProperty, value); }
    }
    public static readonly DependencyProperty ScrollViewerProperty =
            DependencyProperty.Register("ScrollViewer",
            typeof(ScrollViewer),
            typeof(ScrollViewerOffsetMediator),
            new PropertyMetadata(null, OnScrollViewerChanged));
    private static void OnScrollViewerChanged(DependencyObject o, DependencyPropertyChangedEventArgs e)
    {
        var mediator = (ScrollViewerOffsetMediator)o;
        var scrollViewer = (ScrollViewer)(e.NewValue);
        if (null != scrollViewer)
        {
            scrollViewer.ScrollToVerticalOffset(mediator.VerticalOffset);
        }
    }

    /// <summary>
    /// VerticalOffset property to forward to the ScrollViewer.
    /// </summary>
    public double VerticalOffset
    {
        get { return (double)GetValue(VerticalOffsetProperty); }
        set { SetValue(VerticalOffsetProperty, value); }
    }
    public static readonly DependencyProperty VerticalOffsetProperty =
            DependencyProperty.Register("VerticalOffset",
            typeof(double),
            typeof(ScrollViewerOffsetMediator),
            new PropertyMetadata(0.0, OnVerticalOffsetChanged));
    public static void OnVerticalOffsetChanged(DependencyObject o, DependencyPropertyChangedEventArgs e)
    {
        var mediator = (ScrollViewerOffsetMediator)o;
        if (null != mediator.ScrollViewer)
        {
            mediator.ScrollViewer.ScrollToVerticalOffset((double)(e.NewValue));
        }
    }

    /// <summary>
    /// Multiplier for ScrollableHeight property to forward to the ScrollViewer.
    /// </summary>
    /// <remarks>
    /// 0.0 means "scrolled to top"; 1.0 means "scrolled to bottom".
    /// </remarks>
    public double ScrollableHeightMultiplier
    {
        get { return (double)GetValue(ScrollableHeightMultiplierProperty); }
        set { SetValue(ScrollableHeightMultiplierProperty, value); }
    }
    public static readonly DependencyProperty ScrollableHeightMultiplierProperty =
            DependencyProperty.Register("ScrollableHeightMultiplier",
            typeof(double),
            typeof(ScrollViewerOffsetMediator),
            new PropertyMetadata(0.0, OnScrollableHeightMultiplierChanged));
    public static void OnScrollableHeightMultiplierChanged(DependencyObject o, DependencyPropertyChangedEventArgs e)
    {
        var mediator = (ScrollViewerOffsetMediator)o;
        var scrollViewer = mediator.ScrollViewer;
        if (null != scrollViewer)
        {
            scrollViewer.ScrollToVerticalOffset((double)(e.NewValue) * scrollViewer.ScrollableHeight);
        }
    }
}

VerticalOffsetプロパティをDoubleAnimationでアニメーション化できます。

Storyboard sb = new Storyboard();
DoubleAnimation da = new DoubleAnimation();
da.EnableDependentAnimation = true;
da.From = Mediator.ScrollViewer.VerticalOffset;
da.To = da.From + p;
da.Duration = new Duration(TimeSpan.FromMilliseconds(300));
da.EasingFunction = new ExponentialEase() { EasingMode = EasingMode.EaseOut };
Storyboard.SetTarget(da, Mediator);
Storyboard.SetTargetProperty(da, "(Mediator.VerticalOffset)");
sb.Children.Add(da);

sb.Begin();

メディエーターはXAMLで宣言されています。しかし、このアニメーションは私のデバイス(Lumia 930)ではスムーズではありません。

36

データ仮想化がオンになっているかどうかに関係なく、アニメーションをスクロールするにはChangeViewを使用する必要があります。

ChangeViewが機能しないコードを見ないと、実際に何が起こっているのかを推測するのは少し難しいですが、試すことができることがいくつかあります。

最初のアプローチは、ChangeViewを呼び出す前にTask.Delay(1)を追加することです。これは、OSに他の同時UIタスクを完了する時間を与えるためです。

await Task.Delay(1);
scrollViewer.ChangeView(null, scrollViewer.ScrollableHeight, null, false);

2番目のアプローチはもう少し複雑です。私が気付いたのは、ListViewに多くの複雑なアイテムがある場合、最初のアイテムから最後のアイテムへの(ChangeViewメソッドからの)スクロールアニメーションはあまりスムーズではないということです。すべて。

これは、ListViewが最初にデータ仮想化のために多くのアイテムを実現/レンダリングする必要があり、次にアニメーションスクロールを実行するためです。あまり効率的ではない私見。

私が思いついたのはこれです-まず、アニメーション化されていないListView.ScrollIntoViewを使用して、最後のアイテムまでスクロールし、それを実現します。次に、ChangeViewを呼び出して、アニメーションを無効にした状態でListViewActualHeight * 2のサイズまでオフセットを移動します(アプリのスクロールに基づいて、任意のサイズに変更できます)。経験)。最後に、もう一度ChangeViewを呼び出して、今回はアニメーションで最後までスクロールします。これを行うと、スクロール距離がActualHeightListViewにすぎないため、はるかに優れたスクロールエクスペリエンスが得られます。

スクロールしたい項目がUIですでに実現されている場合は、上記のことは何もしたくないことに注意してください。このアイテムとScrollViewerの上部との間の距離を計算し、ChangeViewを呼び出してスクロールするだけです。

私はすでに上記のロジックをこの answerUpdate 2セクションでラップしました(この質問のおかげで、最初の答えは仮想化がオンの場合は機能しません:p)。どうやって行くのか教えてください。

15
Justin XL

私はその質問がすでにここで答えられていると思います:

ScrollViewerでのアニメーション(スムーズ)スクロール

WinRT XAML Toolkiもあります。これは、「ScrollViewerをアニメーションで指定されたオフセットまでスクロールする方法」を提供します。

http://winrtxamltoolkit.codeplex.com/

4
SalientGreen

私は この記事 があなたが探しているものであり、彼が使用した方法があなたのために働いているようだと信じています。

クイックウェイ:

  1. オフセット依存関係パラメーターを手動でscrollviewerに追加します。

  2. スクロールビューアを複製します

  3. アニメーターを使用します。

0
user10141586

ScrollToVerticalOffsetがWindows10の新しいビルドで非推奨/廃止され(ScrollViewOffSetMediator拡張コントロールが機能しなくなったまま)、新しいChangeViewメソッドが実際にはスムーズまたは制御可能なアニメーションを提供しないため、新しいソリューションが必要です。アプリケーションのエンドユーザーがどこにいるかに関係なく、ScrollViewerとそのコンテンツをスムーズにアニメーション化して任意の位置にズームできる私の答えをここで参照してください。最初に配置されたスクロールバー:

WPの要素までスクロールする方法

0
zax