【问题标题】:Creating irregular shaped ImageButton with different click states创建具有不同点击状态的不规则形状的 ImageButton
【发布时间】:2012-06-20 07:20:35
【问题描述】:

我创建了一个带有用于按下和非按下状态选择器的 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;
}

【问题讨论】:

  • 为什么不return OnStartCallButtonTouch(v,event) || startCallButton.onTouch()?

标签: android touch transparent imagebutton clickable


【解决方案1】:

我认为您实际上正在寻找这个:

View.dispatchTouchEvent(...)

如果点不在所需区域,您需要在自定义按钮中覆盖此方法以返回 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(),您可以在最顶部过滤触摸并保留所有其他逻辑 - 您可以向按钮添加任何侦听器,它们将像普通按钮一样工作,但前提是您的条件为真。

【讨论】:

  • 嘿,怎么样?如果答案对你有用,请考虑接受它。
【解决方案2】:

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

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
}

【讨论】:

    猜你喜欢
    • 2017-11-02
    • 1970-01-01
    • 2015-02-01
    • 2013-02-02
    • 2015-11-06
    • 2012-09-02
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    相关资源
    最近更新 更多