2012-06-18 42 views
8

我创建了一个ImageButton,其中包含一个用于按下和未按下状态的选择器,并且这种方式正常工作。用不同的点击状态创建不规则形状的ImageButton

但按钮有不规则的形状,我只希望它可以点击下面的矩形图像是不透明的地方。

因此,我实现了一个OnTouchListener,它根据位图的像素值检查触摸事件的坐标(如第一个答案中所述:link)。 根据确定按钮是否被按下的逻辑,这适用,但现在按钮的图像不再变为按下的图像。

以下是我有:

选择XML文件:

<?xml version="1.0" encoding="utf-8"?> 
<selector xmlns:android="http://schemas.android.com/apk/res/android" > 
    <item android:state_pressed="true" android:drawable="@drawable/button_start_call_pressed" /> 
    <item android:drawable="@drawable/button_start_call_normal" /> 
</selector> 

部分透明的ImageButton布局:

<ImageButton 
    android:id="@+id/dashboardStartCallButton" 
    android:background="@null" 
    android:layout_width="wrap_content" 
    android:layout_height="wrap_content" 
    android:src="@drawable/start_call_button_selector" 
    /> 

在活动:

public void onCreate(Bundle savedInstance) { 
    super.onCreate(savedInstance); 
    ... 
    ImageButton startCallButton = (ImageButton) this.findViewById(R.id.dashboardStartCallButton); 
    startCallButton.setOnTouchListener(new OnTouchListener() { 
     @Override 
     public boolean onTouch(View v, MotionEvent event) { 
      return OnStartCallButtonTouch(v,event); 
     }   
    }); 
} 


public boolean OnStartCallButtonTouch(View v, MotionEvent event) 
{ 
    Bitmap TheBitmap = BitmapFactory.decodeResource(getResources(), R.drawable.button_start_call_normal); 
    int eventPadTouch = event.getAction(); 
    int iX = (int) event.getX(); 
    int iY = (int) event.getY(); 
    switch (eventPadTouch) { 
     case MotionEvent.ACTION_DOWN: 
      if (iX>=0 & iY>=0 & iX<TheBitmap.getWidth() & iY<TheBitmap.getHeight()) {     
       if (TheBitmap.getPixel(iX,iY)!=0) { 
        onStartCallButtonClicked(v); 
        return false; 
       } 
      } 
    }   
    return true; 
} 
+0

为什么不'返回OnStartCallButtonTouch(v,event)|| startCallButton.onTouch()'? –

回答

10

我觉得你“再实际上是寻找这样的:

View.dispatchTouchEvent(...)

您需要在您的自定义按钮,返回如果点不在所需的区域覆盖此方法。我建议你去了解它是这样的:

public static class MyButton extends ImageButton { 
    ... 
    @Override 
    public boolean dispatchTouchEvent(MotionEvent event) { 
     int iX = (int) event.getX(); 
     int iY = (int) event.getY(); 
     // TODO Or use a more sophisticated, pixel value-based condition 
     if (!(iX>=0 & iY>=0 & iX<TheBitmap.getWidth() & iY<TheBitmap.getHeight())) { 
      return false; 
     } 
     return super.dispatchTouchEvent(event) 
    } 
} 

为什么不使用OnTouchListener:因为你需要通过打电话View.onTouchEvent()(在super.dispatchTouchEvent(事件)完成),让查看处理绘制状态(它使用View.refreshDrawableState()方法中的onTouchEvent()完成,也有有一些相当复杂的逻辑)

为什么不能覆盖的onTouchEvent():由于View.dispatchTouchEvent()有如果存在OnTouchListener,则让侦听器处理所有事情并返回true。因此,如果稍后由于某种原因将OnTouchListener设置为按钮,则onTouchEvent()中基于坐标的条件将不会被检查,因为onTouchEvent()永远不会被调用。通过覆盖dispatchTouchEvent()你在最高层过滤触摸并保留所有其他逻辑的地方 - 你可以添加任何侦听器的按钮,他们将工作,因为他们会为正常的按钮,但只有当你的情况是真实的。

+0

嘿,最近怎么样?如果答案为你做了,请考虑接受它。 –

1

我认为你需要修改你的碰撞检测是否触摸是否在你的按钮内。使用以下方法。

public boolean OnStartCallButtonTouch(View v, MotionEvent event) 
{ 
    Bitmap TheBitmap = BitmapFactory.decodeResource(getResources(), R.drawable.button_start_call_normal); 
    int eventPadTouch = event.getAction(); 
    int iX = (int) event.getX(); 
    int iY = (int) event.getY(); 

    int[] location = new int[2]; 
    v.getLocationOnScreen(location); 

    int viewX = location[0]; 
    int viewY = location[1]; 


    switch (eventPadTouch) { 
     case MotionEvent.ACTION_DOWN: 
      if (iX>=viewX & iY>=viewY & iX<=(viewX+TheBitmap.getWidth()) & iY<=(viewY+TheBitmap.getHeight())) {     
       if (TheBitmap.getPixel(iX,iY)!=0) { 
        onStartCallButtonClicked(v); 
        showPressedState(); 
        return false; 
       } 
      } 
      break; 
     case MotionEvent.ACTION_UP: 
     case MotionEvent.ACTION_CANCEL: 
      showNormalState(); 
      break; 
    }   
    return true; 
} 

private void showNormalState() { 
    // set your button background drawable to show normal state 
} 

private void showPressedState() { 
    // set your button background drawable to show pressed state 
}