【问题标题】:Xamarin Forms Swipe Left/Swipe Right GesturesXamarin Forms 向左滑动/向右滑动手势
【发布时间】:2015-07-10 10:21:08
【问题描述】:

我想先说我对移动开发、Xamarin、C#、.Net 完全陌生。

我正在使用 Xamarain Forms 创建一个移动应用程序,并且遇到了我没有可用的滑动手势的问题,至少根据我看到的文档。

我找到了这个网站:http://arteksoftware.com/gesture-recognizers-with-xamarin-forms/

这描述了如何为 IOS/Android 添加一些额外的手势,以便在表单的上下文中访问。在我尝试遵循这一点之前,我想看看其他人是否已经在 Xamarin Forms 应用中实现了滑动,以及他们是如何实现的。

我的目标是必须有一个水平堆栈布局。此布局包含 7 个按钮,每个按钮反映当前一周中的一天。在堆栈布局上向左滑动会将按钮的文本更改为前一周。向右滑动会将按钮的文本更改为下一周。

所以我也在尝试为此使用 MVVM 和 XAML。那么我可以将向左滑动和向右滑动动作分开吗?我想使用 ICommand 根据滑动的方向将某个参数传递给函数。

我们将不胜感激任何这样的例子或任何建议。

【问题讨论】:

  • 看看XLabs tabbed page他们在标签页上实现了左右滑动
  • 好的,我可以看看,不幸的是它没有在 XAML 中实现,但我可能可以使用它。
  • 我使用 XF 为一个项目实现了拖放/滑动/捏合手势,但我发现这样做非常笨拙。尤其是 XF 的封闭和硬编码特性——他们有 TapGestureRecognizer 硬编码,你不能只是实现另一个手势识别器,将它添加到集合中并希望它工作;还有太多私人/内部的事情。我采取的方法是创建一个自定义 ContentView,它支持任何手势和自定义渲染器,将事件传递给视图的子视图
  • 好的,谢谢。您是否碰巧有任何对您有帮助的例子,您可以指出我的方向?涉及到我上面描述的7个按钮来反映一个星期。我将一组 DateTime 对象绑定到按钮,并将每个按钮的文本绑定到该数组中的索引。但是,这种方法的问题是为了让我触发更改,数组本身需要更改。我正在尝试使用 observablecollection,但是否可以绑定到 xaml 中的集合索引?我在网上找不到任何说法。

标签: c# xaml xamarin xamarin.forms


【解决方案1】:

不需要第三方库..无需付费..只需添加这两个类并实现您的滑动侦听器

第 1 步:复制粘贴这两个类

SwipeListener.cs

using System;
using Xamarin.Forms;

namespace SwipeLib
{
public class SwipeListener : PanGestureRecognizer
{
    private ISwipeCallBack mISwipeCallback;
    private double translatedX = 0, translatedY = 0;

    public SwipeListener(View view, ISwipeCallBack iSwipeCallBack)
    {
        mISwipeCallback = iSwipeCallBack;
        var panGesture = new PanGestureRecognizer();
        panGesture.PanUpdated += OnPanUpdated;
        view.GestureRecognizers.Add(panGesture);
    }

    void OnPanUpdated(object sender, PanUpdatedEventArgs e)
    {

        View Content = (View)sender;

        switch (e.StatusType) {

            case GestureStatus.Running:

                try {
                    translatedX = e.TotalX;
                    translatedY = e.TotalY;
                } catch (Exception err) {
                    System.Diagnostics.Debug.WriteLine("" + err.Message);
                }
                break;

            case GestureStatus.Completed:

                System.Diagnostics.Debug.WriteLine("translatedX : " + translatedX);
                System.Diagnostics.Debug.WriteLine("translatedY : " + translatedY);

                if (translatedX < 0 && Math.Abs(translatedX) > Math.Abs(translatedY)) {
                    mISwipeCallback.onLeftSwipe(Content);
                } else if (translatedX > 0 && translatedX > Math.Abs(translatedY)) {
                    mISwipeCallback.onRightSwipe(Content);
                } else if (translatedY < 0 && Math.Abs(translatedY) > Math.Abs(translatedX)) {
                    mISwipeCallback.onTopSwipe(Content);
                } else if (translatedY > 0 && translatedY > Math.Abs(translatedX)) {
                    mISwipeCallback.onBottomSwipe(Content);
                } else {
                    mISwipeCallback.onNothingSwiped(Content);
                }

                break;

        }
    }

}
}

