Apple-like volume control column

Posted by Hillu on Sun, 21 Jun 2020 18:10:04 +0200

After the upgrade of the tablet, we found that in the new IOS system, the volume-adjusting controls appearing after the scroll make people look very comfortable, good, try to achieve the following on Android.
Above:

The end result is this.
Ideas for implementation:

First, draw a rectangle.
Step 2, draw a rounded rectangle on top of the rectangle and pass through the
paint.setXfermode(new PorterDuffXfermode(PorterDuff.Mode.CLEAR));
Method to make the overlap transparent.
Finally, the first rectangle drawn is manipulated in the code to achieve the effect shown above.

Extensions to controls:

        <attr name="bgColor" format="color|integer"></attr>
        <attr name="radius" format="integer"></attr>
        <attr name="isWrappeLine" format="boolean"></attr>

In the code, add

    public void setValues(float v){
        ......
    }
    public IphoneSwitchView setColor(int color){
        ......
    }

Two methods allow us to dynamically change the background color of the control.
A callback was added to facilitate subsequent development.

    public void registerCallback(ValueChangeCallback callback){
        mCallback = callback;
    }
    interface ValueChangeCallback{
        void onValueChanged(double value);
    }

Finally, stick the key code:

public class IphoneSwitchView extends View{

    private int mWidth,mHeight;
    private int strokenWidth;
    private boolean isWrapperLine;
    private float lastX,lastY,curX,curY;
    private int mCurrValue=100,mLastValue=0;
    private int curPoint;
    private int mBgColor;
    private Paint paint;
    private ValueChangeCallback mCallback;
    public IphoneSwitchView(Context context) {
        this(context,null);
    }

    public IphoneSwitchView(Context context, @Nullable AttributeSet attrs) {
        this(context, attrs,0);
    }

    public IphoneSwitchView(Context context, @Nullable AttributeSet attrs, int defStyleAttr) {
        super(context, attrs, defStyleAttr);
        init(context,attrs);
    }

    @Override
    protected void onLayout(boolean changed, int left, int top, int right, int bottom) {
        super.onLayout(changed, left, top, right, bottom);
        mWidth = getWidth();
        mHeight = getHeight();
        //Initialize radian size
        strokenWidth = strokenWidth!=-1?strokenWidth:mWidth/5;
    }

    private void init(Context context,AttributeSet attrs) {
        TypedArray array =  context.obtainStyledAttributes(attrs,R.styleable.IphoneSwitchView);
        int color = (int) array.getInt(R.styleable.IphoneSwitchView_bgColor,-1);
        mBgColor = color!=-1?color:getResources().getColor(R.color.colorAccent);
        strokenWidth = (int) array.getInt(R.styleable.IphoneSwitchView_radius,-1);
        isWrapperLine = array.getBoolean(R.styleable.IphoneSwitchView_isWrappeLine,true);
        paint = new Paint();
        paint.setAntiAlias(true);
        paint.setStrokeWidth(4);
    }


    @Override
    protected void onDraw(Canvas canvas) {
        super.onDraw(canvas);
        // Draw a rectangle at the bottom
        RectF rectF = new RectF(0,mHeight-mCurrValue,mWidth,mHeight);
        int layerId = canvas.saveLayer(0, 0, mWidth, mHeight, null, Canvas.ALL_SAVE_FLAG);
        paint.setColor(mBgColor);
        paint.setStyle(Paint.Style.FILL);
        canvas.drawRect(rectF,paint);
        // Start drawing rounded rectangle
        paint.setXfermode(new PorterDuffXfermode(PorterDuff.Mode.CLEAR));
        paint.setStyle(Paint.Style.STROKE);
        paint.setColor(Color.WHITE);
        paint.setStrokeWidth(strokenWidth);
        rectF = new RectF(0,0,mWidth,mHeight);
        canvas.drawRoundRect(rectF,strokenWidth,strokenWidth,paint);
        paint.setXfermode(null);
        canvas.restoreToCount(layerId);
        // Determine whether an outer border is required
        if(isWrapperLine){
            paint.setStrokeWidth(2);
            paint.setColor(Color.BLACK);
            rectF = new RectF(1,1,mWidth-1,mHeight-1);
            canvas.drawRoundRect(rectF,strokenWidth,strokenWidth,paint);
        }
    }

    @Override
    public boolean onTouchEvent(MotionEvent event) {
        switch (event.getAction()){
            case MotionEvent.ACTION_DOWN:
                lastX =  event.getX();
                lastY =  event.getY();
                //Remember to do event interception consumer action
                return true;
            case MotionEvent.ACTION_MOVE:
                curX = event.getX();
                curY = event.getY();
                resetValues(lastY-curY);
                lastX =  event.getX();
                lastY =  event.getY();
                break;
            case MotionEvent.ACTION_UP:
                break;
        }
        return super.onTouchEvent(event);
    }

    private void resetValues(float v) {
        float cacheValue = mCurrValue+v;
        Log.d("chenxiaoping","v := "+v+"  "+cacheValue+"  mHeight "+mHeight);
        if(cacheValue<=mHeight&&cacheValue>=0){
            mCurrValue = (int) cacheValue;
            if(mCallback!=null){
                mCallback.onValueChanged(cacheValue/mHeight);
            }
        }
        postInvalidate();
    }

    public void setValues(float v){
        setInitialValue(v);
    }

    public IphoneSwitchView setColor(int color){
        mBgColor = color;
        postInvalidate();
        return this;
    }

    /**
     * persent 0-1
     * @param value
     * @return
     */
    public IphoneSwitchView setInitialValue(double value){
        if(value>1||value<0){
            mCurrValue = 0;
        }else{
            mCurrValue = (int) (mHeight*value);
        }

        if(mCallback!=null){
            mCallback.onValueChanged(mCurrValue/mHeight);
        }

        mLastValue = mCurrValue;
        postInvalidate();
        return this;
    }

    public void registerCallback(ValueChangeCallback callback){
        mCallback = callback;
    }

    interface ValueChangeCallback{
        void onValueChanged(double value);
    }
}

After the introduction, continue your efforts.

Topics: iOS Android