Xamarin.forms Xamarin表单:如何为StackLayout添加SwipegestureRecognitor?

Xamarin.forms Xamarin表单:如何为StackLayout添加SwipegestureRecognitor?,xamarin.forms,swipe-gesture,stacklayout,Xamarin.forms,Swipe Gesture,Stacklayout,我的主页上有15个选项。最初,我将在UI中显示9个选项。要查看剩余的6个图标,用户可向右滑动并向左滑动以查看上一个图标。我尝试实现如下所示的刷卡功能,但它不起作用 XAML <StackLayout x:Name="firstLlayout"> <Grid> //3 icons in horizontal </Grid> <Grid> //3 icons in horizontal

我的主页上有15个选项。最初,我将在UI中显示9个选项。要查看剩余的6个图标,用户可向右滑动并向左滑动以查看上一个图标。我尝试实现如下所示的刷卡功能,但它不起作用

XAML

<StackLayout x:Name="firstLlayout">
    <Grid>
        //3 icons in horizontal
    </Grid>

    <Grid>
        //3 icons in horizontal
    </Grid>

    <Grid>
        //3 icons in horizontal
    </Grid>
    <StackLayout.GestureRecognizers>
        <SwipeGestureRecognizer Direction="Right" Swiped="RightSwipe"/>
    </StackLayout.GestureRecognizers>
</StackLayout>

<StackLayout IsVisible="False" x:Name="secondLayout">
     <Grid>
        //3 icons in horizontal
    </Grid>

    <Grid>
        //3 icons in horizontal
    </Grid>
    <StackLayout.GestureRecognizers>
        <SwipeGestureRecognizer Direction="Left" Swiped="LeftSwipe"/>
    </StackLayout.GestureRecognizers>
</StackLayout>

当尝试向左和向右滑动时,UI中不会发生任何事情,事件函数也不会执行代码。我在这里错过了什么?

原因1:

如果将stacklayout置于滚动视图中,则滑动操作将与滚动操作冲突

解决方案:

从根StackLayout中删除ScrollView,然后刷卡即可工作

原因2:必须将子控件(如图像或标签)添加到StackLayout,否则将永远不会调用滑动操作

解决方案:如果您想让StackLayout的内容在默认情况下不显示任何内容,可以检查以下代码

暗藏 在Android项目中 在Xaml中

将StackLayout放在ScrollView中

<local:GestureScrollView SwipeRight="RightSwipe">
     <StackLayout x:Name="firstLlayout" >

        //...        
     </StackLayout>

          
</local:GestureScrollView>

//...        

现在我注意到刷卡一开始不起作用。试了几次后,它开始工作了。我删除了根stacklayout,但仍然存在此问题。有什么评论吗?
using System;
using Xamarin.Forms;

namespace xxx
{
    public class GestureScrollView : ScrollView
    {
        public event EventHandler SwipeLeft;
        public event EventHandler SwipeRight;

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

        public void OnSwipeRight() =>
            SwipeRight?.Invoke(this, null);
    }
}
using System;
using Android.Content;
using Android.OS;
using Android.Runtime;
using Android.Views;
using Android.Widget;
using xxx;
using xxx.Droid;
using Xamarin.Forms;
using Xamarin.Forms.Platform.Android;

[assembly: ExportRenderer(typeof(GestureScrollView), typeof(GestureScrollViewRenderer))]
namespace xxx.Droid
{
    public class GestureScrollViewRenderer : ScrollViewRenderer
    {
        readonly CustomGestureListener _listener;
        readonly GestureDetector _detector;

        public GestureScrollViewRenderer(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(VisualElementChangedEventArgs 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) =>
            ((GestureScrollView)Element).OnSwipeLeft();

        void HandleOnSwipeRight(object sender, EventArgs e) =>
            ((GestureScrollView)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);
        }
    }
}
<local:GestureScrollView SwipeRight="RightSwipe">
     <StackLayout x:Name="firstLlayout" >

        //...        
     </StackLayout>

          
</local:GestureScrollView>