Android不会触发带有代码

时间:2017-06-21 03:41:33

标签: android xamarin.android xamarin.forms

我看过以下内容:

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

上述任何内容似乎都无效。我可能已经走上了正确的道路,但却错过了一路上的批评。

1 个答案:

答案 0 :(得分:0)

我最终继承了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;
        }
    }
}

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

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

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