8

押された状態と押されていない状態のセレクターを使用して 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;
}
4

2 に答える 2

10

私はあなたが実際にこれを探していると思います:

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 が描画可能な状態を処理できるようにする必要があるためです (View.refreshDrawableState() メソッドを使用して onTouchEvent() で行われます)。また、かなり複雑なロジックもあります)

onTouchEvent() をオーバーライドしない理由: View.dispatchTouchEvent() には、OnTouchListener がある場合、リスナーにすべてを処理させて true を返すという条件があるためです。したがって、後で何らかの理由で OnTouchListener をボタンに設定すると、onTouchEvent() が呼び出されないため、onTouchEvent() の座標ベースの条件はチェックされません。dispatchTouchEvent() をオーバーライドすることで、一番上でタッチをフィルタリングし、他のすべてのロジックをそのまま残します。ボタンに任意のリスナーを追加すると、通常のボタンと同じように機能しますが、条件が true の場合のみです。

于 2012-06-21T12:19:19.057 に答える
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
}
于 2012-06-22T16:56:58.927 に答える