Xamarin.Forms - Button Pressed&发布的活动

时间:2016-08-06 10:18:50

标签: c# events cross-platform xamarin.forms

我想在按下按下并释放按钮时触发我的事件,但我只能在Xamarin.Forms中找到点击事件。

我相信必须有一些工作才能获得此功能。我的基本需求是在按下按钮时启动一个过程,在释放时停止。这似乎是一个非常基本的功能,但Xamarin.Forms现在还没有。

我在按钮上尝试了TapGestureRecognizer,但按钮仅触发了点击事件。

MyButton.Clicked += (sender, args) =>
{
  Log.V(TAG, "CLICKED");
};

var tapGestureRecognizer = new TapGestureRecognizer();
tapGestureRecognizer.Tapped += (s, e) => {
    Log.V(TAG, "TAPPED");
};
MyButton.GestureRecognizers.Add(tapGestureRecognizer);

请记住,我需要在Android和iOS中使用这些活动。

5 个答案:

答案 0 :(得分:20)

最后我得到了@Jason建议的解决方案。我们走了......

  1. 使用event在PCL项目中创建Xamarin.Forms.Button的子类 处理能力

    public class CustomButton : Button
    {
        public event EventHandler Pressed;
        public event EventHandler Released;
    
        public virtual void OnPressed()
        {
          Pressed?.Invoke(this, EventArgs.Empty);
        }
    
        public virtual void OnReleased()
        {
          Released?.Invoke(this, EventArgs.Empty);
        }
    }
    
  2. 在相应项目中创建特定于平台的按钮渲染器

    对于Andorid

    [assembly: ExportRenderer(typeof(Button), typeof(CustomButtonRenderer))]
    namespace WalkieTalkie.Droid.Renderer
    {
        public class CustomButtonRenderer : ButtonRenderer
        {
            protected override void OnElementChanged(ElementChangedEventArgs<Xamarin.Forms.Button> e)
            {
                base.OnElementChanged(e);
    
                var customButton = e.NewElement as CustomButton;
    
                var thisButton = Control as Android.Widget.Button;
                thisButton.Touch += (object sender, TouchEventArgs args) =>
                {
                    if (args.Event.Action == MotionEventActions.Down)
                    {
                        customButton.OnPressed();
                    }
                    else if (args.Event.Action == MotionEventActions.Up)
                    {
                        customButton.OnReleased();
                    }
                };
            }
        }
    }
    

    对于IOS

    [assembly: ExportRenderer(typeof(CustomButton), typeof(CustomButtonRenderer))]
    namespace WalkieTalkie.iOS.Renderer
    {
        public class CustomButtonRenderer : ButtonRenderer
        {
            protected override void    OnElementChanged(ElementChangedEventArgs<Xamarin.Forms.Button> e)
            {
                base.OnElementChanged(e);
    
                var customButton = e.NewElement as CustomButton;
    
                var thisButton = Control as UIButton;
                thisButton.TouchDown += delegate
                {
                    customButton.OnPressed();
                };
                thisButton.TouchUpInside += delegate
                {
                    customButton.OnReleased();
                };
            }
        }
    }
    
  3. 在页面中实例化自定义按钮

    var myButton = new CustomButton
    {
        Text = "CustomButton",
        HorizontalOptions = LayoutOptions.FillAndExpand
    };
    myButton.Pressed += (sender, args) =>
    {
        System.Diagnostics.Debug.WriteLine("Pressed");
    };
    myButton.Released += (sender, args) =>
    {
         System.Diagnostics.Debug.WriteLine("Pressed");
    };
    
  4. 希望这能帮助别人:)

答案 1 :(得分:6)

这也可以使用效果而不是完整的自定义渲染器来完成。有关如何操作的说明,请参阅此文章:

https://alexdunn.org/2017/12/27/xamarin-tip-xamarin-forms-long-press-effect/

如果该帖子消失,以下是您可以实施的代码:

  

在共享项目中:

/// <summary>
/// Long pressed effect. Used for invoking commands on long press detection cross platform
/// </summary>
public class LongPressedEffect : RoutingEffect
{
    public LongPressedEffect() : base("MyApp.LongPressedEffect")
    {
    }

    public static readonly BindableProperty CommandProperty = BindableProperty.CreateAttached("Command", typeof(ICommand), typeof(LongPressedEffect), (object)null);
    public static ICommand GetCommand(BindableObject view)
    {
        return (ICommand)view.GetValue(CommandProperty);
    }

    public static void SetCommand(BindableObject view, ICommand value)
    {
        view.SetValue(CommandProperty, value);
    }


    public static readonly BindableProperty CommandParameterProperty = BindableProperty.CreateAttached("CommandParameter", typeof(object), typeof(LongPressedEffect), (object)null);
    public static object GetCommandParameter(BindableObject view)
    {
        return view.GetValue(CommandParameterProperty);
    }

    public static void SetCommandParameter(BindableObject view, object value)
    {
        view.SetValue(CommandParameterProperty, value);
    }
}
  

在Android中:

[assembly: ResolutionGroupName("MyApp")]
[assembly: ExportEffect(typeof(AndroidLongPressedEffect), "LongPressedEffect")]
namespace AndroidAppNamespace.Effects
{
    /// <summary>
    /// Android long pressed effect.
    /// </summary>
    public class AndroidLongPressedEffect : PlatformEffect
    {
        private bool _attached;

        /// <summary>
        /// Initializer to avoid linking out
        /// </summary>
        public static void Initialize() { }

