UWP 帶左右滾動按鈕的橫向ListView———仿NetFlix首頁河的設計

也是以前寫的控件了,模仿NetFlix的河的設計。git

大致要求以下:github

1. 橫向的ListViewapp

2. 左右按鈕,能夠左右移動河卡片,左右的滾動條不可見佈局

3. 左右按鈕僅在鼠標Hover事件中可見spa

你們能夠看下NetFlix uwp版,國內愛奇藝也是這樣設計的,芒果TV以前是,可是新版去掉了這種風格。設計

 

 

 

 

其實我也是一個菜鳥,一開始糾結怎麼寫這個控件,怎麼傳遞ItemsSource,並且還在SO上發起了提問雙向綁定

How to customize a horizontal listview with left/right button on uwp?

很遺憾,uwp幾乎滅絕,沒有人回答個人問題。因而各類尋找,終於發現了大神  Pieter Nijs code

寫的文章https://blog.pieeatingninjas.be/2016/01/17/custom-uwp-control-step-through-listview/blog

大神的需求和個人相似,見圖事件

 

 

因而膜拜文章,寫下了適合我本身的控件見圖:

 

 

👌好了,下面開始擼代碼,先新建一個用戶控件,名字叫 StepThroughListView ,看看Xaml的佈局,

<Grid>
        <ListView 
            x:Name="ListViewRiver"
            HorizontalAlignment="Stretch"
            SingleSelectionFollowsFocus="True"
            ScrollViewer.VerticalScrollBarVisibility="Hidden"
            ScrollViewer.HorizontalScrollBarVisibility="Hidden"
            ScrollViewer.VerticalScrollMode="Disabled"
            ScrollViewer.HorizontalScrollMode="Disabled"
            >
            
            <ListView.ItemsPanel>
                <ItemsPanelTemplate>
                    <VirtualizingStackPanel Orientation="Horizontal"/>
                </ItemsPanelTemplate>
            </ListView.ItemsPanel>
            
        </ListView>

        <Button x:Name="ButtonLeft"/>

        <Button x:Name="ButtonRight" HorizontalAlignment="Right"/>
    </Grid>

 

這樣大致建立了一個這樣的橫向的ListView,橙色矩形爲ListView,灰色圓圈是左右按鈕Button,藍色是ListViewItem

按鈕是默認垂直居中

 

 

而後咱們須要給ListView賦值ItemsSource、SelectedItem、ItemTemplate,這些須要在C#代碼中使用依賴屬性來完成。

        public IEnumerable ItemsSource
        {
            get { return (IEnumerable)GetValue(ItemsSourceProperty); }
            set { SetValue(ItemsSourceProperty, value); RaisePropertyChanged(); }
        }

        public static readonly DependencyProperty ItemsSourceProperty =
            DependencyProperty.Register(nameof(ItemsSource), typeof(IEnumerable), 
                typeof(StepThroughListView), new PropertyMetadata(DependencyProperty.UnsetValue));

        public DataTemplate ItemTemplate
        {
            get { return (DataTemplate)GetValue(ItemTemplateProperty); }
            set { SetValue(ItemTemplateProperty, value); RaisePropertyChanged(); }
        }

        public static readonly DependencyProperty ItemTemplateProperty =
            DependencyProperty.Register(nameof(ItemTemplate), typeof(DataTemplate),
                typeof(StepThroughListView), new PropertyMetadata(DependencyProperty.UnsetValue));

        public object SelectedItem
        {
            get { return GetValue(SelectedItemProperty); }
            set
            {
                if (SelectedItem != value)
                {
                    SetValue(SelectedItemProperty, value);
                    RaisePropertyChanged();
                }
            }
        }

        public static readonly DependencyProperty SelectedItemProperty =
            DependencyProperty.Register(nameof(SelectedItem), typeof(object), 
                typeof(StepThroughListView), new PropertyMetadata(DependencyProperty.UnsetValue));

 

而後在Xaml中,須要給ListView作雙向綁定,

ItemsSource="{Binding ItemsSource, ElementName=root}" 
SelectedItem="{x:Bind SelectedItem, Mode=TwoWay}"
ItemTemplate="{x:Bind ItemTemplate, Mode=TwoWay}"

 

接下來就能夠處理左右按鈕的響應事件了,由於橫向的ListView左右滾動事件被咱們禁用了,因此須要手動控制。

首先定義一個私有變量

ScrollViewer _InternalListScrollViewer;

在ListView的Loaded事件中,經過VisualTreeHelper查找🔍ListView內部的ScrollViewer。

        private void ListView_Loaded(object sender, RoutedEventArgs e)
        {
            _InternalListScrollViewer = TreeHelper.FindVisualChild<ScrollViewer>((DependencyObject)sender);
        }
public static TChild FindVisualChild<TChild>(DependencyObject obj) where TChild : DependencyObject
        {
            if (obj == null) return null;

            for (int i = 0; i < VisualTreeHelper.GetChildrenCount(obj); i++)
            {
                DependencyObject child = VisualTreeHelper.GetChild(obj, i);
                if (child != null && child is TChild found)
                    return found;
                else
                {
                    TChild childOfChild = FindVisualChild<TChild>(child);
                    if (childOfChild != null)
                        return childOfChild;
                }
            }
            return null;
        }

 

 

左右按鈕的Tapped事件,左按鈕和右按鈕的的方向正好相反。因此合併一下

private void ButtonRight_Tapped(object sender, TappedRoutedEventArgs e)
        {
            ScrollList(shouldScrollDown: true);
        }

        private void ButtonLeft_Tapped(object sender, TappedRoutedEventArgs e)
        {
            ScrollList(shouldScrollDown: false);
        }

        private void ScrollList(bool shouldScrollDown)
        {
            SelectedItem = null;

            var step = Math.Floor(Window.Current.Bounds.Width / 400);

            if (!shouldScrollDown)
                step *= -1;

            //_InternalListScrollViewer.ScrollToVerticalOffset(
            //    _InternalListScrollViewer.VerticalOffset + height);
            System.Diagnostics.Debug.WriteLine(_InternalListScrollViewer.ScrollableWidth);
            _InternalListScrollViewer.ChangeView(_InternalListScrollViewer.HorizontalOffset + step, null, null);
        }

 

上面的變量step,我用的是根據窗體大小寬度來決定步長。不過你也能夠用本身的一個固定值,好比2。

而後我又加了一個屬性,叫AlwaysShowButton。若是設置Visible,那麼左右按鈕一直可見。

設置爲Collapse的話,只有當鼠標移動到ListView上,纔會顯示左右按鈕。

 

 

================================================

好了,囉嗦那麼多,控件的代碼奉上:

https://github.com/hupo376787/StepThroughListView

 

用法也很簡單:

    <ctl:StepThroughListView
          AlwaysShowButton="Collapsed"
          ItemsSource="{x:Bind product}"
          Tapped="StepThroughListView_Tapped">
    </ctl:StepThroughListView>
                
                
    private void StepThroughListView_Tapped(object sender, TappedRoutedEventArgs e)
    {
        var item = (sender as Controls.StepThroughListView).SelectedItem as ProductItem;
        if (item != null)
        {
            //TODO...
        }
    }

 

 

OK,下班!!!

相關文章
相關標籤/搜索