自定义拖拽IndicatorView

1. 效果图

这里写图片描述

2. 根据效果,定义需要属性:

其中模式下: 手动不可点击, 风速时: 最低和最高不可点击, 定时模式: 全部可以点击设置.

<declare-styleable name="IndicatorView">
        <attr name="units" format="integer|reference"/>
        <attr name="lightColor" format="reference|color"/>
        <attr name="lightBitmap" format="reference"/>
        <attr name="indicators" format="reference|string"/>

        <attr name="controlStyle" format="enum">
            <enum name="mode" value="0"/>
            <enum name="wind" value="1"/>
            <enum name="time" value="2"/>
        </attr>
    </declare-styleable>
 private void parserAttrs(Context context, AttributeSet attrs) {
        TypedArray ta = context.obtainStyledAttributes(attrs, R.styleable.IndicatorView);
        mLightColor = ta.getColor(R.styleable.IndicatorView_lightColor, 
                    Color.argb(0xFF, 0xFF, 0xC1, 0x00));
        int resourceId = ta.getResourceId(R.styleable.IndicatorView_lightBitmap, 0);
        mLightBitmap = BitmapFactory.decodeResource(context.getResources(), resourceId);
        mText = ta.getString(R.styleable.IndicatorView_indicators);
        mIndicators = mText.split(",");
        mUnits = mText.split(",").length - 1;

        int mode = ta.getInt(R.styleable.IndicatorView_controlStyle, TIME);
        switch (mode) {
            case MODE:
                mType = MODE;
                break;
            case WIND:
                mType = WIND;
                break;
            case TIME:
                mType = TIME;
                break;
        }

        ta.recycle();
    }

2. 初始化控件的一些默认值:

@Override
protected void onSizeChanged(int w, int h, int oldw, int oldh) {
    super.onSizeChanged(w, h, oldw, oldh);
    mLeftX = getPaddingLeft();
    mAvailableWidth = w - getPaddingLeft() - getPaddingRight();
    float unit = mAvailableWidth / mUnits;
    mThumbX = mLeftX + unit * mPosition;//粘近position

}

3. 测量控件的宽高:

    /*简单测量,只支持为match_parent或者固定值*/
    @Override
    protected void onMeasure(int widthMeasureSpec, int heightMeasureSpec) {
        int width;
        int height;

        final int measureWidthMode = MeasureSpec.getMode(widthMeasureSpec);
        final int measureHeightMode = MeasureSpec.getMode(heightMeasureSpec);
        final int measureWidth = MeasureSpec.getSize(widthMeasureSpec);
        final int measureHeight = MeasureSpec.getSize(heightMeasureSpec);

        /*布局width为match_parent或者固定值*/
        if (measureWidthMode == MeasureSpec.EXACTLY) {
            width = measureWidth;
        } else {
            width = mDefaultWidth;
        }
        /*布局height为match_parent或者固定值*/
        if (measureHeightMode == MeasureSpec.EXACTLY) {
            height = measureHeight;
        } else {
            height = mDefaultHeight;
        }
        setMeasuredDimension(width, height);
    }

4.绘制thumb, 文本,及其tracker

 @Override
    protected void onDraw(Canvas canvas) {
        super.onDraw(canvas);
        drawTrack(canvas);
        drawIndicatorTexts(canvas);
        drawThumb(canvas);
    }

    /**
     * 绘制thumb所在的track
     *
     * @param canvas
     */
    private void drawTrack(Canvas canvas) {
        Rect rect = new Rect(mLeftX, getHeight() * 2 / 3 - mTrackHeight / 2, mLeftX + mAvailableWidth, 
        getHeight() * 2 / 3 + mTrackHeight / 2);
        mPaint.setColor(Color.parseColor("#ededed"));
        canvas.drawRect(rect, mPaint);
    }

    /**
     * 绘制indicators
     *
     * @param canvas
     */
    private void drawIndicatorTexts(Canvas canvas) {
        int count = mUnits;
        Paint paint;
        for (int i = 0; i <= count; i++) {
            final float x = mAvailableWidth / count * i + mLeftX;

            if (i == mPosition) {//当前选中的position
                paint = mTextPaint;
                mTextPaint.setColor(mLightColor);
            } else {//没选中的position
                paint = mTextPaint;
                mTextPaint.setColor(Color.argb(0xFF, 0xBB, 0xBB, 0xBB));
            }
            paint.getTextBounds(mIndicators[i], 0, mIndicators[i].length(), mTextRect);
            String text = mIndicators[i];
            canvas.drawText(text, x - mTextRect.width() / 2, getHeight() / 3, paint);
        }
    }

    /**
     * 绘制thumb
     *
     * @param canvas
     */
    private void drawThumb(Canvas canvas) {
        Bitmap bitmap = mLightBitmap;
        mThumbX = getThumbX(mPosition);
        if (bitmap != null) {
            canvas.drawBitmap(bitmap, mThumbX - bitmap.getWidth() / 2, 
            getHeight() * 2 / 3 - bitmap.getHeight() / 2, null);
        }
    }