        /// <summary>
        /// Initializes a new instance of the
        /// <see cref="T:Yukon.Application.AndroidComponents.Effects.AndroidLongPressedEffect"/> class.
        /// Empty constructor required for the odd Xamarin.Forms reflection constructor search
        /// </summary>
        public AndroidLongPressedEffect()
        {
        }

        /// <summary>
        /// Apply the handler
        /// </summary>
        protected override void OnAttached()
        {
            //because an effect can be detached immediately after attached (happens in listview), only attach the handler one time.
            if (!_attached)
            {
                if (Control != null)
                {
                    Control.LongClickable = true;
                    Control.LongClick += Control_LongClick;
                }
                else
                {
                    Container.LongClickable = true;
                    Container.LongClick += Control_LongClick;
                }
                _attached = true;
            }
        }

        /// <summary>
        /// Invoke the command if there is one
        /// </summary>
        /// <param name="sender">Sender.</param>
        /// <param name="e">E.</param>
        private void Control_LongClick(object sender, Android.Views.View.LongClickEventArgs e)
        {
            Console.WriteLine("Invoking long click command");
            var command = LongPressedEffect.GetCommand(Element);
            command?.Execute(LongPressedEffect.GetCommandParameter(Element));
        }

        /// <summary>
        /// Clean the event handler on detach
        /// </summary>
        protected override void OnDetached()
        {
            if (_attached)
            {
                if (Control != null)
                {
                    Control.LongClickable = true;
                    Control.LongClick -= Control_LongClick;
                }
                else
                {
                    Container.LongClickable = true;
                    Container.LongClick -= Control_LongClick;
                }
                _attached = false;
            }
        }
    }
}
  

在iOS中:

[assembly: ResolutionGroupName("MyApp")]
[assembly: ExportEffect(typeof(iOSLongPressedEffect), "LongPressedEffect")]
namespace iOSNamespace.Effects
{
    /// <summary>
    /// iOS long pressed effect
    /// </summary>
    public class iOSLongPressedEffect : PlatformEffect
    {
        private bool _attached;
        private readonly UILongPressGestureRecognizer _longPressRecognizer;
        /// <summary>
        /// Initializes a new instance of the
        /// <see cref="T:Yukon.Application.iOSComponents.Effects.iOSLongPressedEffect"/> class.
        /// </summary>
        public iOSLongPressedEffect()
        {
            _longPressRecognizer = new UILongPressGestureRecognizer(HandleLongClick);
        }

        /// <summary>
        /// Apply the handler
        /// </summary>
        protected override void OnAttached()
        {
            //because an effect can be detached immediately after attached (happens in listview), only attach the handler one time
            if (!_attached)
            {
                Container.AddGestureRecognizer(_longPressRecognizer);
                _attached = true;
            }
        }

        /// <summary>
        /// Invoke the command if there is one
        /// </summary>
        private void HandleLongClick()
        {
            var command = LongPressedEffect.GetCommand(Element);
            command?.Execute(LongPressedEffect.GetCommandParameter(Element));
        }

        /// <summary>
        /// Clean the event handler on detach
        /// </summary>
        protected override void OnDetached()
        {
            if (_attached)
            {
                Container.RemoveGestureRecognizer(_longPressRecognizer);
                _attached = false;
            }
        }

    }
}
  

在XAML中

<Label Text="Long Press Me!" effects:LongPressedEffect.Command="{Binding ShowAlertCommand}" effects:LongPressedEffect.CommandParameter="{Binding .}">
    <Label.Effects>
        <effects:LongPressedEffect />
    </Label.Effects>
</Label>

答案 2 :(得分:2)

Button button = FindViewById (Resource.Id.myButton);
button.Touch += (object sender, View.TouchEventArgs e) =>
{
if (e.Event.Action == MotionEventActions.Up)
{
Toast.MakeText(this, "Key Up", ToastLength.Short).Show();
}
        if(e.Event.Action == MotionEventActions.Down)
        {
            Toast.MakeText(this, "Key Down", ToastLength.Short).Show();
        }
    };

答案 3 :(得分:2)

自Xamarin.Forms 2.4.0起,事件PressedReleased开箱即用(参见PR)。

注意:为了实现Walkie Talkie效果,您可能需要使用Device.BeginInvokeOnMainThread(或通过Prism&#39; IDeviceService)来调用后续操作,以便Released事件将调用,否则可能会阻止UI线程 或者,您可以将事件处理程序声明为asyncawait您的调用,以保持UI线程不被占用。

答案 4 :(得分:0)

为了在Xamarin上拦截PressedReleased事件,我使用了this official Guide中所述的Effects属性。

使用TouchTracking.Forms更为简单。

首先将库添加到您的Forms项目中(平台特定项目中不需要)。

接下来在Xaml分析中使用它

<StackLayout>
    <StackLayout.Effects>
        <tt:TouchEffect TouchAction="Handle_TouchAction" />
    </StackLayout.Effects>
    <Label Text="Sample"/>
</StackLayout>

tt是指:

xmlns:tt="clr-namespace:TouchTracking.Forms;assembly=TouchTracking.Forms"

最后,您在后面的代码中工作吗?

void Handle_TouchAction(object sender, TouchTracking.TouchActionEventArgs args)
{
    ;
}

Handle_TouchAction会在每次触摸操作发生时被调用,请使用args.Type来区分操作PressedReleasedExited ...

NB Effects不仅适用于StackLayout,还适用于各种组件。