0

私は自分自身を描画せず、子ビューを持たないこのカスタムボタンを持っています。アプリの起動直後は、次のようになります。

ここに画像の説明を入力

この時点で、ここに投稿するのにどのコードと詳細が関連するかわかりません。事実は、アプリが状態を変更した後、ボタンが留まるVISIBLEか行くかをチェックすることINVISIBLEです。残っていVISIBLEます。呼び出しsetVisibility(View.VISIBLE)た後、画面が再び表示されると、次のようになります。

ここに画像の説明を入力

ボタンをクリックすると、元の背景の寸法で正常に戻ります。

これまでに何を
したか Androidソースまでコードをデバッグしました。
最初 onDraw(); 私はそこに電話をかけるsuper.onDraw();だけで、背景ではなくテキストのみを処理しているように見えます.
2番目 onMeasure(); super.onMeasure();ここでも;と呼ぶだけです。初めて表示する前に数回 (11) 回呼び出され、表示後に 5 回呼び出されsetVisibility()ます。ボタンをクリックしてもまったく呼び出されません。
3 つ目 onTouchEvent()は、ボタンをクリックしたときに呼び出されます。の別の色の背景を設定しACTION_DOWN、元の色の背景を復元しますACTION_UP

@Override
protected void onDraw(Canvas canvas) {
    Log.d(TAG + " " + getText(), "+ onDraw(canvas:" + canvas + ")");
    super.onDraw(canvas);
    Log.d(TAG + " " + getText(), "- onDraw()");
}

@Override
protected void onMeasure(int widthMeasureSpec, int heightMeasureSpec) {
    Log.d(TAG + " " + getText(), String.format("+ onMeasure(widthMeasureSpec:%x, heightMeasureSpec:%x)", widthMeasureSpec,heightMeasureSpec));
    super.onMeasure(widthMeasureSpec, heightMeasureSpec);
    Log.d(TAG + " " + getText(), String.format("- onMeasure(): width=%d, hieght=%d", getMeasuredWidth(), getMeasuredHeight()));
}

@Override
public boolean onTouchEvent(MotionEvent event) {
    Log.d(TAG + " " + getText(), "+ onTouchEvent(event:" + event + ")");
    super.onTouchEvent(event);

    if( clickable ) {
        if( event.getAction() == MotionEvent.ACTION_UP ) {
            setBackgroundDrawable(normalBackground);
            clickUp.soundPlay();
        } else if( event.getAction() == MotionEvent.ACTION_DOWN ) {
            setBackgroundDrawable(pressedBackground);
            clickDown.soundPlay();
        }
    }

    Log.d(TAG + " " + getText(), "- onTouchEvent()");
    return true;
}

/**
 * Sets the MyButton visible if stateFlags matches.<br>
 * @param stateFlags The current app state.<br> 
 */
public void setState(int stateFlags) {
    Log.d(TAG + " " + getText(), "+ setState(stateFlags:" + stateFlags + ")");
    if( state == stateFlags || state == State.NORMAL) {
        setVisibility(View.VISIBLE);
        Log.d(TAG + " " + getText(), "state(" + state + ") VISIBLE before was " + getVisibility());
    } else {
        setVisibility(View.INVISIBLE);
        Log.d(TAG + " " + getText(), "state(" + state + ") INVISIBLE before was " + getVisibility());
    }
    requestLayout();
    Log.d(TAG + " " + getText(), "- setState()");
}

@Override
protected int[] onCreateDrawableState(int extraSpace) {
    Log.d(TAG + " " + getText(), "+ onCreateDrawableState(extraSpace:" + extraSpace + ")");
    Log.d(TAG + " " + getText(), "- onCreateDrawableState()");
    return super.onCreateDrawableState(extraSpace);
}

これらはボタンのログです:

*** Beggining - first show ***
+ onMeasure(widthMeasureSpec:800002b8, heightMeasureSpec:800003aa)
- onMeasure(): width=200, hieght=125
+ onMeasure(widthMeasureSpec:40000099, heightMeasureSpec:800003aa)
- onMeasure(): width=153, hieght=125
+ onMeasure(widthMeasureSpec:800002b8, heightMeasureSpec:80000152)
- onMeasure(): width=200, hieght=125
+ onMeasure(widthMeasureSpec:40000099, heightMeasureSpec:80000152)
- onMeasure(): width=153, hieght=125
+ onMeasure(widthMeasureSpec:800002b8, heightMeasureSpec:80000035)
- onMeasure(): width=200, hieght=53
+ onMeasure(widthMeasureSpec:40000099, heightMeasureSpec:80000035)
- onMeasure(): width=153, hieght=53
+ onSizeChanged(w:153, h:53, oldw:0, oldh:0)
- onSizeChanged()
+ onLayout(changed:true, left:12, top:3, right:165, bottom:56)
- onLayout()
+ onMeasure(widthMeasureSpec:800002b8, heightMeasureSpec:80000035)
- onMeasure(): width=200, hieght=53
+ onMeasure(widthMeasureSpec:40000099, heightMeasureSpec:80000035)
- onMeasure(): width=153, hieght=53
+ onLayout(changed:false, left:12, top:3, right:165, bottom:56)
- onLayout()
+ onDraw(canvas:android.view.Surface$CompatibleCanvas@b3e434b0)
+ onCreateDrawableState(extraSpace:0)
- onCreateDrawableState()
- onDraw()