5. 构建点击事件的监听器:

@Override
    public boolean onTouchEvent(MotionEvent event) {
        if (!isEnabled()) {
            return false;
        }
        switch (event.getAction()) {
            case MotionEvent.ACTION_DOWN:
            case MotionEvent.ACTION_MOVE: {
                this.getParent().requestDisallowInterceptTouchEvent(true);
                float x = event.getX();
                moveThumb(x);
                break;
            }
            case MotionEvent.ACTION_UP:
            case MotionEvent.ACTION_CANCEL: {
                if (mListener != null) {
                    mListener.onPositionChange(mPosition);
                }
                float x = event.getX();
                moveThumb(x);
                this.getParent().requestDisallowInterceptTouchEvent(false);
                break;
            }
        }
        return true;
    }

    private void moveThumb(float x) {
        if (mPosition == getPosition(x)) {
            return;
        }
        mPosition = getPosition(x);
        switch (mType) {
            case MODE:
                if (mPosition == 0) {
                    mPosition = 1;
                }
                break;
            case WIND:
                if (mPosition == 0) {
                    mPosition = 1;
                } else if (mPosition == 4) {
                    mPosition = 3;
                }
                break;

            case TIME:
                break;
        }
        mThumbX = getThumbX(mPosition);
        invalidate();
    }

    /**
     * 根据thumb的坐标获取thumb的位置
     *
     * @param x
     * @return
     */
    private int getPosition(float x) {
        float unitWidth = mAvailableWidth / mUnits;
        float originX = (x - mLeftX + unitWidth / 2f) / unitWidth;
        return (int) originX;
    }

    /**
     * 根据thumb的位置获取thumb的坐标
     *
     * @param position
     * @return
     */
    private float getThumbX(int position) {
        float unit = mAvailableWidth / mUnits;
        return mLeftX + unit * position;
    }

6.保存与恢复自定义view的状态信息:

在屏幕旋转等情况要保存view的状态, 防止一些状态信息丢失,如thumb图标消失.

 @Override
    protected void onRestoreInstanceState(Parcelable state) {
        if (!(state instanceof Bundle)) {
            super.onRestoreInstanceState(state);
            return;
        }
        Bundle bundle = (Bundle) state;
        mLightBitmap = bundle.getParcelable("bitmap");
        mText = bundle.getString("indicators");
        mPosition = bundle.getInt("position");
        mThumbX = bundle.getFloat("thumbX");
        mType = bundle.getInt("mType");
        mTrackHeight = bundle.getInt("trackHeight");
        super.onRestoreInstanceState(bundle.getParcelable("instance"));
    }

    //##### 对外公布的方法###########################//

    @Override
    protected Parcelable onSaveInstanceState() {

        Bundle bundle = new Bundle();
        bundle.putParcelable("bitmap", mLightBitmap);
        bundle.putInt("position", mPosition);
        bundle.putString("indicators", mText);
        bundle.putFloat("thumbX", mThumbX);
        bundle.putInt("mType", mType);
        bundle.putInt("trackHeight", mTrackHeight);
        bundle.putParcelable("instance", super.onSaveInstanceState());
        return bundle;
    }

完整代码:

package ****

import android.content.Context;
import android.content.res.TypedArray;
import android.graphics.Bitmap;
import android.graphics.BitmapFactory;
import android.graphics.Canvas;
import android.graphics.Color;
import android.graphics.Paint;
import android.graphics.Rect;
import android.os.Bundle;
import android.os.Parcelable;
import android.text.TextPaint;
import android.util.AttributeSet;
import android.util.TypedValue;
import android.view.MotionEvent;
import android.view.View;

import com.bugull.yft_airclean.R;

/**
 * @ author: showdy
 * @ time: 2016/5/21 14:20
 * @ des: 用于控件界面的indicatorView
 */
public class IndicatorView extends View {

    private static final int MODE = 0;
    private static final int WIND = 1;
    private static final int TIME = 2;
    private OnPositionChangedListener mListener;
    private int mUnits;
    private int mLightColor;
    private Bitmap mLightBitmap;
    private String mText;
    private Paint mPaint;
    private Paint mTextPaint; //文字画笔
    private int mDefaultWidth;
    private int mDefaultHeight;
    private int mLeftX;
    private int mAvailableWidth;
    private float mThumbX; //thumb的起始横坐标
    private int mPosition = 0; //当前位置
    private String[] mIndicators;
    private Rect mTextRect;
    private int mTrackHeight = 0;
    private int mType = TIME;
    private Context mContext;

