解决StateButton适配的问题

定制一个以图片为背景的按钮,并且在按下时设置其透明度为原来的35%,之前我们是这么实现的:

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
package com.kingtime.xingpeng.widget;
import android.content.Context;
import android.graphics.Bitmap;
import android.graphics.Canvas;
import android.graphics.drawable.BitmapDrawable;
import android.graphics.drawable.Drawable;
import android.graphics.drawable.StateListDrawable;
import android.util.AttributeSet;
import android.widget.Button;
/**
* Created by xingpeng on 15-7-31.
*/
public class StateButton extends Button{
private boolean mHasSetBackground = false;
private Drawable mBackground = null;
public StateButton(Context context) {
super(context);
}
public StateButton(Context context, AttributeSet attrs) {
super(context, attrs);
}
public StateButton(Context context, AttributeSet attrs, int defStyleAttr) {
super(context, attrs, defStyleAttr);
}
@Override
protected void onLayout(boolean changed, int left, int top, int right, int bottom) {
if(!mHasSetBackground) {
resetBackground();
mHasSetBackground = true;
}
super.onLayout(changed, left, top, right, bottom);
}
//设置按住时透明度背景为35%
private void resetBackground() {
Drawable normalDrawable = this.getBackground();
int width = this.getWidth();
int height = this.getHeight();
Bitmap pressBitmap = Bitmap.createBitmap(width, height, Bitmap.Config.ARGB_8888);
Canvas canvas = new Canvas();
canvas.setBitmap(pressBitmap);
BitmapDrawable pressDrawable = new BitmapDrawable(null, pressBitmap);
normalDrawable.setBounds(0, 0, width , height);
normalDrawable.setAlpha(81);
normalDrawable.draw(canvas);
StateListDrawable stateListDrawable = new StateListDrawable();
stateListDrawable.addState(new int[]{android.R.attr.state_pressed}, pressDrawable);
stateListDrawable.addState(new int[]{android.R.attr.state_focused}, pressDrawable);
stateListDrawable.addState(new int[]{}, normalDrawable);
mBackground = stateListDrawable;
mBackground.setCallback(this);
this.setBackgroundDrawable(mBackground);
}
}

可以直接在布局文件里面用,并且设定一张背景图片

1
2
3
4
5
6
7
8
9
10
11
12
13
14
<LinearLayout xmlns:android="http://schemas.android.com/apk/res/android"
android:layout_width="match_parent"
android:layout_height="match_parent"
android:paddingLeft="@dimen/activity_horizontal_margin"
android:paddingRight="@dimen/activity_horizontal_margin"
android:paddingTop="@dimen/activity_vertical_margin"
android:paddingBottom="@dimen/activity_vertical_margin"
android:orientation="vertical">
<com.kingtime.xingpeng.widget.StateButton
android:layout_width="150dp"
android:layout_height="150dp"
android:background="@drawable/icon_camera"/>
</LinearLayout>

界面预览:

StateButton

很长的一段时间里,这个是没有出现问题的,但是最近在5.0的系统上发现并不能用,按钮一直是灰色的,如下:

StateButton

查找了很久这个问题,发现是这一句出现了问题normalDrawable.setAlpha(81),本来在这里已经改变了正常图片的透明度,而后面依然将其设为正常的图片背景stateListDrawable.addState(new int[]{}, normalDrawable);,在5.0以上跟以下的区别,可能是对象的引用出现了问题,我们有两种方法解决这个问题.

第一种是在5.0以上的系统单独设置按下时背景的透明度

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
//设置按住时透明度背景为35%
private void resetBackground() {
Drawable normalDrawable = this.getBackground();
int width = this.getWidth();
int height = this.getHeight();
Bitmap pressBitmap = Bitmap.createBitmap(width, height, Bitmap.Config.ARGB_8888);
Canvas canvas = new Canvas();
canvas.setBitmap(pressBitmap);
BitmapDrawable pressDrawable = new BitmapDrawable(null, pressBitmap);
normalDrawable.setBounds(0, 0, width, height);
if(Build.VERSION.SDK_INT > Build.VERSION_CODES.KITKAT) {
pressDrawable.setAlpha(81);
} else {
normalDrawable.setAlpha(81);
}
normalDrawable.draw(canvas);
StateListDrawable stateListDrawable = new StateListDrawable();
stateListDrawable.addState(new int[]{android.R.attr.state_pressed}, pressDrawable);
stateListDrawable.addState(new int[]{android.R.attr.state_focused}, pressDrawable);
stateListDrawable.addState(new int[]{}, normalDrawable);
mBackground = stateListDrawable;
mBackground.setCallback(this);
this.setBackgroundDrawable(mBackground);
}

这种可以解决问题,但是在5.0以下的系统也用这种方法会出现按钮按下时变为空白的情况.

第二种是单独生成一个Drawable,避免用其引用

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
package com.kingtime.xingpeng.widget;
import android.content.Context;
import android.graphics.Bitmap;
import android.graphics.Canvas;
import android.graphics.drawable.BitmapDrawable;
import android.graphics.drawable.Drawable;
import android.graphics.drawable.StateListDrawable;
import android.util.AttributeSet;
import android.widget.Button;
import com.kingtime.xingpeng.applicationdemo.R;
/**
* Created by gugutian on 15-7-31.
*/
public class StateButton extends Button{
private boolean mHasSetBackground = false;
private Drawable mBackground = null;
public StateButton(Context context) {
super(context);
}
public StateButton(Context context, AttributeSet attrs) {
super(context, attrs);
}
public StateButton(Context context, AttributeSet attrs, int defStyleAttr) {
super(context, attrs, defStyleAttr);
}
@Override
protected void onLayout(boolean changed, int left, int top, int right, int bottom) {
if(!mHasSetBackground) {
resetBackground();
mHasSetBackground = true;
}
super.onLayout(changed, left, top, right, bottom);
}
//设置按住时透明度背景为35%
private void resetBackground() {
Drawable normalDrawable = generateNewDrawable(this.getBackground());
int width = this.getWidth();
int height = this.getHeight();
Bitmap pressBitmap = Bitmap.createBitmap(width, height, Bitmap.Config.ARGB_8888);
Canvas canvas = new Canvas();
canvas.setBitmap(pressBitmap);
BitmapDrawable pressDrawable = new BitmapDrawable(null, pressBitmap);
normalDrawable.setBounds(0, 0, width , height);
normalDrawable.setAlpha(81);
normalDrawable.draw(canvas);
StateListDrawable stateListDrawable = new StateListDrawable();
stateListDrawable.addState(new int[]{android.R.attr.state_pressed}, pressDrawable);
stateListDrawable.addState(new int[]{android.R.attr.state_focused}, pressDrawable);
stateListDrawable.addState(new int[]{}, this.getBackground());
mBackground = stateListDrawable;
mBackground.setCallback(this);
this.setBackgroundDrawable(mBackground);
}
private Drawable generateNewDrawable(Drawable oldDrawable) {
int width = this.getWidth();
int height = this.getHeight();
Bitmap bitmap = Bitmap.createBitmap(width, height, Bitmap.Config.ARGB_8888);
Canvas canvas = new Canvas();
canvas.setBitmap(bitmap);
BitmapDrawable drawable = new BitmapDrawable(null, bitmap);
oldDrawable.setBounds(0, 0, width, height);
oldDrawable.draw(canvas);
return drawable;
}
}

这样又能愉快的工作了.

StateButton