2017-06-21 74 views
0

我已經看過了以下內容:的Android不觸發點擊ImageButton的透明度與代碼

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

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

    不過總是空:當設置按鈕,我也button.DrawingCacheEnabled = true;

  • 如果DrawingCacheOnTouchListener試圖建立它,抓住它

對於實例爲空。

  • 嘗試將控件繪製到位圖以測試透明像素。一般來說,這是一個糟糕的主意,但我只是想看看它是否有效。

例如:

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

Nothing abov電子似乎工作。我可能一直在正確的道路上,但錯過了一些關鍵的事情。

+0

你的'OnClickListener' /'OnTouchListener'的代碼是什麼?這是您將代碼忽略透明區域的地方 –

+0

添加了Listener代碼和我的一些嘗試。 –

回答

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

我發現我需要做的是在這個級別不是渲染,因爲在:

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

做正確的事,OnClickListener不管是什麼樣的呢TouchListener調用。