Xamarin 表单在按下时禁用图像按钮,背景不正确

发布于 2025-01-14 00:01:01 字数 5438 浏览 1 评论 0原文

我的 Android 图像按钮背景有问题。我根据按下/释放事件实现了长按图像按钮。第一个问题是当我禁用按钮时发布事件。我通过调用 PropagateUpReleased 解决了这个问题,在 iOS 上这就足够了,但在 Android 上我遇到了问题,当我将按钮设置为再次启用时,我有一个按钮背景,就像它被按下一样:

  • ,按钮有深灰色
  • 长按向上箭头 ImageButton (XamarinForms) 的最大设置按钮为禁用
  • 传播释放按钮
  • 释放称为
  • 禁用按钮具有浅灰色
  • 单击向下箭头,向上箭头设置为启用,背景颜色为深灰色 我的 ImageButtonRenderer 实现:

        public CustomButtonRenderer(Context context) : base(context)
        {
        }

        protected override void OnElementPropertyChanged(object sender, PropertyChangedEventArgs e)
        {

            base.OnElementPropertyChanged(sender, e);

            if (e.PropertyName == nameof(Button.IsEnabled) && !Element.IsEnabled && Element.IsPressed)
            {
                PropagateRelease();
            }
        }

        public override bool OnTouchEvent(MotionEvent e)
        {
            if (e.Action == MotionEventActions.Cancel)
                PropagateRelease();
            return base.OnTouchEvent(e);
        }

        private void PropagateRelease()
        {
            Element.PropagateUpReleased();
            ((IButtonController)Element).SendReleased();

            Invalidate();
            PostInvalidate();
        }

编辑:

这是我的行为实现:

 public class LongPressBehavior : Behavior<ImageButton>
    {
        private readonly object syncObject = new object();
        private const int DurationStartLongPress = 500;
        private const int DurationNextLongPress = 150;
        private ImageButton button;


        private Timer startTimer;
        private Timer nextTimer;
        private volatile bool isReleased;

        public static readonly BindableProperty CommandProperty = BindableProperty.Create(nameof(Command),
            typeof(ICommand), typeof(LongPressBehavior), default(ICommand));

        public ICommand Command
        {
            get => (ICommand)GetValue(CommandProperty);
            set => SetValue(CommandProperty, value);
        }

        #region Cnt
        public LongPressBehavior()
        {
            isReleased = true;
        }
        #endregion

        #region LifeCycles
        protected override void OnAttachedTo(ImageButton button)
        {
            this.button = button;
            base.OnAttachedTo(button);
            this.BindingContext = button.BindingContext;

            button.Pressed += Button_Pressed;
            button.Released += Button_Released;
        }

        protected override void OnDetachingFrom(ImageButton button)
        {
            base.OnDetachingFrom(button);
            this.BindingContext = null;
            
            button.Pressed -= Button_Pressed;
            button.Released -= Button_Released;
        }
        #endregion

        #region Events
        private void Button_Pressed(object sender, EventArgs e)
        {
            Debug.WriteLine("Pressed...");
            isReleased = false;
            InitializeStartTimer();
        }

        private void Button_Released(object sender, EventArgs e)
        {
            
            Debug.WriteLine("Released...");
            isReleased = true;

            DeInitializeTimer(ref startTimer);
            DeInitializeTimer(ref nextTimer);
        }

        protected virtual void OnLongPressed()
        {
            if (button.Command != null)
            {
                Debug.WriteLine("Longpress execute...");
                button.Command.Execute(null);
            }

            if (nextTimer == null)
                InitializeNextTimer();
        }

        private void Timer_Elapsed(object state)
        {
            if (isReleased)
            {
                return;
            }
            Device.BeginInvokeOnMainThread(OnLongPressed);
        }
        #endregion

        #region Private methods
        private void DeInitializeTimer(ref Timer timer)
        {
            Debug.WriteLine("Dispose timer...");
            lock (syncObject)
            {
                if (timer == null)
                {
                    return;
                }
                timer.Change(Timeout.Infinite, Timeout.Infinite);
                timer.Dispose();
                timer = null;
                Debug.WriteLine("Timer disposed...");
            }
        }

        private void InitializeStartTimer()
        {
            Debug.WriteLine("Initialize start timer...");
            lock (syncObject)
            {
                startTimer = new Timer(Timer_Elapsed, null, DurationStartLongPress, Timeout.Infinite);
            }
        }

        private void InitializeNextTimer()
        {
            Debug.WriteLine("Initialize next timer...");
            lock (syncObject)
            {
                if (startTimer != null)
                    DeInitializeTimer(ref startTimer);
                nextTimer = new Timer(Timer_Elapsed, null, DurationNextLongPress, DurationNextLongPress);
            }
        }
        #endregion
    }

问题场景: 我们有 2 个带有向上和向下箭头的按钮来增加和减少值。我们也有最小值和最大值的限制。按钮为白色。

  • 用户触摸按钮
  • 按下事件被调用,计时器被初始化
  • 我在小于maksimum(执行的命令)时增加值。如果 value 有一个 maxsimum,我将 IsEnabled 设置为 false
  • Release 事件不会被调用(即使用户释放按钮),而是我手动调用 PropagateUpReleased Android 上的渲染器
  • 按钮是浅灰色
  • 触摸向下按钮
  • 现在值小于最大值,我将按钮 IsEnabled 设置为 true,按钮背景为深灰色(与我们触摸按钮相同)

I had problem with android image button background. I had implementation of long press on image button based on Pressed/Released events. First problem was with Released event when I disabled button. I resolve it by call PropagateUpReleased, on iOS it is enough, but on android I had problem that when I set button to enabled again I had a background of button like it was pressed:

  • long press on up arrow, button have dark gray color
  • get the maximum, set button to disabled
  • propagate release button
  • release of ImageButton (XamarinForms) is call
  • disabled button have light gray color
  • click on down arrow, up arrow set to enabled, background color is dark gray
    My implementation of ImageButtonRenderer:

        public CustomButtonRenderer(Context context) : base(context)
        {
        }

        protected override void OnElementPropertyChanged(object sender, PropertyChangedEventArgs e)
        {

            base.OnElementPropertyChanged(sender, e);

            if (e.PropertyName == nameof(Button.IsEnabled) && !Element.IsEnabled && Element.IsPressed)
            {
                PropagateRelease();
            }
        }

        public override bool OnTouchEvent(MotionEvent e)
        {
            if (e.Action == MotionEventActions.Cancel)
                PropagateRelease();
            return base.OnTouchEvent(e);
        }

        private void PropagateRelease()
        {
            Element.PropagateUpReleased();
            ((IButtonController)Element).SendReleased();

            Invalidate();
            PostInvalidate();
        }

Edit:

This is my implementation of behavior:

 public class LongPressBehavior : Behavior<ImageButton>
    {
        private readonly object syncObject = new object();
        private const int DurationStartLongPress = 500;
        private const int DurationNextLongPress = 150;
        private ImageButton button;


        private Timer startTimer;
        private Timer nextTimer;
        private volatile bool isReleased;

        public static readonly BindableProperty CommandProperty = BindableProperty.Create(nameof(Command),
            typeof(ICommand), typeof(LongPressBehavior), default(ICommand));

        public ICommand Command
        {
            get => (ICommand)GetValue(CommandProperty);
            set => SetValue(CommandProperty, value);
        }

        #region Cnt
        public LongPressBehavior()
        {
            isReleased = true;
        }
        #endregion

        #region LifeCycles
        protected override void OnAttachedTo(ImageButton button)
        {
            this.button = button;
            base.OnAttachedTo(button);
            this.BindingContext = button.BindingContext;

            button.Pressed += Button_Pressed;
            button.Released += Button_Released;
        }

        protected override void OnDetachingFrom(ImageButton button)
        {
            base.OnDetachingFrom(button);
            this.BindingContext = null;
            
            button.Pressed -= Button_Pressed;
            button.Released -= Button_Released;
        }
        #endregion

        #region Events
        private void Button_Pressed(object sender, EventArgs e)
        {
            Debug.WriteLine("Pressed...");
            isReleased = false;
            InitializeStartTimer();
        }

        private void Button_Released(object sender, EventArgs e)
        {
            
            Debug.WriteLine("Released...");
            isReleased = true;

            DeInitializeTimer(ref startTimer);
            DeInitializeTimer(ref nextTimer);
        }

        protected virtual void OnLongPressed()
        {
            if (button.Command != null)
            {
                Debug.WriteLine("Longpress execute...");
                button.Command.Execute(null);
            }

            if (nextTimer == null)
                InitializeNextTimer();
        }

        private void Timer_Elapsed(object state)
        {
            if (isReleased)
            {
                return;
            }
            Device.BeginInvokeOnMainThread(OnLongPressed);
        }
        #endregion

        #region Private methods
        private void DeInitializeTimer(ref Timer timer)
        {
            Debug.WriteLine("Dispose timer...");
            lock (syncObject)
            {
                if (timer == null)
                {
                    return;
                }
                timer.Change(Timeout.Infinite, Timeout.Infinite);
                timer.Dispose();
                timer = null;
                Debug.WriteLine("Timer disposed...");
            }
        }

        private void InitializeStartTimer()
        {
            Debug.WriteLine("Initialize start timer...");
            lock (syncObject)
            {
                startTimer = new Timer(Timer_Elapsed, null, DurationStartLongPress, Timeout.Infinite);
            }
        }

        private void InitializeNextTimer()
        {
            Debug.WriteLine("Initialize next timer...");
            lock (syncObject)
            {
                if (startTimer != null)
                    DeInitializeTimer(ref startTimer);
                nextTimer = new Timer(Timer_Elapsed, null, DurationNextLongPress, DurationNextLongPress);
            }
        }
        #endregion
    }

Problem scenerio:
We have 2 buttons with arrow up and down to increase and decrease value. Also we have limits of value min and max. Buttons have a white color.

  • user touch up button
  • pressed event is call, timer is initialize
  • I increase the value while is less than maksimum (executed command). If value have a maksimum I set IsEnabled to false
  • Release event is not call (even if user release button) , instead I call manually PropagateUpReleased in renderer
  • button on android is light gray
  • touch to down button
  • now value is less than max, I set up button IsEnabled to true, background of button is dark gray (the same like we touch button)

如果你对这篇内容有疑问,欢迎到本站社区发帖提问 参与讨论,获取更多帮助,或者扫码二维码加入 Web 技术交流群。

扫码二维码加入Web技术交流群

发布评论

需要 登录 才能够评论, 你可以免费 注册 一个本站的账号。
列表为空,暂无数据
我们使用 Cookies 和其他技术来定制您的体验包括您的登录状态等。通过阅读我们的 隐私政策 了解更多相关信息。 单击 接受 或继续使用网站,即表示您同意使用 Cookies 和您的相关数据。
原文