自定义设置刻度控件ScaleView的讲解

来源:互联网 发布:xtw100编程器使用说明 编辑:程序博客网 时间:2024/06/05 19:48

1.ScaleView的简介

        ScaleView是一个可以设置身高,体重参数的自定义控件,其中也在github上开源,并被广为流传。因为公司最近的项目里要实现这样的需求,今天我就带着大家学习一下这个自定义控件。先上效果图:

2.ScaleView的用法

1.创建自定义BaseScaleView
public abstract class BaseScaleView extends View {    public static final int[] ATTR = {            R.attr.scale_view_min,            R.attr.scale_view_max,            R.attr.scale_view_margin,            R.attr.scale_view_height,    };    public static final int SCALE_MIN = 0;    public static final int SCALE_MAX = 1;    public static final int SCALE_MARGIN = 2;    public static final int SCALE_HEIGHT = 3;    protected int mMax; //最大刻度    protected int mMin; // 最小刻度    protected int mCountScale; //滑动的总刻度    protected int mScaleScrollViewRange;    protected int mScaleMargin; //刻度间距    protected int mScaleHeight; //刻度线的高度    protected int mScaleMaxHeight; //整刻度线高度    protected int mRectWidth; //总宽度    protected int mRectHeight; //高度    protected Scroller mScroller;    protected int mScrollLastX;    protected int mTempScale; // 用于判断滑动方向    protected int mMidCountScale; //中间刻度    protected OnScrollListener mScrollListener;    public interface OnScrollListener {        void onScaleScroll(int scale);    }    public BaseScaleView(Context context) {        super(context);        init(null);    }    public BaseScaleView(Context context, AttributeSet attrs) {        super(context, attrs);        init(attrs);    }    public BaseScaleView(Context context, AttributeSet attrs, int defStyleAttr) {        super(context, attrs, defStyleAttr);        init(attrs);    }    @TargetApi(Build.VERSION_CODES.LOLLIPOP)    public BaseScaleView(Context context, AttributeSet attrs, int defStyleAttr, int defStyleRes) {        super(context, attrs, defStyleAttr, defStyleRes);        init(attrs);    }    protected void init(AttributeSet attrs) {        // 获取自定义属性        TypedArray ta = getContext().obtainStyledAttributes(attrs, ATTR);        mMin = ta.getInteger(SCALE_MIN, 0);        mMax = ta.getInteger(SCALE_MAX, 200);        mScaleMargin = ta.getDimensionPixelOffset(SCALE_MARGIN, 15);        mScaleHeight = ta.getDimensionPixelOffset(SCALE_HEIGHT, 20);        ta.recycle();        mScroller = new Scroller(getContext());        initVar();    }    @Override    protected void onDraw(Canvas canvas) {        // 画笔        Paint paint = new Paint();        paint.setColor(Color.GRAY);        // 抗锯齿        paint.setAntiAlias(true);        // 设定是否使用图像抖动处理,会使绘制出来的图片颜色更加平滑和饱满,图像更加清晰        paint.setDither(true);        // 空心        paint.setStyle(Paint.Style.STROKE);        // 文字居中        paint.setTextAlign(Paint.Align.CENTER);        onDrawLine(canvas, paint);        onDrawScale(canvas, paint); //画刻度        onDrawPointer(canvas, paint); //画指针        super.onDraw(canvas);    }    protected abstract void initVar();    // 画线    protected abstract void onDrawLine(Canvas canvas, Paint paint);    // 画刻度    protected abstract void onDrawScale(Canvas canvas, Paint paint);    // 画指针    protected abstract void onDrawPointer(Canvas canvas, Paint paint);    /**     * 使用Scroller时需重写     */    @Override    public void computeScroll() {        super.computeScroll();        // 判断Scroller是否执行完毕        if (mScroller.computeScrollOffset()) {            scrollTo(mScroller.getCurrX(), mScroller.getCurrY());            // 通过重绘来不断调用computeScroll            invalidate();        }    }    public void smoothScrollBy(int dx, int dy) {        mScroller.startScroll(mScroller.getFinalX(), mScroller.getFinalY(), dx, dy);    }    public void smoothScrollTo(int fx, int fy) {        int dx = fx - mScroller.getFinalX();        int dy = fy - mScroller.getFinalY();        smoothScrollBy(dx, dy);    }    /**     * 设置回调监听     *     * @param listener     */    public void setOnScrollListener(OnScrollListener listener) {        this.mScrollListener = listener;    }}
2.创建自定义HorizontalScrollScaleView
public class HorizontalScaleScrollView extends BaseScaleView {    public HorizontalScaleScrollView(Context context) {        super(context);    }    public HorizontalScaleScrollView(Context context, AttributeSet attrs) {        super(context, attrs);    }    public HorizontalScaleScrollView(Context context, AttributeSet attrs, int defStyleAttr) {        super(context, attrs, defStyleAttr);    }    public HorizontalScaleScrollView(Context context, AttributeSet attrs, int defStyleAttr, int defStyleRes) {        super(context, attrs, defStyleAttr, defStyleRes);    }    @Override    protected void initVar() {        mRectWidth = (mMax - mMin) * mScaleMargin;        mRectHeight = mScaleHeight * 8;        mScaleMaxHeight = mScaleHeight * 2;        // 设置layoutParams        ViewGroup.MarginLayoutParams lp = new ViewGroup.MarginLayoutParams(mRectWidth, mRectHeight);        this.setLayoutParams(lp);    }    @Override    protected void onMeasure(int widthMeasureSpec, int heightMeasureSpec) {        int height=MeasureSpec.makeMeasureSpec(mRectHeight, MeasureSpec.AT_MOST);        super.onMeasure(widthMeasureSpec, height);        mScaleScrollViewRange = getMeasuredWidth();        mTempScale = mScaleScrollViewRange / mScaleMargin / 2 + mMin;        mMidCountScale = mScaleScrollViewRange / mScaleMargin / 2 + mMin;    }    @Override    protected void onDrawLine(Canvas canvas, Paint paint) {        canvas.drawLine(0, mRectHeight, mRectWidth, mRectHeight, paint);    }    @Override    protected void onDrawScale(Canvas canvas, Paint paint) {        paint.setTextSize(mRectHeight / 4);        for (int i = 0, k = mMin; i <= mMax - mMin; i++) {            if (i % 10 == 0) { //整值                canvas.drawLine(i * mScaleMargin, mRectHeight, i * mScaleMargin, mRectHeight - mScaleMaxHeight, paint);                //整值文字                canvas.drawText(String.valueOf(k), i * mScaleMargin, mRectHeight - mScaleMaxHeight - 20, paint);                k += 10;            } else {                canvas.drawLine(i * mScaleMargin, mRectHeight, i * mScaleMargin, mRectHeight - mScaleHeight, paint);            }        }    }    @Override    protected void onDrawPointer(Canvas canvas, Paint paint) {        paint.setColor(Color.RED);        //每一屏幕刻度的个数/2        int countScale = mScaleScrollViewRange / mScaleMargin / 2;        //根据滑动的距离,计算指针的位置【指针始终位于屏幕中间】        int finalX = mScroller.getFinalX();        //滑动的刻度        int tmpCountScale = (int) Math.rint((double) finalX / (double) mScaleMargin); //四舍五入取整        //总刻度        mCountScale = tmpCountScale + countScale + mMin;        if (mScrollListener != null) { //回调方法            mScrollListener.onScaleScroll(mCountScale);        }        canvas.drawLine(countScale * mScaleMargin + finalX, mRectHeight,                countScale * mScaleMargin + finalX, mRectHeight - mScaleMaxHeight - mScaleHeight, paint);    }    @Override    public boolean onTouchEvent(MotionEvent event) {        int x = (int) event.getX();        switch (event.getAction()) {            case MotionEvent.ACTION_DOWN:                if (mScroller != null && !mScroller.isFinished()) {                    mScroller.abortAnimation();                }                mScrollLastX = x;                return true;            case MotionEvent.ACTION_MOVE:                int dataX = mScrollLastX - x;                if (mCountScale - mTempScale < 0) { //向右边滑动                    if (mCountScale <= mMin && dataX <= 0) //禁止继续向右滑动                        return super.onTouchEvent(event);                } else if (mCountScale - mTempScale > 0) { //向左边滑动                    if (mCountScale >= mMax && dataX >= 0) //禁止继续向左滑动                        return super.onTouchEvent(event);                }                smoothScrollBy(dataX, 0);                mScrollLastX = x;                postInvalidate();                mTempScale = mCountScale;                return true;            case MotionEvent.ACTION_UP:                if (mCountScale < mMin) mCountScale = mMin;                if (mCountScale > mMax) mCountScale = mMax;                int finalX = (mCountScale - mMidCountScale) * mScaleMargin;                mScroller.setFinalX(finalX); //纠正指针位置                postInvalidate();                return true;        }        return super.onTouchEvent(event);    }}
3.创建自定义VerticalSrollScaleView
public class VerticalScaleScrollView extends BaseScaleView {    public VerticalScaleScrollView(Context context) {        super(context);    }    public VerticalScaleScrollView(Context context, AttributeSet attrs) {        super(context, attrs);    }    public VerticalScaleScrollView(Context context, AttributeSet attrs, int defStyleAttr) {        super(context, attrs, defStyleAttr);    }    @TargetApi(Build.VERSION_CODES.LOLLIPOP)    public VerticalScaleScrollView(Context context, AttributeSet attrs, int defStyleAttr, int defStyleRes) {        super(context, attrs, defStyleAttr, defStyleRes);    }    @Override    protected void initVar() {        mRectHeight = (mMax - mMin) * mScaleMargin;        mRectWidth = mScaleHeight * 8;        mScaleMaxHeight = mScaleHeight * 2;        // 设置layoutParams        ViewGroup.MarginLayoutParams lp = new ViewGroup.MarginLayoutParams(mRectWidth, mRectHeight);        this.setLayoutParams(lp);    }    @Override    protected void onMeasure(int widthMeasureSpec, int heightMeasureSpec) {//        int width = MeasureSpec.makeMeasureSpec(mRectWidth, MeasureSpec.AT_MOST);        super.onMeasure(widthMeasureSpec, heightMeasureSpec);        mScaleScrollViewRange = getMeasuredHeight();        mTempScale = mScaleScrollViewRange / mScaleMargin / 2 + mMin;        mMidCountScale = mScaleScrollViewRange / mScaleMargin / 2 + mMin;    }    @Override    protected void onDrawLine(Canvas canvas, Paint paint) {        canvas.drawLine(0, 0, 0, mRectHeight, paint);    }    @Override    protected void onDrawScale(Canvas canvas, Paint paint) {        paint.setTextSize(mRectWidth / 4);        for (int i = 0, k = mMin; i <= mMax - mMin; i++) {            if (i % 10 == 0) { //整值                canvas.drawLine(0, i * mScaleMargin, mScaleMaxHeight, i * mScaleMargin, paint);                //整值文字                canvas.drawText(String.valueOf(k), mScaleMaxHeight + 40, i * mScaleMargin + paint.getTextSize() / 3, paint);                k += 10;            } else {                canvas.drawLine(0, i * mScaleMargin, mScaleHeight, i * mScaleMargin, paint);            }        }    }    @Override    protected void onDrawPointer(Canvas canvas, Paint paint) {        paint.setColor(Color.RED);        //每一屏幕刻度的个数/2        int countScale = mScaleScrollViewRange / mScaleMargin / 2;        //根据滑动的距离,计算指针的位置【指针始终位于屏幕中间】        int finalY = mScroller.getFinalY();        //滑动的刻度        int tmpCountScale = (int) Math.rint((double) finalY / (double) mScaleMargin); //四舍五入取整        //总刻度        mCountScale = tmpCountScale + countScale + mMin;        if (mScrollListener != null) { //回调方法            mScrollListener.onScaleScroll(mCountScale);        }        canvas.drawLine(0, countScale * mScaleMargin + finalY,                mScaleMaxHeight + mScaleHeight, countScale * mScaleMargin + finalY, paint);    }    @Override    public boolean onTouchEvent(MotionEvent event) {        int y = (int) event.getY();        switch (event.getAction()) {            case MotionEvent.ACTION_DOWN:                if (mScroller != null && !mScroller.isFinished()) {                    mScroller.abortAnimation();                }                mScrollLastX = y;                return true;            case MotionEvent.ACTION_MOVE:                int dataY = mScrollLastX - y;                if (mCountScale - mTempScale < 0) { //向下边滑动                    if (mCountScale <= mMin && dataY <= 0) //禁止继续向下滑动                        return super.onTouchEvent(event);                } else if (mCountScale - mTempScale > 0) { //向上边滑动                    if (mCountScale >= mMax && dataY >= 0) //禁止继续向上滑动                        return super.onTouchEvent(event);                }                smoothScrollBy(0, dataY);                mScrollLastX = y;                postInvalidate();                mTempScale = mCountScale;                return true;            case MotionEvent.ACTION_UP:                if (mCountScale < mMin) mCountScale = mMin;                if (mCountScale > mMax) mCountScale = mMax;                int finalY = (mCountScale - mMidCountScale) * mScaleMargin;                mScroller.setFinalY(finalY); //纠正指针位置                postInvalidate();                return true;        }        return super.onTouchEvent(event);    }}
4.Manifest文件申明
<?xml version="1.0" encoding="utf-8"?><RelativeLayout xmlns:android="http://schemas.android.com/apk/res/android"    xmlns:tools="http://schemas.android.com/tools"    android:layout_width="match_parent"    android:layout_height="match_parent"    xmlns:app="http://schemas.android.com/apk/res-auto"    android:paddingLeft="@dimen/activity_horizontal_margin"    android:paddingRight="@dimen/activity_horizontal_margin"    android:paddingTop="@dimen/activity_vertical_margin"    android:paddingBottom="@dimen/activity_vertical_margin"    tools:context="com.lichfaker.views.scaleview.MainActivity">    <com.lichfaker.scaleview.HorizontalScaleScrollView        android:id="@+id/horizontalScale"        android:layout_centerHorizontal="true"        android:layout_below="@+id/horizontalScaleValue"        android:layout_width="wrap_content"        android:layout_height="wrap_content"        android:layout_marginTop="10dp"        app:scale_view_max="200"        app:scale_view_min="20"        app:scale_view_height="8dip"        app:scale_view_margin="5dip"        />    <TextView        android:id="@+id/horizontalScaleValue"        android:layout_centerHorizontal="true"        tools:text="50"        android:textSize="16sp"        android:layout_width="wrap_content"        android:layout_height="wrap_content" />    <com.lichfaker.scaleview.VerticalScaleScrollView        android:id="@+id/verticalScale"        android:layout_below="@+id/horizontalScale"        android:layout_marginTop="60dp"        app:scale_view_max="200"        app:scale_view_min="20"        app:scale_view_height="8dip"        app:scale_view_margin="5dip"        android:layout_width="100dp"        android:layout_height="200dp" />    <TextView        android:id="@+id/verticalScaleValue"        android:layout_toRightOf="@+id/verticalScale"        android:layout_centerInParent="true"        android:layout_marginLeft="60dp"        tools:text="50"        android:textSize="16sp"        android:layout_width="wrap_content"        android:layout_height="wrap_content" /></RelativeLayout>
5.主界面MainActivity
public class MainActivity extends AppCompatActivity {    TextView mTvHorizontalScale;    TextView mTvVerticalScale;    @Override    protected void onCreate(Bundle savedInstanceState) {        super.onCreate(savedInstanceState);        setContentView(R.layout.activity_main);        mTvHorizontalScale = (TextView) findViewById(R.id.horizontalScaleValue);        HorizontalScaleScrollView scaleScrollView = (HorizontalScaleScrollView) findViewById(R.id.horizontalScale);        scaleScrollView.setOnScrollListener(new HorizontalScaleScrollView.OnScrollListener() {            @Override            public void onScaleScroll(int scale) {                mTvHorizontalScale.setText("" + scale);            }        });        mTvVerticalScale = (TextView) findViewById(R.id.verticalScaleValue);        VerticalScaleScrollView vScaleScrollView = (VerticalScaleScrollView) findViewById(R.id.verticalScale);        vScaleScrollView.setOnScrollListener(new HorizontalScaleScrollView.OnScrollListener() {            @Override            public void onScaleScroll(int scale) {                mTvVerticalScale.setText("" + scale);            }        });    }}
ok,这样自定义的设置刻度的控件就诞生了,有木有很兴奋!你可以直接把github中scaleview的mudule导入你的工程里面,然后引用该模块,这样开发起来更有效率,当然你可以好好研究一下底层源码,哈哈,好了,我是张星,欢迎您的关注,后期更精彩!源码地址:http://download.csdn.net/detail/zhangxing52077/9695038

1 0
原创粉丝点击