ISwipeCallBack.cs

using System;
using Xamarin.Forms;
namespace SwipeLib
{  
public interface ISwipeCallBack
{

    void onLeftSwipe(View view);
    void onRightSwipe(View view);
    void onTopSwipe(View view);
    void onBottomSwipe(View view);
    void onNothingSwiped(View view);
}
}

第 2 步:从您的 Xamarin 表单中传递视图和接口 obj。然后你得到结果

就我而言,我通过了标签

 SwipeListener swipeListener = new SwipeListener(lbl_swipe, this);

第三步:实现 ISwipeCallBack 接口

public partial class SwipeLibPage : ContentPage, ISwipeCallBack

示例项目 --> https://github.com/rranjithkumar100/Xamarin-Swipe-Library

【讨论】:

  • 平移手势识别器有很大的问题(即使是现在)。有时,它无法捕捉到已完成的手势状态。因此,我不得不使用 android/ios 原生功能完成上述所有逻辑
【解决方案2】:

Xamarin.Forms 引入了 SwipeGestureRecognizer :

<BoxView Color="Teal" ...>
    <BoxView.GestureRecognizers>
        <SwipeGestureRecognizer Direction="Left" Swiped="OnSwiped"/>
    </BoxView.GestureRecognizers>
</BoxView>

【讨论】:

  • 如何为 stacklayout 做同样的事情?
【解决方案3】:

您可以随时查看this 简单演示。并按如下方式使用:

GestureFrame gi = new GestureFrame
        {
            HorizontalOptions = LayoutOptions.FillAndExpand,
            VerticalOptions = LayoutOptions.FillAndExpand,
            BackgroundColor = Color.FromHex("bf3122"),
        };

        gi.SwipeDown += (s, e) =>
        {
            DisplayAlert("Gesture Info", "Swipe Down Detected", "OK");
            ViewModel.SampleCommand.Execute("Swipe Down Detected");
        };

        gi.SwipeTop += (s, e) =>
        {
            DisplayAlert("Gesture Info", "Swipe Top Detected", "OK");
            ViewModel.SampleCommand.Execute("Swipe Top Detected");
        };

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

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

        this.Content = gi;

【讨论】:

【解决方案4】:

仅供参考

SwipeView 在 Xamarin.Forms 4.4 中可用。

SwipeView 类还定义了四个事件:

SwipeStarted 在滑动开始时触发。伴随此事件的 SwipeStartedEventArgs 对象具有 SwipeDirection 类型的 SwipeDirection 属性。

SwipeChanging 在滑动移动时触发。 伴随此事件的 SwipeChangingEventArgs 对象具有 SwipeDirection 类型的 SwipeDirection 属性和 double 类型的 Offset 属性。

SwipeEnded 在滑动结束时触发。伴随此事件的 SwipeEndedEventArgs 对象具有 SwipeDirection 类型的 SwipeDirection 属性。

CloseRequested 在滑动项目关闭时触发。 另外,SwipeView 定义了一个 Close 方法,用于关闭滑动项。

有关某些新 Xamarin Forms 功能的详细信息,请访问此link