*** App changes state - button shows wrong ****
+ setState(stateFlags:2)
state(1) VISIBLE before was 0
- setState()
+ onMeasure(widthMeasureSpec:800002b8, heightMeasureSpec:80000152)
- onMeasure(): width=200, hieght=125
+ onMeasure(widthMeasureSpec:800002b8, heightMeasureSpec:80000035)
- onMeasure(): width=200, hieght=53
+ onMeasure(widthMeasureSpec:40000099, heightMeasureSpec:80000035)
- onMeasure(): width=153, hieght=53
+ onLayout(changed:false, left:12, top:3, right:165, bottom:56)
- onLayout()
+ onDraw(canvas:android.view.Surface$CompatibleCanvas@b3e434b0)
- onDraw()

*** I am about to click the button, return to show fine ***
+ onTouchEvent(event:MotionEvent { action=ACTION_DOWN, id[0]=0, x[0]=61.0, y[0]=36.0, toolType[0]=TOOL_TYPE_FINGER, buttonState=0, metaState=0, flags=0x0, edgeFlags=0x0, pointerCount=1, historySize=0, eventTime=2879242, downTime=2879242, deviceId=0, source=0x1002 })
- onTouchEvent()
+ onDraw(canvas:android.view.Surface$CompatibleCanvas@b3e434b0)
+ onCreateDrawableState(extraSpace:0)
- onCreateDrawableState()
- onDraw()
+ onTouchEvent(event:MotionEvent { action=ACTION_UP, id[0]=0, x[0]=61.0, y[0]=36.0, toolType[0]=TOOL_TYPE_FINGER, buttonState=0, metaState=0, flags=0x0, edgeFlags=0x0, pointerCount=1, historySize=0, eventTime=2879342, downTime=2879242, deviceId=0, source=0x1002 })
- onTouchEvent()
+ performClick()
- performClick()
+ onDraw(canvas:android.view.Surface$CompatibleCanvas@b3e434b0)
+ onCreateDrawableState(extraSpace:0)
- onCreateDrawableState()
- onDraw()

詳細は、関連性があると判断された場合にオンデマンドで掲載されます。

4

1 に答える 1

0

バイパスを見つけました! とはいえ、実際に何が問題なのかを理解したいと思います。

バイパスは次のとおりです。

@Override
protected void onDraw(Canvas canvas) {
    // This is a bypass for the problem of partial background redraw.
    // The problem causes are not understood yet.
    // But setting mBackgroundSizeChanged = true; in View causes the next Draw to be OK
    onScrollChanged(0, 0, 0, 0);
    super.onDraw(canvas);
}

究極のバイパス ラインは (View.class) です。

mBackgroundSizeChanged = true;

ただしmBackgroundSizeChanged、派生クラスからはアクセスできず、セッター自体はありません。そこで、セッターに最も近いものを見つけました: onScrollChanged(); それは設定さmBackgroundSizeChanged = trueれ、私の場合はそれだけです。TextView.class および View.class のいくつかのソースコード行をチェックして、あなたのケースで他のことを行うかどうかを確認してください。

古いバイパス (まだ動作しますが、より多くの不要な行を実行します):

ボタンの可視性を変更した直後に、次の行を追加しました。

Drawable d = cb.getBackground();
cb.setBackgroundDrawable(null);
cb.setBackgroundDrawable(d);

そしてそれは問題を解決しました。今ではボタンは背景を保持しています。

どうやってそこにたどり着いたかの説明
これにより、ボタンの背景が強制的にリセットされます。setBackgroundDrawable()そこにあるコードが違いを生んでいることを理解しようとするソースを見ました。最初に背景をnullに設定し、後でリセットしてやり直しを強制する必要があることに最初に気付きました。
さらにデバッグすると、違いが次のように減少しました。

mBackgroundSizeChanged = true; 

の最後のコード行でsetBackgroundDrawable()

于 2013-05-16T14:37:22.897 に答える