2013-05-13 105 views
0

我有這個自定義按鈕,它沒有繪製自己,並沒有子視圖。應用程序啓動後右它看起來像這樣:自定義按鈕背景被繪製錯誤(有時)

enter image description here

在這一點上,我不知道是什麼代碼和細節可能是相關的張貼在這裏。事實是,應用程序更改狀態後,按鈕會檢查是否要保留VISIBLE或去INVISIBLE。它仍然是VISIBLE。它要求setVisibility(View.VISIBLE),之後,當屏幕再次顯示,它看起來像這樣:

enter image description here

如果我點擊它返回到被罰款,其原有的背景尺寸的按鈕。

我有什麼到目前爲止
我已經調試的代碼下降到Android源完成。
第一個onDraw();我只打電話super.onDraw();,它似乎只處理文本而不處理背景,如果是這樣,它就可以正常工作,因爲文本仍然像以前一樣定位和標註。
第二onMeasure();這裏我也只叫super.onMeasure();;在第一次顯示前稱爲幾次(11次),在setVisibility()後稱爲5次。當我點擊按鈕時,它根本不會被調用。
第三個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:[email protected]) 
+ 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:[email protected]) 
- 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:[email protected]) 
+ 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:[email protected]) 
+ onCreateDrawableState(extraSpace:0) 
- onCreateDrawableState() 
- onDraw() 

更多細節將按需發佈,如果認爲相關。

回答

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不能從派生的類可訪問的,並且它具有沒有setter本身。所以我發現最接近二傳手的是:onScrollChanged();它確實設置了mBackgroundSizeChanged = true,在我的情況下它就是這樣。檢查TextView.class和View.class中的幾個源代碼行,看看你的情況是否有其他的東西。

老旁路(仍然有效,但執行更多不必要的線路):

權後,我改變一個按鈕的可見我添加這些行:

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

它解決了這個問題,現在的按鈕保留其背景。

解釋我是如何到達那裏
這迫使按鈕背景自行復位。我確實看到了setBackgroundDrawable()的來源,試圖瞭解那裏的代碼有什麼不同。我首先注意到,必須先將背景設置爲null,然後重置它以強制重做。
此外調試減小的差異:

mBackgroundSizeChanged = true; 

在持續的setBackgroundDrawable()

代碼行