Android——自定義音量調節控件

在這裏插入圖片描述
今天我們要實現一個上圖中音量調節的效果。主要有兩種實現方式自定義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,原因不詳。

發表評論
所有評論
還沒有人評論,想成為第一個評論的人麼? 請在上方評論欄輸入並且點擊發布.
相關文章