2013-05-13 3 views
0

У меня есть эта пользовательская кнопка, которая не рисует себя и не имеет дочерних видов. Сразу же после запуска приложения это выглядит следующим образом:Пользовательский фон кнопки рисуется неправильно (иногда)

enter image description here

На данный момент я не знаю, какой код и детали могут быть релевантны для размещения здесь. Дело в том, что после изменения настроек приложения кнопка проверяет, стоит ли оставаться VISIBLE или идти INVISIBLE. Осталось VISIBLE. Он призывает setVisibility(View.VISIBLE) и после этого, когда экран снова показывает, это выглядит следующим образом:

enter image description here

Если я нажимаю на кнопку она возвращается, чтобы быть в порядке с его первоначальными размерами фона.

Что я сделал до сих пор
Я отлажена код вниз андроид источников.
ПервыйonDraw(); Я только звоню там super.onDraw(); и, похоже, имеет дело только с текстом, а не с фоном, и если да, то он работает нормально, так как текст по-прежнему позиционируется и измеряется по-прежнему.
ВторойonMeasure(); здесь тоже я звоню только super.onMeasure();; он называется несколько (11) раз перед первым показом и называется 5 раз после setVisibility(); он не называется вообще, когда я нажимаю кнопку.
Третий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 не доступен из производных классов, и он не имеет сеттер по себе. Поэтому я нашел ближайшую вещь для сеттера: onScrollChanged(); он устанавливает mBackgroundSizeChanged = true, и в моем случае это все, что он делает. Проверьте несколько строк исходного кода в TextView.class и View.class, чтобы убедиться, что в вашем случае это делает другие вещи.

Старого Bypass (по-прежнему работает, но выполняет более ненужные линии):

Сразу после я изменить видимость кнопки я добавили эти строки:

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

И решить эту проблему, теперь кнопку сохраняет свой фон.

Объяснение, как я получил там
Это заставляет фон кнопки, чтобы сбросить себя. Я посмотрел на источник setBackgroundDrawable(), пытаясь понять, какой код там имеет значение. Сначала я заметил, что сначала нужно установить фон в нуль, а затем снова установить его, чтобы принудительно выполнить повтор.
Далее отлаживать сократили разницу в:

mBackgroundSizeChanged = true; 

В длится код строки setBackgroundDrawable()