1

我希望能够在整个列表视图(而不是列表视图中的单个项目)上滑动以执行特定操作。我在 Gridview 内的列表视图上附加了滑动手势。它在 iOS 中按预期工作,但在 android 上永远不会触发手势。

我已经尝试将手势识别器放在仅适用于 android 的父 gridview 上。这会重新启用该功能,但前提是滑动包括屏幕的最边缘(我假设由于列表视图没有占用我的小填充。)我该怎么做才能使行为类似于IOS?

<?xml version="1.0" encoding="utf-8" ?>
<ContentView xmlns="http://xamarin.com/schemas/2014/forms"
             xmlns:x="http://schemas.microsoft.com/winfx/2009/xaml"
             xmlns:d="http://xamarin.com/schemas/2014/forms/design"
             xmlns:mc="http://schemas.openxmlformats.org/markup-compatibility/2006"
             xmlns:local="clr-namespace:Test.ViewModels"
             mc:Ignorable="d"
             x:Class="Test.Pages.ViewerPage"
             x:Name="View">
    <ContentView.BindingContext>
        <local:ViewerViewModel />
    </ContentView.BindingContext>
    <Grid Padding="10, 0, 10, 0">
        <Grid.RowDefinitions>
            <RowDefinition Height="auto" />
            <RowDefinition Height="*" />
        </Grid.RowDefinitions>
        <Grid Grid.Row="0" Padding="0, 5, 0, 0">
            <Grid.ColumnDefinitions>
                <ColumnDefinition Width="50" />
                <ColumnDefinition Width="*" />
                <ColumnDefinition Width="50" />
            </Grid.ColumnDefinitions>
            <Button Grid.Column="0" Text="Back" IsVisible="{Binding ShowBackButton}" Clicked="OnBackTap" VerticalOptions="Center" Padding="10, 0, 0, 0">
            </Button>
            <Button Grid.Column="1" x:Name="Header" HorizontalOptions="Center" BorderColor="Black" TextColor="Black" VerticalOptions="Center" BorderWidth="1" Clicked="OnTitleTap">
            </Button>
        </Grid>
        <ListView Grid.Row="1" x:Name="Viewer" HasUnevenRows="True" SeparatorVisibility="None" BackgroundColor="Green">
            <ListView.GestureRecognizers>
                <SwipeGestureRecognizer Direction="Left" Swiped="OnSwiped" />
                <SwipeGestureRecognizer Direction="Right" Swiped="OnSwiped"/>
            </ListView.GestureRecognizers>
            <ListView.ItemTemplate>
                <DataTemplate>
                    <ViewCell IsEnabled="False">
                        <StackLayout>
                            <Label>
                                <Label.FormattedText>
                                    <FormattedString>
                                        <Span Text="{Binding verse}" FontSize="18" TextColor="Gray"></Span>
                                        <Span Text="  "></Span>
                                        <Span Text="{Binding text}" FontSize="18" TextColor="Black"></Span>
                                    </FormattedString>
                                </Label.FormattedText>
                            </Label>
                        </StackLayout>
                    </ViewCell>
                </DataTemplate>
            </ListView.ItemTemplate>
        </ListView>
    </Grid>
</ContentView>
4

2 回答 2

2

您可以创建自定义渲染器列表视图。

  public class MyListview:ListView
    {
        public event EventHandler SwipeLeft;
        public event EventHandler SwipeRight;

        public void OnSwipeLeft() =>
            SwipeLeft?.Invoke(this, null);

        public void OnSwipeRight() =>
            SwipeRight?.Invoke(this, null);
    }

在安卓平台。

using Android.App;
using Android.Content;
using Android.OS;
using Android.Runtime;
using Android.Views;
using Android.Widget;
using App3;
using App3.Droid;
using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;
using Xamarin.Forms;
using Xamarin.Forms.Platform.Android;

[assembly: ExportRenderer(typeof(MyListview), typeof(MyListviewRenderer))]
namespace App3.Droid
{
    class MyListviewRenderer : ListViewRenderer
    {
        readonly CustomGestureListener _listener;
        readonly GestureDetector _detector;
        public MyListviewRenderer(Context context) : base(context)
        {
            _listener = new CustomGestureListener();
            _detector = new GestureDetector(context, _listener);
        }
        public override bool DispatchTouchEvent(MotionEvent e)
        {
            if (_detector != null)
            {
                _detector.OnTouchEvent(e);
                base.DispatchTouchEvent(e);
                return true;
            }

            return base.DispatchTouchEvent(e);
        }

        public override bool OnTouchEvent(MotionEvent ev)
        {
            base.OnTouchEvent(ev);

            if (_detector != null)
                return _detector.OnTouchEvent(ev);

            return false;
        }

