Windows Phone8.1ランタイムでScrollViewer
sの垂直オフセットをスムーズにアニメーション化する方法はありますか?
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)ではスムーズではありません。
データ仮想化がオンになっているかどうかに関係なく、アニメーションをスクロールするには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
を呼び出して、アニメーションを無効にした状態でListView
のActualHeight * 2
のサイズまでオフセットを移動します(アプリのスクロールに基づいて、任意のサイズに変更できます)。経験)。最後に、もう一度ChangeView
を呼び出して、今回はアニメーションで最後までスクロールします。これを行うと、スクロール距離がActualHeight
のListView
にすぎないため、はるかに優れたスクロールエクスペリエンスが得られます。
スクロールしたい項目がUIですでに実現されている場合は、上記のことは何もしたくないことに注意してください。このアイテムとScrollViewer
の上部との間の距離を計算し、ChangeView
を呼び出してスクロールするだけです。
私はすでに上記のロジックをこの answer のUpdate 2セクションでラップしました(この質問のおかげで、最初の答えは仮想化がオンの場合は機能しません:p)。どうやって行くのか教えてください。
私はその質問がすでにここで答えられていると思います:
ScrollViewerでのアニメーション(スムーズ)スクロール
WinRT XAML Toolkiもあります。これは、「ScrollViewerをアニメーションで指定されたオフセットまでスクロールする方法」を提供します。
私は この記事 があなたが探しているものであり、彼が使用した方法があなたのために働いているようだと信じています。
クイックウェイ:
オフセット依存関係パラメーターを手動でscrollviewerに追加します。
スクロールビューアを複製します
アニメーターを使用します。
ScrollToVerticalOffsetがWindows10の新しいビルドで非推奨/廃止され(ScrollViewOffSetMediator拡張コントロールが機能しなくなったまま)、新しいChangeViewメソッドが実際にはスムーズまたは制御可能なアニメーションを提供しないため、新しいソリューションが必要です。アプリケーションのエンドユーザーがどこにいるかに関係なく、ScrollViewerとそのコンテンツをスムーズにアニメーション化して任意の位置にズームできる私の答えをここで参照してください。最初に配置されたスクロールバー: