【问题标题】:Android do not trigger click for ImageButton with transparency with codeAndroid不会触发带有透明度的ImageButton点击代码
【发布时间】:2017-06-21 03:41:32
【问题描述】:

我看过以下内容:

imagebutton with @null background (transparent)

How to prevent onClick method on transparent portion of a PNG-loaded ImageView

还有无数其他人,所以我一定很想念它。

我有一个ImageButton。按钮表示的图像是具有透明度的 PNG。一切都显示得很好。但是,当我单击透明度上的按钮时,会触发单击事件。这根本不是我想要的。

我正在寻找一个解决方案,它可能很明显,但我错过了它,透明度不计入按钮的点击测试。

我想在代码中完成这一切,而不是在 xml 中。

到目前为止,我正在像这样初始化我的ImageButton。这一切都在 Xamarin.Android 中,但这不重要。语法将是 C# 而不是 Java。

// make the states:
var states = new StateListDrawable();
states.AddState(new int[] { -Android.Resource.Attribute.StateEnabled }, new BitmapDrawable(Context.Resources, disabledImage));
states.AddState(StateSet.WildCard.ToArray(), drawable);

// setup the button
var button = new Android.Widget.ImageButton(Context);

button.SetBackgroundColor(Android.Graphics.Color.Transparent);
button.SetPadding(0, 0, 0, 0);
button.SetImageDrawable(states);

// I am using this in a custom renderer, so these are my 
// click handlers. I don't think that matters, but maybe it does?
button.SetOnClickListener(ButtonClickListener.Instance.Value);
button.SetOnTouchListener(ButtonTouchListener.Instance.Value);
button.Tag = this;

再次,一切都完美显示,唯一的事情是在图像的透明部分触发点击,这是我不想要的。

编辑

我的点击/触摸侦听器代码。这是从Xamarin.Forms 中的平台按钮渲染中提取的

https://github.com/xamarin/Xamarin.Forms/blob/master/Xamarin.Forms.Platform.Android/Renderers/ButtonRenderer.cs#L251-L284

class ButtonClickListener : Object, IOnClickListener
{
    public static readonly Lazy<ButtonClickListener> Instance = new Lazy<ButtonClickListener>(() => new ButtonClickListener());

    public void OnClick(AView v)
    {
        var renderer = v.Tag as MyButtonRenderer;

        if (renderer != null)
            ((IButtonController)renderer.Element).SendClicked();
    }
}

class ButtonTouchListener : Object, IOnTouchListener
{
    public static readonly Lazy<ButtonTouchListener> Instance = new Lazy<ButtonTouchListener>(() => new ButtonTouchListener());

    public bool OnTouch(AView v, AMotionEvent e)
    {
        var renderer = v.Tag as MyButtonRenderer;

        if (renderer != null)
        {
            var buttonController = renderer.Element as IButtonController;
            if (e.Action == AMotionEventActions.Down)
            {
                buttonController?.SendPressed();
            }
            else if (e.Action == AMotionEventActions.Up)
            {
                buttonController?.SendReleased();
            }
        }
        return false;
    }
}

我尝试过的事情:在OnTouchListener

  • 尝试获取renderer.Control.DrawingCache,以便获取位图并测试透明像素。 DrawingCache 总是返回null。设置按钮的时候,我也button.DrawingCacheEnabled = true;

  • 如果DrawingCacheOnTouchListener 中为空,则尝试构建并抓取它

例如:

if (cache == null)
{
    renderer.Control.BuildDrawingCache();
    cache = renderer.Control.DrawingCache;
}

始终为空。

  • 尝试将控件绘制到位图以测试透明像素。一般来说,这是一个坏主意,但我只是想看看它是否有效。

例如:

Bitmap bitmap = Bitmap.CreateBitmap(renderer.Control.Width, renderer.Control.Height, Bitmap.Config.Argb8888);
Canvas canvas = new Canvas(bitmap);
renderer.Control.Draw(canvas);

在上述情况下,一旦我有一个或认为我有一个Bitmap 表示,我会像这样检查像素:

int color = bitmap.GetPixel((int)e.GetX(), (int)e.GetY());
if (color == Android.Graphics.Color.Transparent)
    return false;

上述尝试是为了尝试这种方法: https://stackoverflow.com/a/19566795/1060314

上面似乎没有任何效果。我可能一直走在正确的道路上,但只是错过了一些重要的事情。

【问题讨论】:

  • 您的OnClickListener/OnTouchListener 的代码是什么?这是您可以放置​​代码以忽略透明区域的地方
  • 添加了监听器代码和我的一些尝试。

标签: android xamarin.android xamarin.forms


【解决方案1】:

我最终继承了ImageButton,这成功了。

using System;
using Android.Content;
using Android.Graphics;
using Android.Graphics.Drawables;
using Android.Util;
using Android.Widget;
using AMotionEvent = Android.Views.MotionEvent;

namespace MyProject.Droid.Renderers
{
    public class MDImageButton : Android.Widget.ImageButton
    {
        public MDImageButton(Context context) : this(context, null)
        { }
        public MDImageButton(Context context, IAttributeSet attrs) : this(context, attrs, Android.Resource.Attribute.ImageButtonStyle)
        { }


        public MDImageButton(Context context, IAttributeSet attrs, int defStyleAttr) : this(context, attrs, defStyleAttr, 0)
        { }

        public MDImageButton(Context context, IAttributeSet attrs, int defStyleAttr, int defStyleRes) : base(context, attrs, defStyleAttr, defStyleRes)
        {
            Focusable = true;
        }

        public override bool OnTouchEvent(AMotionEvent e)
        {
            var view = (ImageView)this;
            var currentState = ((StateListDrawable)this.Drawable).Current;

            if (currentState is BitmapDrawable)
            {
                var x = (int)e.GetX();
                var y = (int)e.GetY();

                if (isPixelTransparent(x, y))
                    return false;
                else
                    return base.OnTouchEvent(e);
            }

            return base.OnTouchEvent(e);
        }

        private bool isPixelTransparent(int x, int y)
        {
            var currentState = ((StateListDrawable)this.Drawable).Current;
            Bitmap bmp = ((BitmapDrawable)currentState).Bitmap;

            int color = Android.Graphics.Color.Transparent;

            try
            {
                color = bmp.GetPixel(x, y);
            }
            catch (Exception e)
            {
                // x or y exceed the bitmap's bounds.
                // Reverts the View's internal state from a previously set "pressed" state.
                Pressed = false;
            }

            // Ignores touches on transparent background.
            if (color == Android.Graphics.Color.Transparent)
                return true;
            else
                return false;
        }
    }
}

我发现我需要在这个级别而不是渲染器上做,因为当:

button.SetOnClickListener(ButtonClickListener.Instance.Value);
button.SetOnTouchListener(ButtonTouchListener.Instance.Value);

做正确的事,无论TouchListener 做什么,都会调用OnClickListener

【讨论】:

    猜你喜欢
    • 2013-05-07
    • 2012-06-07
    • 1970-01-01
    • 2012-10-01
    • 2011-08-05
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    相关资源
    最近更新 更多