Andoird 仿某理财APP自定义尺子控件

模仿某理财界面做了一个类似尺子的控件

 

步骤:
1,重写三个构造方法
2,用画笔和canvas分别画三种线条(底部线条,当前刻度,所有刻度)
3,重写 onTouchEvent,根据移动的距离重绘
4,设置手势识别器从而增加滚动惯性,滚动的时候用handler重绘控件
5,设置回调让主界面实时更新选中的刻度。

Talk is cheap,show you my code.

自定义尺子代码:

package com.ouyang.qqui.view;
import android.content.Context;
import android.graphics.Canvas;
import android.graphics.Color;
import android.graphics.Paint;
import android.os.Handler;
import android.os.Message;
import android.util.AttributeSet;
import android.util.Log;
import android.view.GestureDetector;
import android.view.MotionEvent;
import android.view.View;
import android.widget.Scroller;

/**
 * Create by oy 2017/8/15 15:35.
 */

public class Ruler extends View {
    //画笔
    //底部
    private Paint mBorderPaint = new Paint();
    //刻度
    private Paint mScaleMarkPaint = new Paint();
    //当前
    private Paint mCurrentMarkPaint = new Paint();
    //高
    private int mViewHeight;
    //宽
    private int mViewWidth;
    //每份的宽度
    private int partWith;
    //中间数
    private int mCenterNum;
    //最后按下的X坐标
    private float mLastDownX;

    private Context context;
    private Scroller scroller;
    private GestureDetector gestureDetector;

    public interface OnChangeListener{
        void  onChange(int mCenterNum);
    }
    private OnChangeListener onChangeListener;
    public void setOnChangeListener(OnChangeListener onChangeListener){
        this.onChangeListener = onChangeListener;
    }


    private int ON_FLING = 1;
    private Handler handler = new Handler(){
        @Override
        public void handleMessage(Message msg) {
            //判断是否滚动完成,true说明滚动尚未完成
            boolean isFinished = scroller.computeScrollOffset();
            //获取mScroller当前水平滚动的位置
            int curX = scroller.getCurrX();
            float v = (curX - mLastDownX)/partWith;
            mLastDownX = curX;
            //设置中间数然后重绘
            mCenterNum +=v;
            invalidate();
            if(isFinished){
                //未完成就一直重绘
                handler.sendEmptyMessage(ON_FLING);
            }
        }
    };
    private float distanceX;

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

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

    public Rule(Context context, AttributeSet attrs, int defStyleAttr) {
        super(context, attrs, defStyleAttr);
        //初始化view
        this.context = context;
        initView();
    }

    private void initView() {
        gestureDetector = new GestureDetector(context, simpleOnGestureListener);
        gestureDetector.setIsLongpressEnabled(false);
        scroller = new Scroller(context);

        //设置底部画笔
        mBorderPaint.setColor(Color.GRAY);
        mBorderPaint.setStyle(Paint.Style.STROKE);
        mBorderPaint.setStrokeWidth(2);

        //所有刻度
        mScaleMarkPaint.setColor(Color.GRAY);
        mScaleMarkPaint.setStyle(Paint.Style.FILL);
        mScaleMarkPaint.setStrokeWidth(3);
        mScaleMarkPaint.setTextSize(20);

        //当前刻度
        mCurrentMarkPaint.setColor(0xfffca23a);
        mCurrentMarkPaint.setStyle(Paint.Style.FILL);
        mCurrentMarkPaint.setStrokeWidth(3);
        mCurrentMarkPaint.setTextSize(20);
    }

    //手势识别器
    private GestureDetector.SimpleOnGestureListener simpleOnGestureListener = new GestureDetector.SimpleOnGestureListener(){
        @Override
        public boolean onScroll(MotionEvent e1, MotionEvent e2, float distanceX, float distanceY) {
            return true;
        }

        @Override
        public boolean onFling(MotionEvent e1, MotionEvent e2, float velocityX, float velocityY) {
            //最大和最小的整型数 int
            final int minX = -0x7fffffff;
            final int maxX = 0x7fffffff;
            //惯性滑动
            //指定起点(startX,startY),滑动(velocityX,velocityY),最大和最小坐标
            //fling(int startX, int startY, int velocityX, int velocityY,
            // int minX, int maxX, int minY, int maxY):
            //设置滚动惯性
            scroller.fling(0, 0, (int)-velocityX, 0, minX, maxX, 0, 0);
            //根据惯性重绘界面
            handler.sendEmptyMessage(ON_FLING);
            mLastDownX = 0;
            return true;
        }
    };

    @Override
    protected void onMeasure(int widthMeasureSpec, int heightMeasureSpec) {
        super.onMeasure(widthMeasureSpec, heightMeasureSpec);
        //获取view的宽高,作为绘制线条用
        mViewHeight = getMeasuredHeight();
        mViewWidth = getMeasuredWidth();
    }

