如何使Xamarin冒泡手势

时间:2015-10-27 15:23:06

标签: xamarin xamarin.forms

我目前正在为Xamarin.Forms开发SideDrawer,因为在这一点上,来自telerik的那个是相当糟糕的副作用。

我知道如何在WPF中执行此操作,因为它非常简单,但在Xamarin中却有所不同。

我的GestureFrame代码与this几乎相同。

我已使用some github project / xamarin docs / XLabs上的来源开始使用。起初它进展顺利,但是一旦我将控件置于手势框内,我将不再接收任何事件,因为子控件似乎消耗了任何触摸/手势事件。

这对任何人都响了吗?现在我不确定我可能做错了控制行为这样

1 个答案:

答案 0 :(得分:1)

Xamarin Forms目前处理的唯一手势是Tap和DoubleTap默认情况下这些冒泡。对于Android,Windows和大概IOS每个处理其他手势的方式不同。

Xamarin.Forms世界中事件处理的快速回顾:

在Android上 手势由渲染器处理,每个渲染器都有一个Touch事件。发生手势时,在渲染器中触摸。通过订阅Touch事件并更新EventArgs,您可以确定屏幕上发生了什么。现在,您可以自己决定用户正在做什么,或者使用Mono.Android.GestureDetector为您做出决定。 GestureDetector需要一个GestureListener,当它认为发生了tap或double这样的事件时会通知它。然后,您的Gesture监听器可以包含您想要响应这些事件的任何代码。

在Windows上 每个本机控件在事件发生时自行确定并为这些事件公开一组EventHandler。要响应这些事件,您需要创建一个自定义渲染器并订阅本机控件上的事件,然后执行您自己的代码。

在IOS上? 不知道在我的项目中还没有那么远https://github.com/Indiponics/IndiXam-Lib也许其他人可以给你那件作品。

冒泡活动 让我们看一个简单的冒泡情况:

public class App : Application
{
    public App()
    {
        // The root page of your application
        MainPage = new ContentPage
        {
            Content = new Frame
            {
                Content = 
                    new Label {
                        Text = "Hold Me, Thrill Me, Kiss Me"
                    }
            }
        };
    }
}

让我们把一些自定义渲染器放在一起,看看发生了什么。首先,我们需要为堆栈中的每个控件提供渲染器,因此在我们的示例中为Label Renderer和Frame Renderer。

我们将从Windows开始:

[assembly: ExportRenderer(typeof(Label), typeof(myLabelCustomRenderer))]
[assembly: ExportRenderer(typeof(Frame), typeof(myFrameCustomRenderer))]
namespace App4.WinPhone
{
    public class myFrameCustomRenderer:FrameRenderer 
    {
        protected override void OnElementChanged(ElementChangedEventArgs<Xamarin.Forms.Frame> e)
        {
            base.OnElementChanged(e);
            if(e.NewElement!=null)
            {
                this.Control.Hold += Control_Hold;
            }
        }

        void Control_Hold(object sender, System.Windows.Input.GestureEventArgs e)
        {
            System.Diagnostics.Debug.WriteLine("Frame Held");
            e.Handled = false;
        }
    }
    public class myLabelCustomRenderer : LabelRenderer
    {
        protected override void OnElementChanged(ElementChangedEventArgs<Xamarin.Forms.Label> e)
        {
            base.OnElementChanged(e);
            if (e.NewElement != null)
            {
                this.Control.Hold += Control_Hold;
            }
        }

        void Control_Hold(object sender, System.Windows.Input.GestureEventArgs e)
        {
            System.Diagnostics.Debug.WriteLine("Label Held");
            e.Handled = false;
        }
    }
}

运行这个,我们发现了 在Windows中默认冒泡。如果我们想要通过改变

来关闭冒泡
e.Handled = true;

在我们的标签渲染器中,框架永远不会收到保持事件的通知。

现在适用于Android 在Android上,事情变得有点麻烦。我们将再次创建两个渲染器。

[assembly: ExportRenderer(typeof(Label), typeof(myLabelCustomRenderer))]
[assembly: ExportRenderer(typeof(Frame), typeof(myFrameCustomRenderer))]
namespace App4.Droid
{
    public class myFrameCustomRenderer : FrameRenderer
    {
        protected override void OnElementChanged(ElementChangedEventArgs<Xamarin.Forms.Frame> e)
        {
            base.OnElementChanged(e);
            if (e.NewElement != null)
            {
                this.Touch += myFrameCustomRenderer_Touch;
            }
        }

        void myFrameCustomRenderer_Touch(object sender, Android.Views.View.TouchEventArgs e)
        {
            System.Diagnostics.Debug.WriteLine("You Touched My Frame");
            e.Handled = false;
        }
    }
    public class myLabelCustomRenderer : LabelRenderer
    {
        protected override void OnElementChanged(ElementChangedEventArgs<Xamarin.Forms.Label> e)
        {
            base.OnElementChanged(e);
            if (e.NewElement != null)
            {
                this.Touch += myFrameCustomRenderer_Touch;
            }
        }

        void myFrameCustomRenderer_Touch(object sender, Android.Views.View.TouchEventArgs e)
        {
            System.Diagnostics.Debug.WriteLine("You Touched My Label");
            e.Handled = false;
        }
    }
}

如果我们运行它,看起来一切都与windows我们geta触摸标签中的事件和框架中的触摸事件相同。冒泡似乎是自动的。当我们尝试禁用冒泡时,它会变得混乱。如果我们改变

e.Handled = TRUE;

在标签渲染器中

再次运行应用程序--- 在标签RENDERER中触摸两次。一旦我们触摸屏幕,一旦我们停止。如果我们设置labelrenderer的e.Handled = false;并将Frame设置为true。然后标签触摸后跟帧,但只有帧触发第二次。

此外,如果我们从两个渲染器中删除e.Handled = false并运行应用程序,我们发现只有LabelRenderer的Touch事件会触发。暗示Handled的默认值似乎为真。如果未在渲染器中设置e.Handled = false,则事件将在LabelRenderer中触发,而不会将堆栈冒泡到FrameRenderer。

结论: 冒泡在Windows上开箱即用。在Android上它不会像你期望的那样工作。首先,您必须在每个子节点中显式设置Handled = false,以便父节点获得通知,然后只有处理事件的处理程序才会收到通知,触摸事件结束,其余的堆栈会收到启动通知,但从不知道它的结束