激情久久久_欧美视频区_成人av免费_不卡视频一二三区_欧美精品在欧美一区二区少妇_欧美一区二区三区的

服務(wù)器之家:專注于服務(wù)器技術(shù)及軟件下載分享
分類導(dǎo)航

PHP教程|ASP.NET教程|Java教程|ASP教程|編程技術(shù)|正則表達式|C/C++|IOS|C#|Swift|Android|VB|R語言|JavaScript|易語言|vb.net|

香港云服务器
服務(wù)器之家 - 編程語言 - C# - ListView用法中與滾動相關(guān)的需求實現(xiàn)

ListView用法中與滾動相關(guān)的需求實現(xiàn)

2022-01-10 14:37WPInfo C#

這篇文章主要介紹了ListView用法中與滾動相關(guān)的需求實現(xiàn),獲取并設(shè)置ListView的滾動位置,以及獲取滾動位置處的項目,具有一定的參考價值,感興趣的小伙伴們可以參考一下

在 App 的開發(fā)過程中,ListView 控件是比較常用的控件之一。掌握它的用法,能幫助我們在一定程度上提高開發(fā)效率。本文將會介紹 ListView 的一種用法——獲取并設(shè)置ListView的滾動位置,以及獲取滾動位置處的項目。這里多說一句,由于這個描述有點,所以本文的標(biāo)題實在不好起。

舉個例子,如果你正在開發(fā)的應(yīng)用有這樣一個需求,當(dāng)用戶從一個列表頁(包括 ListView 控件)返回到前一頁面時,你需要得到用戶在瀏覽 ListView 中的內(nèi)容到哪個位置以及哪一項了,以便告訴用戶最近瀏覽項,并且可以讓用戶再次打開列表時,直接從上次瀏覽的位置處繼續(xù)瀏覽。如下圖:

ListView用法中與滾動相關(guān)的需求實現(xiàn)

本文介紹了實現(xiàn)上述需求的方法。具體來說,這個需求可細(xì)分為兩個小需求,即:

  • 獲取、設(shè)置 ListView 的滾動位置;
  • 獲取 ListView 滾動位置處的項目。

以下我會通過上面配圖中的 Demo 應(yīng)用逐一說明(本文末尾有源碼下載鏈接),這個 Demo 包括兩個頁面,一個主頁 (MainPage),一個列表頁 (ItemsPage)。主頁中包括:

按鈕:可以導(dǎo)航到 ItemsPage;
最近瀏覽信息區(qū)域:可以查看上次瀏覽的項目,并提供一個按鈕可以導(dǎo)航到列表頁中上次瀏覽的項目處;

而列表頁,則包括一個 ListView 控件,展示若干個項目。

一、獲取、設(shè)置 ListView 的滾動位置

關(guān)于獲取、設(shè)置 ListView 的滾動位置,微軟已經(jīng)提供了相關(guān)的例子,我在這個 Demo 中是直接套用的。這個功能主要是通過 ListViewPersistenceHelper 來實現(xiàn)的,它提供以下兩個方法:

?
1
2
3
4
5
//獲取 ListView 的滾動位置
public static string GetRelativeScrollPosition(ListViewBase listViewBase, ListViewItemToKeyHandler itemToKeyHandler)
 
// 設(shè)置 ListView 的滾動位置
public static IAsyncAction SetRelativeScrollPositionAsync(ListViewBase listViewBase, String relativeScrollPosition, ListViewKeyToItemHandler keyToItemHandler)

這兩個方法中各有一個參考是委托類型,分別是ListViewItemToKeyHandler ListViewKeyToItemHandler,它們的作用是告訴這個類如何處理列表項與 Key 的對應(yīng)關(guān)系,好使得該類可以正確地獲取或設(shè)置滾動位置。這里的 Key 是 ListViewItem 所代表的項目的一個屬性(比如 Demo 中 Item 類的 Id 屬性),這個屬性的值在整個列表中是唯一的;而 Item 是在 Item 對象本身。在 Demo 中它們的實現(xiàn)分別如下:

