一下是控件代码
import android.content.Context;
import android.content.res.TypedArray;
import android.graphics.Canvas;
import android.graphics.Color;
import android.graphics.Paint;
import android.graphics.PixelFormat;
import android.graphics.PorterDuff;
import android.graphics.PorterDuffXfermode;
import android.graphics.Rect;
import android.util.AttributeSet;
import android.util.Log;
import android.view.SurfaceHolder;
import android.view.SurfaceView;
import com.voiceai.voicekey.R;
public class VolumeView extends SurfaceView implements Runnable {
private SurfaceHolder mSurfaceHolder;
private Paint paint;
private int highVolColor = 0xFF4500, midVolColor = 0xFB90F, lowVolColor = 0x32CD32, edgeColor = 0xffffff;
private int volValue, maxVolume;
private float unitSize;
private int width, height, edgeSize;
/***
* 是否在绘制:用于关闭子线程:true则表示一直循环
*/
private boolean isDrawing = true;
public VolumeView(Context context) {
this(context, null);
}
public VolumeView(Context context, AttributeSet attrs) {
this(context, attrs, 0);
}
public VolumeView(Context context, AttributeSet attrs, int defStyleAttr) {
super(context, attrs, defStyleAttr);
init(attrs, defStyleAttr);
initSurface();
}
private void init(AttributeSet attrs, int defStyleAttr) {
paint = new Paint();
TypedArray array = getContext().getTheme().obtainStyledAttributes(attrs, R.styleable
.VolumeBar, defStyleAttr, 0);
int n = array.getIndexCount();
for (int i = 0; i < n; i++) {
int attr = array.getIndex(i);
switch (attr) {
case R.styleable.VolumeBar_HighVolumeColor:
highVolColor = array.getColor(attr, 0xFF4500);
break;
case R.styleable.VolumeBar_LowVolumeColor:
lowVolColor = array.getColor(attr, 0x32CD32);
break;
case R.styleable.VolumeBar_MidVolumeColor:
midVolColor = array.getColor(attr, 0xFB90F);
break;
case R.styleable.VolumeBar_VolumeValue:
volValue = array.getInt(attr, 50);
break;
case R.styleable.VolumeBar_MaxVolume:
maxVolume = array.getInt(attr, 100);
break;
case R.styleable.VolumeBar_EdgeColor:
edgeColor = array.getColor(attr, 0xffffff);
break;
case R.styleable.VolumeBar_EdgeSize:
edgeSize = array.getDimensionPixelSize(attr, 0);
break;
}
}
}
private void initSurface() {
/**通过holder去申请绘图表面的画布,surfaceview其实draw()或dispathDraw()都只是一块默认的黑色区域,并不是用作宿主
* 真正要做的事情由开发者自行绘制,绘制之前就是通过holder获取一块内存区域的画布,
* 然后可在UI线程或工作线程在这个画布上进行绘制所需要的视图,最后还是通过holder提交这个画布就可以显示
*
*
* 生命周期自动和activity一起
* */
mSurfaceHolder = getHolder();
setZOrderOnTop(true);
//回调
mSurfaceHolder.addCallback(new SurfaceHolder.Callback() {
/***
* surfaceview的绘图表面(就是activity宿主创建一个透明的表面用于surfaceView绘制)被创建时执行
* 在updateWindow()创建宿主(activity的窗口)的绘图表面时会回调,虽然surfaceView是独立于一个线程但还是离不开宿主窗口,
* 最后还是要粘贴到window中
*
* surfaceCreated方法,是当SurfaceView被显示时会调用的方法,所以你需要再这边开启绘制的线 程
*
* @param holder
*/
@Override
public void surfaceCreated(SurfaceHolder holder) {
isDrawing = true;
new Thread(VolumeView.this).start();
Log.e("VolumeView", "SurfaceHolder生命周期surfaceCreated");
}
/**
* 创建、更新会认为发生变化也会回调这个方法
* @param holder
* @param format
* @param width
* @param height
*/
@Override
public void surfaceChanged(SurfaceHolder holder, int format, int width, int height) {
Log.e("VolumeView", "SurfaceHolder生命周期surfaceChanged");
}
/***
*surfaceDestroyed方法是当SurfaceView被隐藏会销毁时调用的方法,在这里你可以关闭绘制的线程
* @param holder
*/
@Override
public void surfaceDestroyed(SurfaceHolder holder) {
isDrawing = false;
Log.e("VolumeView", "SurfaceHolder生命周期surfaceDestroyed");
}
});
}
public void setDrawing(boolean drawing) {
isDrawing = drawing;
}
@Override
protected void onMeasure(int widthMeasureSpec, int heightMeasureSpec) {
super.onMeasure(widthMeasureSpec, heightMeasureSpec);
height = measureHeight(heightMeasureSpec);
width = measureWidth(widthMeasureSpec);
setMeasuredDimension(width, height);
}
private int measureHeight(int measureSpec) {
int specMode = MeasureSpec.getMode(measureSpec);
int specSize = MeasureSpec.getSize(measureSpec);
// Default size if no limits are specified.
int result = 500;
if (specMode == MeasureSpec.AT_MOST) {
result = specSize;
} else if (specMode == MeasureSpec.EXACTLY) {
result = specSize;
}
return result;
}
private int measureWidth(int measureSpec) {
int specMode = MeasureSpec.getMode(measureSpec);
int specSize = MeasureSpec.getSize(measureSpec);
// Default size if no limits are specified.
int result = 500;
if (specMode == MeasureSpec.AT_MOST) {
result = specSize;
} else if (specMode == MeasureSpec.EXACTLY) {
result = specSize;
}
return result;
}
@Override
public void run() {
while (isDrawing) {
draw();
}
}
//设置音量
public void setVolValue(int value) {
if (value > maxVolume) {
value = maxVolume;
}
this.volValue = value;
}
/***
* 注意这个是在子线程中绘制的,surface支持子线程更新ui,所以
*/
private void draw() {
Canvas canvas = null;
//给画布加锁,防止线程安全,防止该内存区域被其他线程公用
try {
synchronized (mSurfaceHolder) {
canvas = mSurfaceHolder.lockCanvas();
if (null != canvas) {
//清屏操作或者设置背景
onDrawPic(canvas);
Thread.sleep(50);
}
}
} catch (Exception e){
Log.e("VolumeView", "VolumeView异常:"+e.getMessage());
}finally {
//提交显示视图并解锁,防止长期占用此内存
if (null != mSurfaceHolder) mSurfaceHolder.unlockCanvasAndPost(canvas);
}
}
protected void onDrawPic(Canvas canvas) {
final Rect rect = new Rect(0, 0, this.width, this.width);
paint.setAntiAlias(true);
canvas.drawARGB(0, 0, 0, 0);
unitSize = (float) (width - 2 * edgeSize) / (float) maxVolume;
int drawSize = Math.round(volValue * unitSize);
//颜色渐变原则:当音量小于50时,R值递增/递减(根据指定的low、mid颜色值来判断),G值不变,B值递增/递减,
//当音量大于50时,R值不变,G值递减/递增(),B值递增/递减
float redColorUnitFirstStage = (float) (((midVolColor & 0xff0000) - (lowVolColor &
0xff0000)) >> 16) / 70;
float greenColorUnitFirstStage = (float) (((midVolColor & 0x00ff00) - (lowVolColor &
0x00ff00)) >> 8) / 70;
float blueColorUnitFirstStage = (float) (((midVolColor & 0x0000ff) - (lowVolColor &
0x0000ff))) / 70;
float redColorUnitSecondStage = (float) (((highVolColor & 0xff0000) - (midVolColor &
0xff0000)) >> 16) / 30;
float greenColorUnitSecondStage = (float) (((highVolColor & 0x00ff00) - (midVolColor &
0x00ff00)) >> 8) / 30;
float blueColorUnitSecondStage = (float) (((highVolColor & 0x0000ff) - (midVolColor &
0x0000ff))) / 30;
int red = (lowVolColor & 0xff0000) >> 16;
int green = (lowVolColor & 0x00ff00) >> 8;
int blue = (lowVolColor & 0x0000ff);
//绘制有颜色区域
for (int i = 0; i < volValue; i++) {
if (i <= 70) {
//当音量小于50时,更新颜色的R值,递增/递减。
red = red + (int) redColorUnitFirstStage;
green = green + (int) greenColorUnitFirstStage;
blue = blue + (int) blueColorUnitFirstStage;
int colorValue = Color.rgb(red, green, blue);
paint.setColor(colorValue);
paint.setXfermode(new PorterDuffXfermode(PorterDuff.Mode.SRC_IN));
canvas.drawRect(i * unitSize, edgeSize, (i + 1) * unitSize + 1, height - edgeSize, paint);
} else {
//当音量小于50时,更新颜色的G值,递减。
red = red + (int) redColorUnitSecondStage;
green = green + (int) greenColorUnitSecondStage;
blue = blue + (int) blueColorUnitSecondStage;
int colorValue = Color.rgb(red, green, blue);
paint.setColor(colorValue);
paint.setXfermode(new PorterDuffXfermode(PorterDuff.Mode.SRC_IN));
canvas.drawRect(i * unitSize, edgeSize, (i + 1) * unitSize + 1, height, paint);
}
}
//绘制边框
paint.setColor(edgeColor);
paint.setXfermode(new PorterDuffXfermode(PorterDuff.Mode.SRC_IN));
//绘制左边框
canvas.drawRect(0, 0, edgeSize, height, paint);
//绘制上边框
canvas.drawRect(0, 0, width, edgeSize, paint);
//绘制下边框
canvas.drawRect(0, height - edgeSize, width, height, paint);
//绘制有边框
canvas.drawRect(width - edgeSize, 0, width, height, paint);
//绘制第一个刻度
canvas.drawRect(width / 4, height - 10 * edgeSize, width / 4 + 2 * edgeSize, height, paint);
//绘制第二个刻度
canvas.drawRect(width * 4 / 5, height - 10 * edgeSize, width * 4 / 5 + 2 * edgeSize, height, paint);
}
}
在activity调用了 vVolumeBar.setVolValue(20);然后其他手机都ok就是小米,初次进去就会显示默认黑色背景,再次回到该页面显示效果正常