【讨论】:

    【解决方案5】:

    基于@Ranjith Kumar 的解决方案,我提出了以下建议:

    public delegate void SwipedEventHandler(ISwipeListener sender, SwipedEventArgs e);
    
    public class SwipedEventArgs : EventArgs
    {
        readonly double _x;
        public double X => _x;
    
        readonly double _y;
        public double Y => _y;
    
        readonly View _view;
        public View View => _view;
    
        public SwipedEventArgs(View view, double x, double y)
        {
            _view = view;
            _x = x;
            _y = y;
        }
    }
    
    public interface ISwipeListener
    {
        event SwipedEventHandler SwipedDown;
    
        event SwipedEventHandler SwipedLeft;
    
        event SwipedEventHandler SwipedNothing;
    
        event SwipedEventHandler SwipedRight;
    
        event SwipedEventHandler SwipedUp;
    
        double TotalX
        {
            get;
        }
    
        double TotalY
        {
            get;
        }
    }
    
    public class SwipeListener : PanGestureRecognizer, ISwipeListener
    {
        public event SwipedEventHandler SwipedDown;
    
        public event SwipedEventHandler SwipedLeft;
    
        public event SwipedEventHandler SwipedNothing;
    
        public event SwipedEventHandler SwipedRight;
    
        public event SwipedEventHandler SwipedUp;
    
        double _totalX = 0, _totalY = 0;
    
        public double TotalX => _totalX;
    
        public double TotalY => _totalY;
    
        readonly View _view;
    
        public SwipeListener(View view) : base()
        {
            _view = view;
            _view.GestureRecognizers.Add(this);
            PanUpdated += OnPanUpdated;
        }
    
        void OnPanUpdated(object sender, PanUpdatedEventArgs e)
        {
            switch (e.StatusType)
            {
                case GestureStatus.Running:
                    try
                    {
                        _totalX = e.TotalX;
                        _totalY = e.TotalY;
                    }
                    catch (Exception exception)
                    {
                        Debug.WriteLine(exception.Message);
                    }
                    break;
    
                case GestureStatus.Completed:
                    if (_totalX < 0 && Math.Abs(_totalX) > Math.Abs(_totalY))
                    {
                        OnSwipedLeft(_totalX, _totalY);
                    }
                    else if (_totalX > 0 && _totalX > Math.Abs(_totalY))
                    {
                        OnSwipedRight(_totalX, _totalY);
                    }
                    else if (_totalY < 0 && Math.Abs(_totalY) > Math.Abs(_totalX))
                    {
                        OnSwipedUp(_totalX, _totalY);
                    }
                    else if (_totalY > 0 && _totalY > Math.Abs(_totalX))
                    {
                        OnSwipedDown(_totalX, _totalY);
                    }
                    else OnSwipedNothing(_totalX, _totalY);
                    break;
    
            }
        }
    
        protected virtual void OnSwipedDown(double x, double y)
            => SwipedDown?.Invoke(this, new SwipedEventArgs(_view, x, y));
    
        protected virtual void OnSwipedLeft(double x, double y)
            => SwipedLeft?.Invoke(this, new SwipedEventArgs(_view, x, y));
    
        protected virtual void OnSwipedNothing(double x, double y)
            => SwipedNothing?.Invoke(this, new SwipedEventArgs(_view, x, y));
    
        protected virtual void OnSwipedRight(double x, double y)
            => SwipedRight?.Invoke(this, new SwipedEventArgs(_view, x, y));
    
        protected virtual void OnSwipedUp(double x, double y)
            => SwipedUp?.Invoke(this, new SwipedEventArgs(_view, x, y));
    }
    

    缺点是在执行滑动时你不能做任何事情,只有在之后。

    【讨论】:

    • 您在@Ranjith 的解决方案中解决了什么问题?还是只是重构?
    • 我写这篇文章已经有一段时间了,但我相信主要是重构。
    【解决方案6】:

    也许这对某人有帮助。

    我遇到了一个问题:其中有一个带有滚动视图和网格的 ContentPage。我需要做的就是处理左右滑动手势。 通过google/stackoverflow/github搜索后,我发现了一个名为XamarinFormsGestures的Nuget包。这对我帮助很大。所有说明都在链接内。 有我的代码:

    Vapolia.Lib.Ui.Gesture.SetSwipeLeftCommand(scrollviewgrid, 
    new Command(() => { OnLeftSwipe(); })); // What's going on when left swiped.
    Vapolia.Lib.Ui.Gesture.SetSwipeRightCommand(scrollviewgrid, 
    new Command(() => { OnRightSwipe(); })); // What's going on when right swiped.
    

    【讨论】:

    • 如果有人对这个包感兴趣,现在我有一个上下滑动手势的问题,解决方案是拒绝这个包...
    猜你喜欢
    • 2011-07-23
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 2013-10-01
    • 2013-02-17
    相关资源
    最近更新 更多