?
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
private string ItemToKeyHandler(object item)
 {
  Item dataItem = item as Item;
  if (dataItem == null) return null;
 
  return dataItem.Id.ToString();
 }
 
 private IAsyncOperation<object> KeyToItemHandler(string key)
 {
  Func<System.Threading.CancellationToken, Task<object>> taskProvider = token =>
  {
   var items = listView.ItemsSource as List<Item>;
   if (items != null)
   {
    var targetItem = items.FirstOrDefault(m => m.Id == int.Parse(key));
    return Task.FromResult((object)targetItem);
   }
   else
   {
    return Task.FromResult((object)null);
   }
  };
  return AsyncInfo.Run(taskProvider);
 }

實現(xiàn)這兩個方法后,重載列表頁的  OnNavigatingFrom 方法,在其中加入以下代碼,來實現(xiàn)獲取滾動位置并保存:

?
1
2
string position = ListViewPersistenceHelper.GetRelativeScrollPosition(this.listView, ItemToKeyHandler);
NavigationInfoHelper.SetInfo(targetItem, position);

繼續(xù)為頁面注冊 Loaded 事件,在 Loaded 事件中加入以下代碼來實現(xiàn)設(shè)置滾動位置:

?
1
2
3
4
5
6
7
if (navigationParameter != null)
  {
   if (NavigationInfoHelper.IsHasInfo)
   {
    await ListViewPersistenceHelper.SetRelativeScrollPositionAsync(listView, NavigationInfoHelper.LastPosition, KeyToItemHandler);
   }
  }

這里需要注意的是,設(shè)置滾動位置的方法是異步的,所以 Loaded 方法需要加上 async 修飾符。而上述代碼中對 navigationParameter 參數(shù)的判斷則是為了區(qū)別:在導(dǎo)航時是否定位到最近瀏覽的位置,具體可參考 Demo 的代碼。

二、獲取 ListView 滾動位置處的項目

關(guān)于第二個需求的實現(xiàn),我們首先需要明白以下三點:

  • ListView 的模板 (Template) 中包括 ScrollViewer,我們可以通過 VisualTreeHelper 獲取到此控件;
  • ListView 提供 ContainerFromItem 方法,它使們可以通過傳遞 Item 獲取包括此 Item 的 Container,即 ListViewItem;
  • UIElement 提供 TransformToVisual 方法,可以得到某控件相對指定控件的位置轉(zhuǎn)換信息;

所以我們的思路就是:得到 ListView 控件中的 ScrollViewer,并遍歷 ListView 中所有的 Item,在遍歷過程中,得到每一項目的 ListViewItem,并判斷它的位置是否位于 ScrollViewer 的位置中。以下是獲取 ListView 中當(dāng)前所有可見項的代碼:

?
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
public static List<T> GetAllVisibleItems<T>(this ListViewBase listView)
  {
   var scrollViewer = listView.GetScrollViewer();
   if (scrollViewer == null)
   {
    return null;
   }
 
   List<T> targetItems = new List<T>();
   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)前可見。其代碼如下:

 

?
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
/// <summary>
  /// 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
  /// </summary>
  /// <param name="element">ListViewItem or element in ListViewItem</param>
  /// <param name="container">ScrollViewer</param>
  /// <param name="isTotallyVisible">If the element is partially visible, then include it. The default value is false</param>
  /// <returns>Get the visibility of the target element</returns>
  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);
   }
  }

可以看出,我們是能過得到兩個 Rect 值。Rect 類型的值代表一個矩形區(qū)域的位置和大小,我們對這兩個值進行比較后,返回最終的結(jié)果。

獲取 ListViewItem 的 Rect 值: element.TransformToVisual(container) 返回的結(jié)果是 GeneralTransform 類型,這個值表明了 ListViewItem 相對于 Container(即 ScrollViewer)的位置轉(zhuǎn)換信息。GeneralTransform 類型可能我們并不太熟悉,不過,從它派生出來的這些類: ScaleTransform、TranslateTransform ,我們就熟悉了,GeneralTransform 正是它們的基類。GeneralTransform 包括以下兩個重要的方法:

  • TransformPoint, 可以將得到的轉(zhuǎn)換信息計算成 Point 值,表示某控件相對于另一控件的坐標(biāo)位置
  • TransformBounds,可以將得到的轉(zhuǎn)換信息計算成 Rect 值,表示某控件相對于另一控件的坐標(biāo)位置及所占的區(qū)域。

