這篇文章給大家介紹如何正確的使用ListView,內(nèi)容非常詳細(xì),感興趣的小伙伴們可以參考借鑒,希望對(duì)大家能有所幫助。
成都創(chuàng)新互聯(lián)公司,為您提供網(wǎng)站建設(shè)公司、成都網(wǎng)站制作公司、網(wǎng)站營(yíng)銷推廣、網(wǎng)站開發(fā)設(shè)計(jì),對(duì)服務(wù)主動(dòng)防護(hù)網(wǎng)等多個(gè)行業(yè)擁有豐富的網(wǎng)站建設(shè)及推廣經(jīng)驗(yàn)。成都創(chuàng)新互聯(lián)公司網(wǎng)站建設(shè)公司成立于2013年,提供專業(yè)網(wǎng)站制作報(bào)價(jià)服務(wù),我們深知市場(chǎng)的競(jìng)爭(zhēng)激烈,認(rèn)真對(duì)待每位客戶,為客戶提供賞心悅目的作品。 與客戶共同發(fā)展進(jìn)步,是我們永遠(yuǎn)的責(zé)任!
一、獲取、設(shè)置 ListView 的滾動(dòng)位置
關(guān)于獲取、設(shè)置 ListView 的滾動(dòng)位置,微軟已經(jīng)提供了相關(guān)的例子,我在這個(gè) Demo 中是直接套用的。這個(gè)功能主要是通過 ListViewPersistenceHelper 來實(shí)現(xiàn)的,它提供以下兩個(gè)方法:
//獲取 ListView 的滾動(dòng)位置 public static string GetRelativeScrollPosition(ListViewBase listViewBase, ListViewItemToKeyHandler itemToKeyHandler) // 設(shè)置 ListView 的滾動(dòng)位置 public static IAsyncAction SetRelativeScrollPositionAsync(ListViewBase listViewBase, String relativeScrollPosition, ListViewKeyToItemHandler keyToItemHandler)
這兩個(gè)方法中各有一個(gè)參考是委托類型,分別是ListViewItemToKeyHandler 和 ListViewKeyToItemHandler,它們的作用是告訴這個(gè)類如何處理列表項(xiàng)與 Key 的對(duì)應(yīng)關(guān)系,好使得該類可以正確地獲取或設(shè)置滾動(dòng)位置。這里的 Key 是 ListViewItem 所代表的項(xiàng)目的一個(gè)屬性(比如 Demo 中 Item 類的 Id 屬性),這個(gè)屬性的值在整個(gè)列表中是唯一的;而 Item 是在 Item 對(duì)象本身。在 Demo 中它們的實(shí)現(xiàn)分別如下:
private string ItemToKeyHandler(object item) { Item dataItem = item as Item; if (dataItem == null) return null; return dataItem.Id.ToString(); } private IAsyncOperation
實(shí)現(xiàn)這兩個(gè)方法后,重載列表頁(yè)的 OnNavigatingFrom 方法,在其中加入以下代碼,來實(shí)現(xiàn)獲取滾動(dòng)位置并保存:
string position = ListViewPersistenceHelper.GetRelativeScrollPosition(this.listView, ItemToKeyHandler); NavigationInfoHelper.SetInfo(targetItem, position);
繼續(xù)為頁(yè)面注冊(cè) Loaded 事件,在 Loaded 事件中加入以下代碼來實(shí)現(xiàn)設(shè)置滾動(dòng)位置:
if (navigationParameter != null) { if (NavigationInfoHelper.IsHasInfo) { await ListViewPersistenceHelper.SetRelativeScrollPositionAsync(listView, NavigationInfoHelper.LastPosition, KeyToItemHandler); } }
這里需要注意的是,設(shè)置滾動(dòng)位置的方法是異步的,所以 Loaded 方法需要加上 async 修飾符。而上述代碼中對(duì) navigationParameter 參數(shù)的判斷則是為了區(qū)別:在導(dǎo)航時(shí)是否定位到最近瀏覽的位置,具體可參考 Demo 的代碼。
二、獲取 ListView 滾動(dòng)位置處的項(xiàng)目
關(guān)于第二個(gè)需求的實(shí)現(xiàn),我們首先需要明白以下三點(diǎn):
ListView 的模板 (Template) 中包括 ScrollViewer,我們可以通過 VisualTreeHelper 獲取到此控件;
ListView 提供 ContainerFromItem 方法,它使們可以通過傳遞 Item 獲取包括此 Item 的 Container,即 ListViewItem;
UIElement 提供 TransformToVisual 方法,可以得到某控件相對(duì)指定控件的位置轉(zhuǎn)換信息;
所以我們的思路就是:得到 ListView 控件中的 ScrollViewer,并遍歷 ListView 中所有的 Item,在遍歷過程中,得到每一項(xiàng)目的 ListViewItem,并判斷它的位置是否位于 ScrollViewer 的位置中。以下是獲取 ListView 中當(dāng)前所有可見項(xiàng)的代碼:
public static ListGetAllVisibleItems (this ListViewBase listView) { var scrollViewer = listView.GetScrollViewer(); if (scrollViewer == null) { return null; } List targetItems = new List (); foreach (T item in listView.Items) { var itemContainer = listView.ContainerFromItem(item) as FrameworkElement; bool isVisible = IsVisibileToUser(itemContainer, scrollViewer, true); if (isVisible) { targetItems.Add(item); } } return targetItems; }
在上述代碼的 foreach 循環(huán)中的部分,正是我們前述思路的體現(xiàn)。而其中所調(diào)用的 IsVisibleToUser 方法,則是如何判斷某一 ListViewItem 是否在 ScrollViewer 中為當(dāng)前可見。其代碼如下:
////// Code from here: /// https://social.msdn.microsoft.com/Forums/en-US/86ccf7a1-5481-4a59-9db2-34ebc760058a/uwphow-to-get-the-first-visible-group-key-in-the-grouped-listview?forum=wpdevelop /// /// ListViewItem or element in ListViewItem /// ScrollViewer /// If the element is partially visible, then include it. The default value is false ///Get the visibility of the target element private static bool IsVisibileToUser(FrameworkElement element, FrameworkElement container, bool isTotallyVisible = false) { if (element == null || container == null) return false; if (element.Visibility != Visibility.Visible) return false; Rect elementBounds = element.TransformToVisual(container).TransformBounds(new Rect(0.0, 0.0, element.ActualWidth, element.ActualHeight)); Rect containerBounds = new Rect(0.0, 0.0, container.ActualWidth, container.ActualHeight); if (!isTotallyVisible) { return (elementBounds.Top < containerBounds.Bottom && elementBounds.Bottom > containerBounds.Top); } else { return (elementBounds.Bottom < containerBounds.Bottom && elementBounds.Top > containerBounds.Top); } }
可以看出,我們是能過得到兩個(gè) Rect 值。Rect 類型的值代表一個(gè)矩形區(qū)域的位置和大小,我們對(duì)這兩個(gè)值進(jìn)行比較后,返回最終的結(jié)果。
獲取 ListViewItem 的 Rect 值: element.TransformToVisual(container) 返回的結(jié)果是 GeneralTransform 類型,這個(gè)值表明了 ListViewItem 相對(duì)于 Container(即 ScrollViewer)的位置轉(zhuǎn)換信息。GeneralTransform 類型可能我們并不太熟悉,不過,從它派生出來的這些類: ScaleTransform、TranslateTransform ,我們就熟悉了,GeneralTransform 正是它們的基類。GeneralTransform 包括以下兩個(gè)重要的方法:
TransformPoint, 可以將得到的轉(zhuǎn)換信息計(jì)算成 Point 值,表示某控件相對(duì)于另一控件的坐標(biāo)位置
TransformBounds,可以將得到的轉(zhuǎn)換信息計(jì)算成 Rect 值,表示某控件相對(duì)于另一控件的坐標(biāo)位置及所占的區(qū)域。
所以,我們通過 TransformBounds 方法就得到了 ListViewItem 相對(duì)于 ScrollViewer 的位置和所占區(qū)域的信息。
獲取 ScrollViewer 的 Rect 值:直接實(shí)例化一個(gè) Rect,以 0,0 作為你左上角的坐標(biāo)位置點(diǎn), ScrollViewer 的 ActualWidth 和 ActualHeight 作為其大小。
接下來,就是比較的過程:這里,我們做了一個(gè)判斷,判斷是否要求元素 (ListViewItem) 完全在 ScrollViewer 中(而非僅部分在其中)。如果要求部分顯示即可,則只要元素的 Top 小于 Container 的 Bottom 值,并且元素的 Bottom 大于 Container 的 Top;如果要求全部顯示,那么算法是:元素的 Top 大于 Container 的 Top 并且元素的 Bottom 小于 Container 的 Bottom。如果您對(duì)語(yǔ)言描述或者代碼都還不明白,也可以在紙上畫一下進(jìn)行比較。
接下來,我們照著 GetAllVisbleItems 方法的思路可以實(shí)現(xiàn) GetFirstVisibleItem 方法,即獲取列表中第一個(gè)可見項(xiàng),代碼可參考 Demo 的源碼,在此不再贅述。
我們?cè)谥爸剌d的方法 OnNavigatingFrom 中加上這句代碼,即可以獲取到用戶瀏覽位置處的那一項(xiàng)。
var targetItem = this.listView.GetFirstVisibleItem- ();
關(guān)于如何正確的使用ListView就分享到這里了,希望以上內(nèi)容可以對(duì)大家有一定的幫助,可以學(xué)到更多知識(shí)。如果覺得文章不錯(cuò),可以把它分享出去讓更多的人看到。