天天看點

安卓自定義圓形seekBar

之前公司項目要求做一個可控制燈泡的色溫的一個圓形滑動選擇控件。這樣描述大多數人會覺得很懵逼,放一張效果圖吧。

安卓自定義圓形seekBar

滑動圓點可以擷取目前所在位置的RGB的值和設定的1-100的值來改變背景顔色和上方顯示的數組,就這麼簡單。看看代碼是怎麼實作的吧!

先貼一個自定義view的類:

package com.simon.circleseekview;

import android.content.Context;
import android.graphics.Bitmap;
import android.graphics.BitmapFactory;
import android.graphics.Canvas;
import android.graphics.Color;
import android.graphics.Paint;
import android.support.annotation.Nullable;
import android.util.AttributeSet;
import android.view.MotionEvent;
import android.view.View;

/**
 * Created by ZHUQI on 2017/9/19.
 */

public class CircleSeekView extends View {

    private static final float CIRCLE_RATE = 0.37f;
    private int mWidth;
    private int mHeight;
    private Bitmap bitmapBg;
    private Bitmap bitmapThum;
    private Paint mPaint;
    private float thumLeftPosition;
    private float thumTopPosition;
    private int bitmapThumWidth;
    private int bitmapThumHeight;
    private int radius;
    private OnSelectColorListener mOnSelectColorListener;
    private int colorValue;
    private float circleD;
    private float top;
    private boolean isByUser;


    public CircleSeekView(Context context) {
        super(context);
    }

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

    public CircleSeekView(Context context, @Nullable AttributeSet attrs, int defStyleAttr) {
        super(context, attrs, defStyleAttr);
        initPaint();
        initBitmap();
    }

    private void initBitmap() {
        bitmapBg = BitmapFactory.decodeResource(getResources(), R.mipmap.k2_light_color_picker_bg);
        bitmapThum = BitmapFactory.decodeResource(getResources(), R.mipmap.k2_light_switch_thum);
        bitmapThumWidth = bitmapThum.getWidth()/2;
        bitmapThumHeight = bitmapThum.getHeight()/2;
    }

    private void initPaint(){
        mPaint = new Paint();
    }

    @Override
    protected void onMeasure(int widthMeasureSpec, int heightMeasureSpec) {
        int widthMode = MeasureSpec.getMode(widthMeasureSpec);
        int heightMode = MeasureSpec.getMode(heightMeasureSpec);
        int widthSize = MeasureSpec.getSize(widthMeasureSpec);
        int heightSize = MeasureSpec.getSize(heightMeasureSpec);

        if (widthMode == MeasureSpec.EXACTLY) {
            mWidth = widthSize;
            radius = mWidth/2;
        }else if(widthMode == MeasureSpec.AT_MOST){
            throw new IllegalArgumentException("width must be EXACTLY,you should set like android:width=\"200dp\"");
        }

        if (heightMode == MeasureSpec.EXACTLY) {
            mHeight = heightSize;
        }else if(widthMeasureSpec == MeasureSpec.AT_MOST){

            throw new IllegalArgumentException("height must be EXACTLY,you should set like android:height=\"200dp\"");
        }

        if(!isByUser){
            getFixedThumPostion(radius, 0);
            float top = thumTopPosition;
            getFixedThumPostion(radius, mHeight);
            float bottom = thumTopPosition;
            circleD = bottom - top;
            thumTopPosition = circleD*colorValue/100 + top;
            if(colorValue == 0 || colorValue == 100){
                thumLeftPosition = radius-bitmapThumWidth;
            }else {
                thumLeftPosition = (float) (Math.sqrt(CIRCLE_RATE*2*(radius) * CIRCLE_RATE*2*(radius) -
                        Math.abs(thumTopPosition+bitmapThumWidth - radius) * Math.abs(thumTopPosition+bitmapThumWidth - radius))+radius-bitmapThumWidth);
            }

            int rgb[] = getPointRGB((int)thumLeftPosition,(int)thumTopPosition);
            if(mOnSelectColorListener != null)
                mOnSelectColorListener.onSelectColor(rgb, getColorValue(),false);
        }
        setMeasuredDimension(mWidth, mHeight);
    }

    @Override
    protected void onDraw(Canvas canvas) {
        super.onDraw(canvas);
        canvas.drawBitmap(bitmapBg,0,0,mPaint);
        canvas.drawBitmap(bitmapThum,thumLeftPosition,thumTopPosition,mPaint);
    }

    @Override
    public boolean onTouchEvent(MotionEvent event) {

        if(event.getAction() == MotionEvent.ACTION_DOWN || event.getAction() == MotionEvent.ACTION_MOVE ||
                event.getAction() == MotionEvent.ACTION_HOVER_MOVE ){
            isByUser = true;
            thumLeftPosition = event.getX() - bitmapThumWidth/2;
            thumTopPosition = event.getY()- bitmapThumHeight/2;
            getFixedThumPostion(thumLeftPosition,thumTopPosition);
            int rgb[] = getPointRGB((int)thumLeftPosition,(int)thumTopPosition);
            colorValue = (int) ((thumTopPosition-(1-CIRCLE_RATE/2)*radius)*100/(CIRCLE_RATE*4*(radius))) + 48;
            if(mOnSelectColorListener != null)
                mOnSelectColorListener.onSelectColor(rgb, getColorValue(),true);
        }else if(event.getAction() == MotionEvent.ACTION_UP){
            if(mOnSelectColorListener != null)
                mOnSelectColorListener.onSelectColorFinish(getColorValue());
        }
        invalidate();
        return true;
    }