所以,我們通過 TransformBounds 方法就得到了 ListViewItem 相對于 ScrollViewer 的位置和所占區(qū)域的信息。

獲取 ScrollViewer 的 Rect 值: 直接實例化一個 Rect,以 0,0 作為你左上角的坐標(biāo)位置點, ScrollViewer 的 ActualWidth 和 ActualHeight 作為其大小。

接下來,就是比較的過程:這里,我們做了一個判斷,判斷是否要求元素 (ListViewItem) 完全在 ScrollViewer 中(而非僅部分在其中)。如果要求部分顯示即可,則只要元素的 Top 小于 Container 的 Bottom 值,并且元素的 Bottom 大于 Container 的 Top;如果要求全部顯示,那么算法是:元素的 Top 大于 Container 的 Top 并且元素的 Bottom 小于 Container 的 Bottom。如果您對語言描述或者代碼都還不明白,也可以在紙上畫一下進行比較。

接下來,我們照著 GetAllVisbleItems 方法的思路可以實現(xiàn) GetFirstVisibleItem 方法,即獲取列表中第一個可見項,代碼可參考 Demo 的源碼,在此不再贅述。

我們在之前重載的方法 OnNavigatingFrom 中加上這句代碼,即可以獲取到用戶瀏覽位置處的那一項。

?
1
var targetItem = this.listView.GetFirstVisibleItem<Item>();

至此,所有主要功能已經(jīng)基本完成。

結(jié)語

本文介紹了如何獲取和設(shè)置 ListView 的滾動位置,以及獲取滾動位置處的那一項,前者主要是借助于 ListViewPersistenceHelper 來實現(xiàn),后者則是通過獲取 ListViewItem 和 ScrollViewer 的 Rect 值并進行比較而最終實現(xiàn)的。如果您有更好的方法、不同的看見,請留言,共同交流。

源碼下載

參考資料:

ListView Sample
How to get the first visible group key in the grouped listview

以上就是本文的全部內(nèi)容,希望對大家的學(xué)習(xí)有所幫助,也希望大家多多支持服務(wù)器之家。

原文鏈接:http://www.cnblogs.com/wpinfo/p/6437487.html

延伸 · 閱讀

精彩推薦
927
主站蜘蛛池模板: 国产精品久久久久久久久粉嫩 | 欧美成年人视频 | 黄色大片免费看 | 国产精品成人免费一区久久羞羞 | 中文字幕一区在线观看视频 | 精品欧美一区二区精品久久 | 一本精品999爽爽久久久 | 爱视频福利 | 日本一区视频在线观看 | 爱福利视频网 | 久久精品视频1 | 奇米影视奇奇米色狠狠色777 | www.99热视频| 久久蜜桃香蕉精品一区二区三区 | 国产精品久久久久久久久久尿 | 在线成人免费av | 美国黄色毛片女人性生活片 | 国产欧美日韩视频在线观看 | 国产高潮国产高潮久久久91 | 国产一区二区精彩视频 | 男女一边摸一边做羞羞视频免费 | av电影网在线观看 | 亚洲午夜久久久久 | 免费久久久久 | 黄色成人在线播放 | 一级做受大片免费视频 | 久久久久久久91 | 一级性生活视频 | 99精品在线免费 | 国产一区二区在线免费播放 | 国产亚洲精品久久久久婷婷瑜伽 | 久久免费精品视频 | 在线1区 | 在线播放免费av | 久久久日韩精品一区二区 | 欧美爱爱视频网站 | 欧美在线a | 免费一级毛片电影 | 日韩黄色精品 | 日本逼逼视频 | 超级av在线 |