    public IndicatorView(Context context) {
        this(context, null);
    }

    public IndicatorView(Context context, AttributeSet attrs) {
        this(context, attrs, 0);
    }

    public IndicatorView(Context context, AttributeSet attrs, int defStyleAttr) {
        super(context, attrs, defStyleAttr);
        mContext = context;
        mTrackHeight = (int) TypedValue.applyDimension(TypedValue.COMPLEX_UNIT_DIP, 4, 
        context.getResources().getDisplayMetrics());
        mDefaultWidth = (int) TypedValue.applyDimension(TypedValue.COMPLEX_UNIT_DIP, 260,
         context.getResources().getDisplayMetrics());
        mDefaultHeight = (int) TypedValue.applyDimension(TypedValue.COMPLEX_UNIT_DIP, 70,
         context.getResources().getDisplayMetrics());
        parserAttrs(context, attrs);
        initPaint();
    }

    private void initPaint() {
        mPaint = new Paint(Paint.ANTI_ALIAS_FLAG | Paint.DITHER_FLAG);
        mPaint.setColor(Color.argb(0xFF, 0xBB, 0xBB, 0xBB));
        mPaint.setStyle(Paint.Style.FILL);

        mTextPaint = new TextPaint(Paint.ANTI_ALIAS_FLAG | Paint.DITHER_FLAG);
        mTextPaint.setColor(Color.argb(0xFF, 0xBB, 0xBB, 0xBB));
        mTextPaint.setStyle(Paint.Style.FILL);
        mTextPaint.setTextSize(TypedValue.applyDimension(TypedValue.COMPLEX_UNIT_DIP, 14, 
        getResources().getDisplayMetrics()));

        mTextRect = new Rect();

    }

    private void parserAttrs(Context context, AttributeSet attrs) {
        TypedArray ta = context.obtainStyledAttributes(attrs, R.styleable.IndicatorView);
        mLightColor = ta.getColor(R.styleable.IndicatorView_lightColor, Color.argb(0xFF, 0xFF, 0xC1, 0x00));
        int resourceId = ta.getResourceId(R.styleable.IndicatorView_lightBitmap, 0);
        mLightBitmap = BitmapFactory.decodeResource(context.getResources(), resourceId);
        mText = ta.getString(R.styleable.IndicatorView_indicators);
        mIndicators = mText.split(",");
        mUnits = mText.split(",").length - 1;

        int mode = ta.getInt(R.styleable.IndicatorView_controlStyle, TIME);
        switch (mode) {
            case MODE:
                mType = MODE;
                break;
            case WIND:
                mType = WIND;
                break;
            case TIME:
                mType = TIME;
                break;
        }

        ta.recycle();
    }

    @Override
    protected void onMeasure(int widthMeasureSpec, int heightMeasureSpec) {
        int width;
        int height;

        final int measureWidthMode = MeasureSpec.getMode(widthMeasureSpec);
        final int measureHeightMode = MeasureSpec.getMode(heightMeasureSpec);
        final int measureWidth = MeasureSpec.getSize(widthMeasureSpec);
        final int measureHeight = MeasureSpec.getSize(heightMeasureSpec);

        if (measureWidthMode == MeasureSpec.EXACTLY) {
            width = measureWidth;
        } else {
            width = mDefaultWidth;
        }
        if (measureHeightMode == MeasureSpec.EXACTLY) {
            height = measureHeight;
        } else {
            height = mDefaultHeight;
        }
        setMeasuredDimension(width, height);
    }

    @Override
    protected void onSizeChanged(int w, int h, int oldw, int oldh) {
        super.onSizeChanged(w, h, oldw, oldh);
        mLeftX = getPaddingLeft();
        mAvailableWidth = w - getPaddingLeft() - getPaddingRight();
        float unit = mAvailableWidth / mUnits;
        mThumbX = mLeftX + unit * mPosition;//粘近position

    }

    @Override
    public boolean onTouchEvent(MotionEvent event) {
        if (!isEnabled()) {
            return false;
        }
        switch (event.getAction()) {
            case MotionEvent.ACTION_DOWN:
            case MotionEvent.ACTION_MOVE: {
                this.getParent().requestDisallowInterceptTouchEvent(true);
                float x = event.getX();
                moveThumb(x);
                break;
            }
            case MotionEvent.ACTION_UP:
            case MotionEvent.ACTION_CANCEL: {
                if (mListener != null) {
                    mListener.onPositionChange(mPosition);
                }
                float x = event.getX();
                moveThumb(x);
                this.getParent().requestDisallowInterceptTouchEvent(false);
                break;
            }
        }
        return true;
    }

