天天看點

UWP Composition API - PullToRefresh

背景:

之前用ScrollViewer 來做過 PullToRefresh的控件,在項目一些特殊的條件下總有一些問題,比如ScrollViewer不會及時到達指定位置。

于是便有了使用Composition API來重新實作PullToRefresh控件。本控件的難點不是實作,而是對Composition API的一些探索。

本文的一些觀點或者說結論不一定是全對的,都是通過實驗得到的,Composition API 可用的資料實在是太少了。

成品效果圖:

UWP Composition API - PullToRefresh

資料:

Composition API 資料

還是自己動手封裝成控件。

實作原理:

這裡引用 VALID VOID裡面的話:

<code>ElementCompositionPreview.GetScrollViewerManipulationPropertySet</code> 是讓你能夠把玩輸入驅動動效的第一步。雖然它仍然沒給你任何對内容滾動時觀感進行控制的額外能力,但它确實允許你對次級内容應用表達式動畫。例如,我們終于能完成我們的基礎視差滾動代碼:

使用這一技巧,你能夠實作多種優秀的效果:視差滾動、粘性表頭、自定義滾動條等等。唯一缺失的就是定制操作本身的觀感……

我講一下我的了解:使用過ScrollViewer 和Manipulation相關事件的童鞋都知道,想要得到一些ScrollViewer 觸摸的詳情太難了,

DirectManipulationStarted和DirectManipulationCompleted得到資訊太少了,而Manipulation其他的事件又需要設定ManipulationMode,這樣全部的情況都要你自己來處理。當看到

<code>ElementCompositionPreview.GetScrollViewerManipulationPropertySet(MyScrollViewer); </code>

的時候,你是不是感覺有點親切。看上去你拿到了ScrollViewer 的一些Manipulation 的資訊。。話說這裡是最最坑爹了,

MyForeground 其實是GetScrollViewerManipulationPropertySet傳回的東東,

但MyForeground.Translation.Y這是什麼鬼東西。。Manipulation 的Translation??? 後來我在網上搜尋了一下,

但我查了下<code>CompositionPropertySet 并沒發現有相關Translation的屬性啊? </code>

難道跟Manipulation事件裡面的參數裡面的Translation 是一樣的嗎??這是我的推測。

網上都是這樣用的,但是沒有文檔。。除了Translation不知道還有其他屬性能使用不。

暫時沒有尋找到答案,希望知道的童鞋可以留言,萬分感激。。。

上面這段的代碼的意思就是說把Manipulation.Translation.Y 映射到<code>backgroundVisual的Offset.Y上面。</code>

也就是說你現在已經可以找到ScrollViewer滾動的時候一些有用的數值了。。值得說的是,用滑鼠滾動的時候 映射依然能生效。

這種映射是實時的,是會有慣性效果的。

實作過程:

因為要用到ScrollViewer,是以我做了2種,一種是重新整理内容第一進制素是ScrollViewer的,一種不是ScrollViewer的。

如果重新整理内容第一進制素是ScrollViewer,模闆如下:

如果重新整理内容第一進制素不是ScrollViewer,那麼我為它添加了一個ScrollViewer:

當然,其實第2種也是統用的,我隻是想減少控件的Child,如果你不知道重新整理内容裡面有沒有ScrollViewer,那麼用第2種就好了。有人會說為啥控件的名字這麼奇怪。。那是因為我之前也寫過PullToRefresh控件(PullToRefreshControl,PullToRefreshPanel),我把名字都想完了。。實在想不出更好的了。。大家體諒下。。( ╯□╰ )

好了,重點就是拿到這個ScrollViewer 然後跟Header,産生某種關系(你懂的)。。。

RefreshThreshold 是到達Release to refresh的一個點。。可以由使用者設定,預設是header的高度。

MaxOffsetY 是當到達RefreshThreshold之後我還能拖動的最大值,這裡設定為RefreshThreshold 的5/4。

我再來講講這個表達式的意思,ScrollManipulation.Translation.Y 大家都已經知道了。是ScrollViewer進行Manipulation的Y值,向下是正值,向上時負值,初始為0.

綜合起來就是最大值為MaxOffsetY最小值為0.。這個速率是根據RefreshThreshold/headerHeight來的,因為你會發現,你向下drag scrollViewer的時候是有一定最大值的,當RefreshThreshold比較大的時候,你很難ScrollManipulation.Translation.Y值達到RefreshThreshold。

這個也比較簡單,是給header的Opaicty做了一個動畫。

完成之後我們将動畫開始就好了。這樣在向下拖scrollviewer的時候,scrollviewer和header就都會向下移動。

接下來我們需要監聽 offset。

在開始manipulat的時候,注冊CompositionTarget.Rendering事件。在這個事件裡面我們就可以實時獲得offset的變化了。

這裡有點坑爹的是,發現如果不StopAnimation,那麼Offset.Y永遠都是0.。。很囧啊。。

最後我們在ScrollViewer_DirectManipulationCompleted事件裡面處理是否要 觸發PullToRefresh事件就ok了。

最後說下Header模闆(HeaderTemplate)是可以定義的。。它的DataContext是綁定到這個控件上的,有用的屬性有(LastRefreshTime,IsReachThreshold等),你可以用它們創造你屬于你喜歡的Header樣式。

通過本控件,初步了解Composition API 的一些用法。下一篇,我會講講一些更多的探索。。

問題:

1.Visual 是繼承IDisposable,我們需要在什麼時候Dispose 掉它呢? 還是它自己管理的?

我試過在unload的時候去dispose它。但是會出了Win32的異常。。官方sample裡面對這個也講的不清楚。

希望知道的童鞋能留言告知,萬分感謝。另外希望有對這個比較了解的童鞋能提供一些sample,資料,再次感謝。

補充:

使用條件:

因為10586之前的版本是不支援Composition API的。是以使用的時候記得判斷:

繼續閱讀