【问题标题】:ListView Scrolling With Horizontal and Vertical in xamarin.formsListView 在 xamarin.forms 中水平和垂直滚动
【发布时间】:2018-09-13 18:31:41
【问题描述】:

我坚持创建一个支持水平和垂直滚动的Listview,如下所示:

我不明白如何在 Xamarin 表单中实现这种类型的 ListView

【问题讨论】:

标签: xamarin xamarin.forms xamarin.ios xamarin.android xamarin-studio


【解决方案1】:

您可以通过自定义控件实现水平和垂直列表视图。请参考此代码,

1) 为渲染的 Listview 扩展 Scrollview 属性

using System;
using System.Collections;
using System.Collections.Generic;
using System.Windows.Input;
using Xamarin.Forms;
namespace ProjectName.CustomControls
{
public class HorizontalListview : ScrollView
    {
        public static readonly BindableProperty ItemsSourceProperty =
            BindableProperty.Create("ItemsSource", typeof(IEnumerable), typeof(HorizontalListview), default(IEnumerable));

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

        public static readonly BindableProperty ItemTemplateProperty =
            BindableProperty.Create("ItemTemplate", typeof(DataTemplate), typeof(HorizontalListview), default(DataTemplate));

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

        public event EventHandler<ItemTappedEventArgs> ItemSelected;

        public static readonly BindableProperty SelectedCommandProperty =
            BindableProperty.Create("SelectedCommand", typeof(ICommand), typeof(HorizontalListview), null);

        public ICommand SelectedCommand
        {
            get { return (ICommand)GetValue(SelectedCommandProperty); }
            set { SetValue(SelectedCommandProperty, value); }
        }

        public static readonly BindableProperty SelectedCommandParameterProperty =
            BindableProperty.Create("SelectedCommandParameter", typeof(object), typeof(HorizontalListview), null);

        public object SelectedCommandParameter
        {
            get { return GetValue(SelectedCommandParameterProperty); }
            set { SetValue(SelectedCommandParameterProperty, value); }
        }


        public void Render()
        {
            if (ItemTemplate == null || ItemsSource == null)
                return;

            var layout = new StackLayout();
           layout.Spacing = 0;

            layout.Orientation = Orientation == ScrollOrientation.Vertical ? StackOrientation.Vertical : StackOrientation.Horizontal;

            foreach (var item in ItemsSource)
            {
                var command = SelectedCommand ?? new Command((obj) =>
                {
                    var args = new ItemTappedEventArgs(ItemsSource, item);
                    ItemSelected?.Invoke(this, args);
                });
                var commandParameter = SelectedCommandParameter ?? item;

                var viewCell = ItemTemplate.CreateContent() as ViewCell;
                viewCell.View.BindingContext = item;
                viewCell.View.GestureRecognizers.Add(new TapGestureRecognizer
                {
                    Command = command,
                    CommandParameter = commandParameter,
                    NumberOfTapsRequired = 1
                });
                layout.Children.Add(viewCell.View);
            }

            Content = layout;
        }
    }

2) 在 XAML 页面中包含命名空间

xmlns:control="clr-namespace:ProjectName"

3) 在设计中使用控制

<control:HorizontalListview Orientation="Horizontal" x:Name="lst">                   
                    <control:HorizontalListview.ItemTemplate>
                        <DataTemplate>
                            <ViewCell>
                                <Label Style="{StaticResource lblPlaceNumberRing}" />
                            </ViewCell>
                        </DataTemplate>
                    </control:HorizontalListview.ItemTemplate>
                </control:HorizontalListview>

4) 为 Android 制作渲染器

using System;
using System.ComponentModel;
using ProjectName;
using ProjectName.Droid;
using Xamarin.Forms;
using Xamarin.Forms.Platform.Android;


[assembly: ExportRenderer(typeof(HorizontalListview), typeof(HorizontalListviewRendererAndroid))]