    private void moveThumb(float x) {
        if (mPosition == getPosition(x)) {
            return;
        }
        mPosition = getPosition(x);
        switch (mType) {
            case MODE:
                if (mPosition == 0) {
                    mPosition = 1;
                }
                break;
            case WIND:
                if (mPosition == 0) {
                    mPosition = 1;
                } else if (mPosition == 4) {
                    mPosition = 3;
                }
                break;

            case TIME:
                break;
        }
        mThumbX = getThumbX(mPosition);
        invalidate();
    }

    /**
     * 根据thumb的坐标获取thumb的位置
     *
     * @param x
     * @return
     */
    private int getPosition(float x) {
        float unitWidth = mAvailableWidth / mUnits;
        float originX = (x - mLeftX + unitWidth / 2f) / unitWidth;
        return (int) originX;
    }

    /**
     * 根据thumb的位置获取thumb的坐标
     *
     * @param position
     * @return
     */
    private float getThumbX(int position) {
        float unit = mAvailableWidth / mUnits;
        return mLeftX + unit * position;
    }

    @Override
    protected void onDraw(Canvas canvas) {
        super.onDraw(canvas);
        drawTrack(canvas);
        drawIndicatorTexts(canvas);
        drawThumb(canvas);
    }

    /**
     * 绘制thumb所在的track
     *
     * @param canvas
     */
    private void drawTrack(Canvas canvas) {
        Rect rect = new Rect(mLeftX, getHeight() * 2 / 3 - mTrackHeight / 2, 
        mLeftX + mAvailableWidth, getHeight() * 2 / 3 + mTrackHeight / 2);
        mPaint.setColor(Color.parseColor("#ededed"));
        canvas.drawRect(rect, mPaint);
    }

    /**
     * 绘制indicators
     *
     * @param canvas
     */
    private void drawIndicatorTexts(Canvas canvas) {
        int count = mUnits;
        Paint paint;
        for (int i = 0; i <= count; i++) {
            final float x = mAvailableWidth / count * i + mLeftX;

            if (i == mPosition) {//当前选中的position
                paint = mTextPaint;
                mTextPaint.setColor(mLightColor);
            } else {//没选中的position
                paint = mTextPaint;
                mTextPaint.setColor(Color.argb(0xFF, 0xBB, 0xBB, 0xBB));
            }
            paint.getTextBounds(mIndicators[i], 0, mIndicators[i].length(), mTextRect);
            String text = mIndicators[i];
            canvas.drawText(text, x - mTextRect.width() / 2, getHeight() / 3, paint);
        }
    }

    /**
     * 绘制thumb
     *
     * @param canvas
     */
    private void drawThumb(Canvas canvas) {
        Bitmap bitmap = mLightBitmap;
        mThumbX = getThumbX(mPosition);
        if (bitmap != null) {
            canvas.drawBitmap(bitmap, mThumbX - bitmap.getWidth() / 2, getHeight() * 2 / 3 - bitmap.getHeight() / 2, null);
        }
    }

    @Override
    protected void onRestoreInstanceState(Parcelable state) {
        if (!(state instanceof Bundle)) {
            super.onRestoreInstanceState(state);
            return;
        }
        Bundle bundle = (Bundle) state;
        mLightBitmap = bundle.getParcelable("bitmap");
        mText = bundle.getString("indicators");
        mPosition = bundle.getInt("position");
        mThumbX = bundle.getFloat("thumbX");
        mType = bundle.getInt("mType");
        mTrackHeight = bundle.getInt("trackHeight");
        super.onRestoreInstanceState(bundle.getParcelable("instance"));
    }

    //##### 对外公布的方法###########################//

    @Override
    protected Parcelable onSaveInstanceState() {

        Bundle bundle = new Bundle();
        bundle.putParcelable("bitmap", mLightBitmap);
        bundle.putInt("position", mPosition);
        bundle.putString("indicators", mText);
        bundle.putFloat("thumbX", mThumbX);
        bundle.putInt("mType", mType);
        bundle.putInt("trackHeight", mTrackHeight);
        bundle.putParcelable("instance", super.onSaveInstanceState());
        return bundle;
    }

    public void setPosition(int position) {
        mPosition = position;
        invalidate();
    }

    public void setLightColor(Context context, int resId, int color) {
        Bitmap bitmap = BitmapFactory.decodeResource(context.getResources(), resId);
        mLightBitmap = bitmap;
        mLightColor = color;
        invalidate();
    }

    public void setOnPositionChangedListener(OnPositionChangedListener listener) {
        mListener = listener;
    }

    @Override
    public void setEnabled(boolean enabled) {
        if (!enabled) {
            setPosition(0);
            setLightColor(mContext, R.mipmap.fsk_thumb_black, Color.parseColor("#bbbbbb"));
        }
        super.setEnabled(enabled);
    }


    public interface OnPositionChangedListener {
        void onPositionChange(int position);
    }
}
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值