今天我們要實現一個上圖中音量調節的效果。主要有兩種實現方式自定義RatingBar和自定義View。
自定義RatingBar
volume_rating.xml
<layer-list xmlns:android="http://schemas.android.com/apk/res/android">
<item android:id="@android:id/background" android:drawable="@drawable/volume_off"/>
<item android:id="@android:id/secondaryProgress" android:drawable="@drawable/volume_on"/>
<item android:id="@android:id/progress" android:drawable="@drawable/volume_on"/>
</layer-list>
main.xml
<android.support.v7.widget.AppCompatRatingBar
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
<?xml version="1.0" encoding="utf-8"?>
<resources>
<declare-styleable name="VolumeView">
<attr name="volumeColor" format="color|reference" />
<attr name="defaultVolumenColor" format="color|reference" />
<attr name="max" format="integer"/>
<attr name="volume" format="integer"/>
</declare-styleable>
</resources>
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 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();
}
public void setOnVolumeChangedListener(OnVolumeChangedListener onVolumeChangedListener) {
this.onVolumeChangedListener = onVolumeChangedListener;
}
@Override
protected void onDraw(Canvas canvas) {
super.onDraw(canvas);
if (onVolumeChangedListener != null) {
onVolumeChangedListener.onVolumenChanged(currentVolume);
}
Bitmap volumeIcon = BitmapFactory.decodeResource(getResources(), R.drawable.volume);
Bitmap volumeCloseIcon = BitmapFactory.decodeResource(getResources(), R.drawable.volume_close);
if (currentVolume == 0) {
canvas.drawBitmap(volumeCloseIcon, 0, 0, paint);
} else {
canvas.drawBitmap(volumeIcon, 0, 0, paint);
}
int iconWidth = volumeIcon.getWidth();
int iconHeight = volumeIcon.getHeight();
Bitmap minusIcon = BitmapFactory.decodeResource(getResources(), R.drawable.minus);
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);
}
Bitmap plusIcon = BitmapFactory.decodeResource(getResources(), R.drawable.plus);
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
,原因不詳。