    /**
     * 根據y軸坐标換算成 0-100 的色溫值
     * @return
     */
    public int getColorValue() {
        return colorValue;
    }

    public void setColorValue(int colorValue){
        isByUser = false;
        this.colorValue = colorValue;
    }

    /**
     * 根據目前坐标擷取背景圖檔的RGB值
     * @param x
     * @param y
     * @return
     */
    private int[] getPointRGB(int x, int y) {
        int[] rgb = {Color.red(bitmapBg.getPixel(x,y)),
                Color.green(bitmapBg.getPixel(x,y)),
                Color.blue(bitmapBg.getPixel(x,y))};
        return rgb;
    }

    /**
     * 計算出圓點滑動軌迹内的位置坐标
     * @param x
     * @param y
     */
    private void getFixedThumPostion(float x, float y) {
        if(x > radius && y < radius){
            thumLeftPosition = (float) ((CIRCLE_RATE*mWidth *(x - radius))/Math.sqrt((x - radius)*(x - radius) + (y - radius)*(y - radius))) + radius-bitmapThumWidth;
            thumTopPosition = (float) (radius - (CIRCLE_RATE*mWidth *(radius - y))/Math.sqrt((x - radius)*(x - radius) + (y - radius)*(y - radius))) - bitmapThumHeight;
        }else if (x <= radius && y < radius){
            thumLeftPosition = (float) (radius - (CIRCLE_RATE*mWidth *(radius - x))/Math.sqrt((x - radius)*(x - radius) + (y - radius)*(y - radius)))-bitmapThumWidth;
            thumTopPosition = (float) (radius - (CIRCLE_RATE*mWidth *(radius - y))/Math.sqrt((x - radius)*(x - radius) + (y - radius)*(y - radius))) - bitmapThumHeight;
        }else if (x > radius && y >= radius){
            thumLeftPosition = (float) ((CIRCLE_RATE*mWidth *(x - radius))/Math.sqrt((x - radius)*(x - radius) + (y - radius)*(y - radius))) + radius-bitmapThumWidth;
            thumTopPosition = (float) ((CIRCLE_RATE*mWidth *(y -radius ))/Math.sqrt((x - radius)*(x - radius) + (y - radius)*(y - radius))) + radius - bitmapThumHeight;
        }else if (x <= radius && y >= radius){
            thumLeftPosition = (float) (radius - (CIRCLE_RATE*mWidth *(radius - x))/Math.sqrt((x - radius)*(x - radius) + (y - radius)*(y - radius)))-bitmapThumWidth;
            thumTopPosition = (float) ((CIRCLE_RATE*mWidth *(y -radius))/Math.sqrt((x - radius)*(x - radius) + (y - radius)*(y - radius))) + radius - bitmapThumHeight;
        }
    }

    public void setOnSelectColorListener(OnSelectColorListener listener) {
        this.mOnSelectColorListener = listener;
    }

    public interface OnSelectColorListener {
        void onSelectColor(int[] rgb, int colorValue,boolean isFromUser);
        void onSelectColorFinish(int colorValue);
    }

    public void recycleBitMap(){
        if(bitmapBg != null){
            bitmapBg.recycle();
            bitmapBg = null;
        }
        if(bitmapThum != null){
            bitmapThum.recycle();
            bitmapThum = null;
        }
    }

}


           

然後是MainActivity:

package com.simon.circleseekview;

import android.graphics.Color;
import android.os.Bundle;
import android.support.v7.app.AppCompatActivity;
import android.widget.RelativeLayout;
import android.widget.TextView;

public class MainActivity extends AppCompatActivity {

    private CircleSeekView color_picker;
    private RelativeLayout layout;
    private TextView value_tv;

    @Override
    protected void onCreate(Bundle savedInstanceState) {
        super.onCreate(savedInstanceState);
        setContentView(R.layout.activity_main);
        color_picker = findViewById(R.id.k2_light_color_picker);
        value_tv = findViewById(R.id.value_tv);
        layout = findViewById(R.id.layout);
        color_picker.setColorValue(50);
        color_picker.setOnSelectColorListener(new CircleSeekView.OnSelectColorListener() {
            @Override
            public void onSelectColor(int[] rgb, int colorValue,boolean isFromUser) {
                layout.setBackgroundColor(Color.argb(255,rgb[0],rgb[1],rgb[2]));
                value_tv.setText(colorValue+"");
            }

            @Override
            public void onSelectColorFinish(int colorValue) {

            }
        });

    }

    @Override
    protected void onDestroy() {
        color_picker.recycleBitMap();
        super.onDestroy();
    }
}
           

就這麼簡單,不過還有很多可以優化的地方,以後慢慢優化。

=========================================================================================

第一次發帖,請多多指教!