我看过以下内容:
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
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;
如果DrawingCache
在OnTouchListener
尝试构建并抓住它时为空
例如:
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
上述任何内容似乎都无效。我可能已经走上了正确的道路,但却错过了一路上的批评。
答案 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
。