自定义按钮的背景正在绘制错误的(有时) [英] Custom Button background is being drawn wrong (sometimes)

查看:315
本文介绍了自定义按钮的背景正在绘制错误的(有时)的处理方法,对大家解决问题具有一定的参考价值,需要的朋友们下面随着小编来一起学习吧!

问题描述

我有这样的自定义按钮,它不画自己,也没有孩子的意见。应用程序启动之后,它看起来是这样的:

I have this custom button, which does not draw himself and has no child views. Right after app launch it looks like this:

在这一点上,我不知道是什么code和细节可能是相关张贴在这里。事实是经过程序状态改变按钮检查是否留可见或进入看不见。它仍然可见。它调用 setVisibility(View.VISIBLE),之后,当屏幕再次出现,它看起来像这样:

At this point I don't know what code and details might be relevant for posting here. The fact is after the app changes state the button checks whether to stay VISIBLE or go INVISIBLE. It remains VISIBLE. It calls setVisibility(View.VISIBLE) and after that, when the screen shows again, it looks like this:

如果我点击它返回到被罚款,其原有的背景尺寸的按钮。

If I click the button it returns to be fine with its original background dimensions.

我做了什么至今结果
我已经调试了code到Android的源。结果
第一 的onDraw();我只叫有 super.onDraw(); ,它似乎只处理文本,而不是背景,如果是这样,它的工作原理确定,因为文本仍定位和尺寸如前。结果
onMeasure();这里也是我只能叫 super.onMeasure(); ;它显示在第一次调用之前数(11)倍,它是在 setVisibility()所谓的5倍;它完全不叫当我点击按钮。结果
第三 onTouchEvent(),堪称当我点击按钮。它为 ACTION_DOWN 不同颜色的背景,并恢复对 ACTION_UP

What have I done so far
I have debugged the code down to android sources.
First onDraw(); I only call there super.onDraw(); and it seems to deal only with the text and not the background, and if so, it works OK, since the text is still positioned and dimensioned as before.
Second onMeasure(); here too I only call super.onMeasure();; it is called several (11) times before showing for the first time and it is called 5 times after setVisibility(); it is not called at all when I click the button.
Third onTouchEvent(), called when I click the button. It sets a different color background for ACTION_DOWN and restores the original color background on 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);
}

这些都是日志按钮:

these are the logs for the button:

*** 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()

更多细节将按需发布,如果认为相关的。

More details will be posted on demand, if deemed relevant.

推荐答案

我发现了一个旁路!虽然我很想了解什么是真正的问题。

I found a bypass!, though I would like very much to understand what is really the problem.

旁路是:

@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):

The ultimate bypass line is (View.class):

mBackgroundSizeChanged = true;

mBackgroundSizeChanged 是不是从派生类访问,并且它没有制定者本身。于是我找到了最接近的setter有: onScrollChanged();它集 mBackgroundSizeChanged = TRUE 和我的情况是它所做的一切。检查TextView.class和View.class少数源$ C ​​$ C线,看看你的情况确实其他的东西。

But mBackgroundSizeChanged is not accessible from derived classes, and it has no setter per se. So I found the closest thing to a setter there is: onScrollChanged(); it does set mBackgroundSizeChanged = true and in my case is all it does. Check the few source code lines in TextView.class and View.class to see if in your case it does other stuff.

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

Old Bypass (still works but executes more unecessary lines):

右键后,我改变一个按钮的可见我添加这些行:

Right after I change the visibility of a button I added these lines:

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

和它解决了这个问题,现在该按钮保留其背景。

And it solved the problem, now the button retains its background.

解释我是如何到达那里结果
这迫使按钮背景自行复位。我也看 setBackgroundDrawable源()试图了解code的存在使得差异。我第一次注意到了将背景设置第一为null,重置后强制重做。结果
进一步调试减少了差异:

Explanation how I got there
This forces the button background to reset itself. I did look at the source of setBackgroundDrawable() trying to understand what code in there is making the difference. I first noticed that had to set the background to null first and reset it afterwards to force a redo.
Further debug reduced the difference to:

mBackgroundSizeChanged = true; 

在持续 setBackgroundDrawable的code线()

这篇关于自定义按钮的背景正在绘制错误的(有时)的文章就介绍到这了,希望我们推荐的答案对大家有所帮助,也希望大家多多支持IT屋!

查看全文
登录 关闭
扫码关注1秒登录
发送“验证码”获取 | 15天全站免登陆