В Xamarin.Forms - Кнопка Нажата И Выпущено Событие

Я хочу, чтобы мое событие запускалось, когда кнопка нажать и отпустить, но я могу только найти клик событие в Xamarin.Формы.

Я считаю, что должна быть какая-то работа, чтобы получить эту функциональность. Моя основная потребность -запуск процесса при нажатии кнопки и остановка при освобождении. Кажется, это очень простая функция, но Xamarin.В формулярах сейчас этого нет.

я попробовал 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 togather.

4 ответов


наконец, я получил решение, предложенное @Jason. Вот и мы...

  1. создать подкласс Xamarin.Формы.Кнопка в проекте PCL, с событием возможность обработки

    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");
    };
    

надеюсь, что это поможет кому-то :)


Это также может быть сделано с эффектом вместо полноценного пользовательского рендерера. См. этот пост для объяснения того, как это сделать:

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>

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();
        }
    };

Начиная С Xamarin.Формы 2.4.0, события Pressed и Released предлагаются из коробки (см. PR).

Примечание: Для достижения эффекта рации вы можете использовать Device.BeginInvokeOnMainThread (или через призму IDeviceService) вызывать последующие действия, чтобы Released событие будет вызываться, иначе поток пользовательского интерфейса может быть заблокирован.
Кроме того, можно объявить обработчики событий как async и await ваши заклинания, чтобы держите поток пользовательского интерфейса незанятым.