我创建了一个带有按下和非按下状态选择器的ImageButton,这很好。
但按钮的形状不规则,我只希望它可以在基础矩形图像不透明的地方点击。
所以我实现了一个OnTouchListener,它根据Bitmap的像素值检查触摸事件的坐标(如第一个答案中所述:link)。 就判断是否按下按钮的逻辑而言,这是有效的,但现在按钮的图像不再变为按下的图像。
这就是我所拥有的:
Selector 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 :(得分:10)
我认为你实际上在寻找这个:
如果点不在所需区域,则需要在自定义按钮中覆盖此方法以返回 false 。我建议你这样做:
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(event)中完成)让View处理可绘制状态(它在onTouchEvent中完成) ()使用View.refreshDrawableState()方法,还有一些更复杂的逻辑)
为什么不覆盖onTouchEvent():因为在View.dispatchTouchEvent()中有一个条件,如果有一个OnTouchListener,那么让监听器处理所有内容并返回true。因此,如果稍后因为某种原因将OnTouchListener设置为按钮,则不会检查onTouchEvent()中基于坐标的条件,因为onTouchEvent()永远不会被调用。通过重写dispatchTouchEvent(),您可以在最顶部过滤触摸并保留所有其他逻辑 - 您可以向按钮添加任何侦听器,它们将像普通按钮一样工作,但仅在您的条件为真时才会工作。
答案 1 :(得分: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
}