今天我们要实现一个上图中音量调节的效果。主要有两种实现方式自定义RatingBar和自定义View。
自定义RatingBar
volume_rating.xml
main.xml
android:id="@+id/volume_ratingBar"
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:layout_gravity="center_vertical"
android:numStars="6"
android:paddingBottom="20dip"
android:visibility="gone"
android:paddingTop="20dip"
android:max="10"
android:progress="7"
android:progressDrawable="@drawable/volume_rating"
android:stepSize="1" />
这里注意一下,layer-list中的drawable必须是图片,不能用自己画的shape,原因我也不清楚。
自定义View
attrs.xml
VolumeView
public class VolumeView extends View {
private Paint paint;
// 控件宽度
private int width = 430;
// 控件高度
private int height = 100;
// 两个音量矩形最左侧之间的间隔
private int rectMargin = 10;
// 音量矩形高
private int rectH = 30;
// 音量矩形宽
private int rectW = 15;
// 未选中音量颜色
private int unChoiceVolumeColor;
// 选中音量颜色
private int choiceVolumeColor;
// 当前音量
private int currentVolume;
// 最大音量
private int maxVolume;
// 音量减-左坐标
private int minusLeft;
// 音量减-右坐标
private int minusRight;
// 音量加-左坐标
private int plusLeft;
// 音量加-右坐标
private int plusRight;
//音量图标
private Bitmap volumeIcon;
//音量关闭图标
private Bitmap volumeCloseIcon;
//减音量图标
private Bitmap minusIcon;
//加音量图标
private Bitmap plusIcon;
private OnVolumeChangedListener onVolumeChangedListener;
public VolumeView(Context context) {
this(context, null);
}
public VolumeView(Context context, @Nullable AttributeSet attrs) {
this(context, attrs, 0);
}
public VolumeView(Context context, @Nullable AttributeSet attrs, int defStyleAttr) {
super(context, attrs, defStyleAttr);
TypedArray typedArray = context.obtainStyledAttributes(attrs, R.styleable.VolumeView);
choiceVolumeColor = typedArray.getColor(R.styleable.VolumeView_volumeColor, Color.BLACK);
unChoiceVolumeColor = typedArray.getColor(R.styleable.VolumeView_defaultVolumenColor, Color.WHITE);
currentVolume = typedArray.getInteger(R.styleable.VolumeView_volume, 0);
maxVolume = typedArray.getInteger(R.styleable.VolumeView_max, 0);
typedArray.recycle();
paint = new Paint();
volumeIcon = BitmapFactory.decodeResource(getResources(), R.drawable.volume);
volumeCloseIcon = BitmapFactory.decodeResource(getResources(), R.drawable.volume_close);
minusIcon = BitmapFactory.decodeResource(getResources(), R.drawable.minus);
plusIcon = BitmapFactory.decodeResource(getResources(), R.drawable.plus);
}
public void setOnVolumeChangedListener(OnVolumeChangedListener onVolumeChangedListener) {
this.onVolumeChangedListener = onVolumeChangedListener;
}
@Override
protected void onDraw(Canvas canvas) {
super.onDraw(canvas);
if (onVolumeChangedListener != null) {
onVolumeChangedListener.onVolumenChanged(currentVolume);
}
if (currentVolume == 0) {
canvas.drawBitmap(volumeCloseIcon, 0, 0, paint);
} else {
canvas.drawBitmap(volumeIcon, 0, 0, paint);
}
int iconWidth = volumeIcon.getWidth();
int iconHeight = volumeIcon.getHeight();
int offsetTop = (iconHeight - minusIcon.getHeight()) / 2;
int offsetLeft = iconWidth + rectMargin * 2;
minusLeft = iconWidth;
canvas.drawBitmap(minusIcon, offsetLeft, offsetTop, paint);
int offsetVolumeLeft = offsetLeft + minusIcon.getWidth() + rectMargin * 2;
minusRight = offsetVolumeLeft;
int offsetVolumeTop = (iconHeight - rectH) / 2;
paint.setColor(choiceVolumeColor);
for (int i = 0; i < currentVolume; i++) {
int left = offsetVolumeLeft + i * rectW + i * rectMargin;
canvas.drawRect(left, offsetVolumeTop, left + rectW, offsetVolumeTop + rectH, paint);
}
paint.setColor(unChoiceVolumeColor);
for (int i = currentVolume; i < maxVolume; i++) {
int left = offsetVolumeLeft + i * rectW + i * rectMargin;
canvas.drawRect(left, offsetVolumeTop, left + rectW, offsetVolumeTop + rectH, paint);
}
int offsetPlusTop = (iconHeight - plusIcon.getHeight()) / 2;
int offsetPlusLeft = offsetVolumeLeft + maxVolume * rectW + maxVolume * rectMargin + rectMargin;
plusLeft = offsetVolumeLeft + maxVolume * rectW + (maxVolume - 1) * rectMargin;
plusRight = offsetPlusLeft + plusIcon.getWidth() + rectMargin;
canvas.drawBitmap(plusIcon, offsetPlusLeft, offsetPlusTop, paint);
}
public void addVolume() {
if (currentVolume >= maxVolume) {
return;
}
currentVolume++;
invalidate();
}
public void minusVolume() {
if (currentVolume <= 0) {
return;
}
currentVolume--;
invalidate();
}
@Override
public boolean onTouchEvent(MotionEvent event) {
if (event.getAction() == MotionEvent.ACTION_DOWN) {
float eventX = event.getX();
if (eventX >= minusLeft && eventX <= minusRight) {//minusVolume
minusVolume();
return true;
} else if (eventX >= plusLeft && eventX <= plusRight) {//addVolume
addVolume();
return true;
}
}
return super.onTouchEvent(event);
}
public interface OnVolumeChangedListener {
void onVolumenChanged(int volume);
}
}
MainActivity.java
volumeView.setOnVolumeChangedListener(volume -> {
tvCurVolume.setText("当前音量:" + volume);
});
这里也注意下,Bitmap plusIcon = BitmapFactory.decodeResource(getResources(), R.drawable.plus);同样不能用自己画的shape,原因不详。