namespace ProjectName.Droid.Renderers
{
    public class HorizontalListviewRendererAndroid : ScrollViewRenderer
    {
        protected override void OnElementChanged(VisualElementChangedEventArgs e)
        {
            base.OnElementChanged(e);

            var element = e.NewElement as HorizontalListview;
            element?.Render();

            if (e.OldElement != null)
                e.OldElement.PropertyChanged -= OnElementPropertyChanged;

            e.NewElement.PropertyChanged += OnElementPropertyChanged;

        }

        protected void OnElementPropertyChanged(object sender, PropertyChangedEventArgs e)
        {
            if (ChildCount > 0)
            {
                GetChildAt(0).HorizontalScrollBarEnabled = false;
                GetChildAt(0).VerticalScrollBarEnabled = false;
            }
        }
    }
}

5) 制作 iOS 渲染器

using System;
using UIKit;
using ProjectName.iOS;
using Xamarin.Forms;
using Xamarin.Forms.Platform.iOS;
using ProjectName;
using System.ComponentModel;

[assembly: ExportRenderer(typeof(HorizontalListview), typeof(HorizontalListviewRendererIos))]

namespace ProjectName.iOS.Renderers
{
    public class HorizontalListviewRendererIos : ScrollViewRenderer
    {
        protected override void OnElementChanged(VisualElementChangedEventArgs e)
        {
            base.OnElementChanged(e);

            var element = e.NewElement as HorizontalListview;
            element?.Render();
            if (e.OldElement != null)
                e.OldElement.PropertyChanged -= OnElementPropertyChanged;

            e.NewElement.PropertyChanged += OnElementPropertyChanged;
        }

        protected void OnElementPropertyChanged(object sender, PropertyChangedEventArgs e)
        {
            this.ShowsHorizontalScrollIndicator = false;
            this.ShowsVerticalScrollIndicator = false;
            this.AlwaysBounceHorizontal = false;
            this.AlwaysBounceVertical = false;
            this.Bounces = false;

        }
       }
}

【讨论】:

    【解决方案2】:

    我试图在ListView 周围设置一个ScrollView,但如果ListView 负责垂直滚动,而ScrollView 负责水平滚动,则会导致不愉快的行为。所以你必须确保ListView 不会向任何方向滚动,而ScrollView 会双向滚动。

    后者很容易通过设置来实现:

    scrollView.Orientation = ScrollOrientation.Both;
    

    防止滚动ListView 有点棘手。显然,唯一的方法是确保ListView.HeightRequest 大于它实际需要的值。我最终这样做了:

    listView.HeightRequest = listView.RowHeight * (ListUsedAsItemSource.Count + 1) + 1;
    

    括号内的+ 1 也是为标题设置一点高度。如果你没有标题,你可以省略它。另请注意,您必须手动设置listView.RowHeight(我认为默认值为 40)。在我没有自己设置的情况下,它是-1。

    ListView 不会水平滚动,因此您不必在此处阻止任何事情。但默认情况下,ListView 将适合水平空间。因此,您还必须将WidthRequest 设置为类似于上面的HeightRequest。无论如何,您将无法从 ListView 获得类似列宽的内容,因此您将自己定义一个值(并将该值用作列的 WidthRequest

    【讨论】:

    • 请注意,使用此解决方案,ListView 的延迟加载将不再起作用,您将一直加载所有元素。因此,对于(可能)大数据集,这不是一个合适的解决方案。
    【解决方案3】:

    您可以使用RecyclerView。我在github上传了一个demo。

    您可以下载并测试它。该项目使用RecyclerView 包装另一个RecyclerView

    【讨论】:

    • 我想要 xamarin 表单,你有任何自定义的想法。
    • 嗨,@sumitsisodia,抱歉,我没有看到你的项目是 Xamarin.forms。我会试试看。您是否使用过任何第三方库?
    猜你喜欢
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 2011-08-12
    • 2017-05-17
    • 2019-10-20
    • 2014-01-09
    • 1970-01-01
    • 1970-01-01
    相关资源
    最近更新 更多