        protected override void OnElementChanged(ElementChangedEventArgs<Xamarin.Forms.ListView> e)
        {
            base.OnElementChanged(e);

            if (e.NewElement == null)
            {
                _listener.OnSwipeLeft -= HandleOnSwipeLeft;
                _listener.OnSwipeRight -= HandleOnSwipeRight;
            }

            if (e.OldElement == null)
            {
                _listener.OnSwipeLeft += HandleOnSwipeLeft;
                _listener.OnSwipeRight += HandleOnSwipeRight;
            }
        }
        

        void HandleOnSwipeLeft(object sender, EventArgs e) =>
            ((MyListview)Element).OnSwipeLeft();

        void HandleOnSwipeRight(object sender, EventArgs e) =>
            ((MyListview)Element).OnSwipeRight();
    }


    public class CustomGestureListener : GestureDetector.SimpleOnGestureListener
    {
        static readonly int SWIPE_THRESHOLD = 100;
        static readonly int SWIPE_VELOCITY_THRESHOLD = 100;

        MotionEvent mLastOnDownEvent;

        public event EventHandler OnSwipeLeft;
        public event EventHandler OnSwipeRight;

        public override bool OnDown(MotionEvent e)
        {
            mLastOnDownEvent = e;

            return true;
        }

        public override bool OnFling(MotionEvent e1, MotionEvent e2, float velocityX, float velocityY)
        {
            if (e1 == null)
                e1 = mLastOnDownEvent;

            float diffY = e2.GetY() - e1.GetY();
            float diffX = e2.GetX() - e1.GetX();

            if (Math.Abs(diffX) > Math.Abs(diffY))
            {
                if (Math.Abs(diffX) > SWIPE_THRESHOLD && Math.Abs(velocityX) > SWIPE_VELOCITY_THRESHOLD)
                {
                    if (diffX > 0)
                        OnSwipeRight?.Invoke(this, null);
                    else
                        OnSwipeLeft?.Invoke(this, null);
                }
            }

            return base.OnFling(e1, e2, velocityX, velocityY);
        }
    }
 
}

然后你可以在 xaml 中使用它。

   <app3:MyListview  x:Name="gi">

            <app3:MyListview.ItemsSource>
                <x:Array Type="{x:Type x:String}">
                    <x:String>mono</x:String>
                    <x:String>monodroid</x:String>
                    <x:String>monotouch</x:String>
                    <x:String>monorail</x:String>
                    <x:String>monodevelop</x:String>
                    <x:String>monotone</x:String>
                    <x:String>monopoly</x:String>
                    <x:String>monomodal</x:String>
                    <x:String>mononucleosis</x:String>
                </x:Array>
            </app3:MyListview.ItemsSource>
        </app3:MyListview>

这是layot背景代码,

 public MainPage()
        {
            InitializeComponent();

            gi.SwipeLeft += (s, e) =>
    DisplayAlert("Gesture Info", "Swipe Left Detected", "OK");

            gi.SwipeRight += (s, e) =>
                DisplayAlert("Gesture Info", "Swipe Right Detected", "OK");
        }

这是运行的gif。

在此处输入图像描述

于 2020-11-24T15:07:53.833 回答
0

您可以使用SwipeView。将您的 ListView 包裹在 SwipeView 中。

<SwipeView SwipeStarted="SwipeView_SwipeStarted" SwipeEnded="SwipeView_SwipeEnded" SwipeChanging="SwipeView_SwipeChanging">
    
    <SwipeView.RightItems>
        <SwipeItems Mode="Reveal | Execute">
            <SwipeItem Text="Your Action" Command="{Binding SwipeRightToLeftCommand}" />
        </SwipeItems>
    </SwipeView.RightItems>
    
    <SwipeView.LeftItems>
        <SwipeItems Mode="Reveal | Execute">
            <SwipeItem Text="Your Action" Command="{Binding SwipeLeftToRightCommand}" />
        </SwipeItems>
    </SwipeView.LeftItems>
    
    <ListView>
    .
    . Your Complete ListView
    .
    </ListView>
    
</SwipeView>
  • 要启用从右向左滑动,请使用SwipeView.RightItems,对于从左到右,请使用SwipeView.LeftItems。如果您想在两个方向上启用滑动,请同时使用。

  • SwipeItems.Mode="Execute"将在刷卡时直接执行命令。

  • SwipeItems.Mode="Reveal"只会显示操作按钮,您必须单击它才能执行命令。

  • SwipeView目前是实验性的,所以记得在你的MainActivity类中添加以下行,然后再调用Forms.Init.

     Forms.SetFlags("SwipeView_Experimental");
    
于 2020-11-27T19:41:51.370 回答