    @Override
    protected void onDraw(Canvas canvas) {
        super.onDraw(canvas);
        //限制范围
        int maxNum = 1000;
        int minNum = -1000;
        if (mCenterNum>maxNum){
            mCenterNum = maxNum;
        }else if (mCenterNum<minNum){
            mCenterNum = minNum;
        }
        //绘制底部线条
        drawBottomLine(canvas);
        //绘制刻度
        drawScaleLine(canvas);
        //绘制当前刻度
        drawCurrentLine(canvas);
    }

    private void drawCurrentLine(Canvas canvas) {
        //绘制当前刻度
        canvas.drawLine(mViewWidth/2, mViewHeight,mViewWidth/2, mViewHeight-25, mCurrentMarkPaint);
    }

    private void drawScaleLine(Canvas canvas) {
        //总刻度为-10到110,左边绘制完了绘制右边
        //将总长度绘制为20等份,然后每隔10份绘制一条长的
        partWith = (mViewWidth-30)/30;
        //最小值为-10,最大值为100,计数器为count
        int count = 0;
        //左边距
        int left = mViewWidth/2;
        while (left>0){
            //左边距等于中间宽度减去距离*数量
            left = mViewWidth/2 - partWith * count;
            //左边数字等于中间数字减去数量
            int leftNum = mCenterNum - count;
            String leftText = String.valueOf(leftNum);
            if(leftNum % 10 == 0) {
                //线条
                canvas.drawLine(left, mViewHeight - 25, left, mViewHeight - 1, mScaleMarkPaint);
                //文字
                canvas.drawText(leftText,left-3, mViewHeight -35, mCurrentMarkPaint);
            }else {
                //线条
                canvas.drawLine(left, mViewHeight  - 10, left, mViewHeight - 1, mScaleMarkPaint);
            }
            count++;
        }
        count = 0;
        int right = mViewWidth/2;
        while (right < mViewWidth ){
            //右边距
            right =  mViewWidth/2  + partWith * count;
            //右边数字
            int rightNum = mCenterNum + count;
            String rightText = String.valueOf(rightNum);
            if(rightNum % 10 == 0) {
                //线条
                canvas.drawLine(right, mViewHeight - 25, right, mViewHeight - 1, mScaleMarkPaint);
                //文字
                canvas.drawText(rightText,right-3, mViewHeight -35, mCurrentMarkPaint);
            }else {
                canvas.drawLine(right, mViewHeight  - 10, right, mViewHeight - 1, mScaleMarkPaint);
            }
            count++;
        }
        if (onChangeListener!=null){
            onChangeListener.onChange(mCenterNum);
        }
    }

    private void drawBottomLine(Canvas canvas) {
        //绘制底部线条,高度不变,宽度从0到view的总宽
        canvas.drawLine(0, mViewHeight, mViewWidth, mViewHeight, mBorderPaint);
    }


    //重写触摸事件
    @Override
    public boolean onTouchEvent(MotionEvent event) {
        switch (event.getActionMasked()) {
            case MotionEvent.ACTION_DOWN:
                //强制结束本次滑屏操作
                scroller.forceFinished(true);
                mLastDownX =(int) event.getX();
                break;
            case MotionEvent.ACTION_MOVE:
                //随着移动而重绘
                float moveX =  event.getX();
                //移动的距离叠加
                distanceX += (moveX - mLastDownX)/partWith;
                mLastDownX = moveX;
                //当移动的距离大于1或小于-1的时候移动一格
                if (distanceX >1|| distanceX <-1){
                    mCenterNum -= (int) distanceX;
                    distanceX = 0;
                }
                invalidate();
                break;
        }
        //调用手势识别器的触摸监听是为了增加滑动惯性
        gestureDetector.onTouchEvent(event);
        return true;
    }
}

主界面布局代码:
<?xml version="1.0" encoding="utf-8"?>
<RelativeLayout xmlns:android="http://schemas.android.com/apk/res/android"
    xmlns:materialdesign="http://schemas.android.com/apk/res-auto"
    android:id="@+id/activity_main"
    android:layout_width="match_parent"
    android:layout_height="match_parent"
    >
    <com.ouyang.qqui.view.Ruler
        android:id="@+id/ruler"
        android:layout_alignParentBottom="true"
        android:layout_width="match_parent"
        android:layout_height="30dp"
        android:layout_marginBottom="50dp"/>
     <TextView
        android:id="@+id/tv_ruler"
        android:layout_width="wrap_content"
        android:layout_alignParentBottom="true"
        android:layout_centerHorizontal="true"
        android:layout_height="wrap_content"
        android:textSize="15sp"
        android:text=""
        android:layout_marginBottom="20dp"/>
</RelativeLayout>

主界面回调更新刻度代码:
ruler.setOnChangeListener(new Ruler.OnChangeListener() {
            @Override
            public void onChange(int mCenterNum) {
                String s = "我要出借"+mCenterNum+"元";
                tvRule.setText(s);
            }
        });




  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值