美文网首页
Android 自定义尺子

Android 自定义尺子

作者: 层林尽染lr | 来源:发表于2018-05-11 13:04 被阅读0次

开始之前bb几句,虽然现在已经有类似的开源项目,但如果想真正理解它,还是要自己去手写一下,这不,趁着这两天空闲,公司项目不忙,就自己写了个demo,基本功能已完成,可能会有bug,回头再优化。

先说一下基本思路:

1.先创建一个类,继承View,先把刻度画出来。

2.再创建一个类,继承ViewGroup,这个类主要是控制内部尺子的滚动。

下面直接贴代码:

RulerView:

public class RulerView extends View {

    private Paint mPaint;

    private Path path;
    private String color = "#FF4081";
    //尺子Y轴水平基点
    private int startYDraw;
    //矫正刻度起始位置
    private float firststep = 0;
    //每个刻度起始位置
    private float cachStep = 0;
    //尺子长度
    private int ruleSize = 501;
    //一屏幕的刻度数
    private int viewAll = 60;
    private NumListener numListener;

    private boolean isScrowComplent = false;

    public RulerView(Context context) {
        super(context);
        initView();
    }

    public RulerView(Context context, @Nullable AttributeSet attrs) {
        super(context, attrs);
        initView();
    }

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


    private void initView() {
        mPaint = new Paint();
        path = new Path();
        mPaint.setStyle(Paint.Style.FILL);
        mPaint.setStrokeWidth(2);
        mPaint.setColor(Color.parseColor(color));
        mPaint.setTextAlign(Paint.Align.CENTER);
        mPaint.setTextSize(35);
    }


    protected void setScrowComplent(boolean isScrowComplent) {
        this.isScrowComplent = isScrowComplent;
        invalidate();
    }

    /**
     * 滚动时调用(给RuleViewGroup调用,不要私自调用)
     *
     * @param changeX
     */
    protected void setChangeX(float changeX) {
        firststep = firststep + changeX;
        invalidate();
    }


    /**
     * 手动输入时,设置当前刻度值
     *
     * @param rule
     */
    public void setNowRule(int rule) {
        firststep = getWidth() / 2 - (getWidth() / viewAll * rule);
        invalidate();
    }

    @Override
    protected void onDraw(Canvas canvas) {
        super.onDraw(canvas);

        startYDraw = (getHeight() / 2 - 20);

        path.moveTo(getWidth() / 2, (startYDraw));
        path.lineTo((getWidth() / 2) + 10, (startYDraw) - 30);
        path.lineTo((getWidth() / 2) - 10, (startYDraw) - 30);
        path.lineTo(getWidth() / 2, (startYDraw));
        canvas.drawPath(path, mPaint);


        //当起始位置超过中点时,则切换为中点,这样起始位置就不会跨过中点
        if (firststep > getWidth() / 2) {
            firststep = getWidth() / 2;
        }


        //-((getWidth()/viewAll)*(ruleSize-1)-(getWidth()/2))的计算结果为终点滑到中点时,起始位置的结果,
        // 控制器不要超过此点,能保证终点不划过中点
        if (firststep <= -((getWidth() / viewAll) * (ruleSize - 1) - (getWidth() / 2))) {
            firststep = -((getWidth() / viewAll) * (ruleSize - 1) - (getWidth() / 2));
        }

        cachStep = firststep;
        for (int i = 0; i < ruleSize; i++) {

            if ((i % 5) == 0) {
                canvas.drawLine(cachStep, startYDraw, cachStep, (startYDraw) + 80, mPaint);
                canvas.drawText(i + "", cachStep, (startYDraw) + 120, mPaint);
            } else {
                canvas.drawLine(cachStep, startYDraw, cachStep, (startYDraw) + 55, mPaint);
            }

            //当前刻度在中点
            if (cachStep <= (getWidth() / 2) && (cachStep + (getWidth() / viewAll)) >= (getWidth() / 2)) {
                if (null != numListener) {
                    numListener.getnum(i);

                    //滚动完成
                    if (isScrowComplent) {
                        if(cachStep+(getWidth() / viewAll/2)>=(getWidth() / 2)){
                            setChangeX((getWidth() / 2)-cachStep);
                        }else{
                            setChangeX((getWidth() / 2)-(getWidth() / viewAll)-cachStep);
                        }
                    }
                }
            }
            cachStep = cachStep + (getWidth() / viewAll);
        }
    }

    public void setNumListener(NumListener numListener) {
        this.numListener = numListener;
    }

    public interface NumListener {
        void getnum(int num);
    }
}

RulerViewGroup:

public class RulerViewGroup extends RelativeLayout implements Runnable {

    private VelocityTracker mVelocityTracker;
    //手指离开时的滚动速度
    private float velocityX;
    //当前的触摸点的X值
    private float nowtouchX = 0;
    //加速度
    private int speedAdd = 1;
    //单位时间
    private int unitTime = 5;
    //手指滑动方向
    private boolean isLeft = false;

    public RulerViewGroup(Context context) {
        super(context);
        intView();
    }

    public RulerViewGroup(Context context, AttributeSet attrs) {
        super(context, attrs);
        intView();
    }

    public RulerViewGroup(Context context, AttributeSet attrs, int defStyleAttr) {
        super(context, attrs, defStyleAttr);
        intView();
    }


    private void intView() {

    }


    @Override
    public boolean onTouchEvent(MotionEvent event) {
        if (mVelocityTracker == null) {
            mVelocityTracker = VelocityTracker.obtain();
        }
        boolean eventAddedToVelocityTracker = false;
        final MotionEvent vtev = MotionEvent.obtain(event);


        switch (event.getAction()) {
            case MotionEvent.ACTION_DOWN:
                nowtouchX = event.getX();
                break;

            case MotionEvent.ACTION_MOVE:
                ((RulerView) getChildAt(0)).setScrowComplent(false);
                try {
                    ((RulerView) getChildAt(0)).setChangeX((event.getX() - nowtouchX));
                    Log.e("ChangeX", (event.getX() - nowtouchX) + "");
                    nowtouchX = event.getX();
                } catch (Exception e) {
                    Log.e("RuleViewGroup", "布局错误");
                }


                //计算实时滑动速度
                mVelocityTracker.addMovement(vtev);
                eventAddedToVelocityTracker = true;
                mVelocityTracker.computeCurrentVelocity(unitTime, 1000);
                velocityX = mVelocityTracker.getXVelocity(event.getPointerId(0));

                //用于run方法判断加速度的正负
                if (velocityX >= 0) {
                    isLeft = false;
                } else {
                    isLeft = true;
                }

                break;

            case MotionEvent.ACTION_UP:
                //启动惯性滚动
                postDelayed(this, unitTime);
                break;

            case MotionEvent.ACTION_CANCEL:
                releaseVelocityTracker();
                break;

            default:
                break;
        }

        if (!eventAddedToVelocityTracker) {
            mVelocityTracker.addMovement(vtev);
        }
        vtev.recycle();
        return true;
    }


    @Override
    public void run() {
        int x = (int) (velocityX * unitTime / 5);

        if (isLeft) {
            velocityX = velocityX + speedAdd;
            if (velocityX >= 0) {
                velocityX = 0;
            }
        } else {
            velocityX = velocityX - speedAdd;
            if (velocityX <= 0) {
                velocityX = 0;
            }
        }
        
        try {
            ((RulerView) getChildAt(0)).setChangeX(x);
        } catch (Exception e) {
            Log.e("RuleViewGroup", "布局错误");
        }
        
        if (velocityX != 0) {
            postDelayed(this, unitTime);
        } else {

            try {
                ((RulerView) getChildAt(0)).setScrowComplent(true);
            } catch (Exception e) {
                Log.e("RuleViewGroup", "布局错误");
            }
        }
    }


    //释放VelocityTracker
    private void releaseVelocityTracker() {
        if (null != mVelocityTracker) {
            mVelocityTracker.clear();
            mVelocityTracker.recycle();
            mVelocityTracker = null;
        }
    }
}

下面是布局文件:

<?xml version="1.0" encoding="utf-8"?>
<LinearLayout xmlns:android="http://schemas.android.com/apk/res/android"
    android:layout_width="match_parent"
    android:layout_height="match_parent"
    android:orientation="vertical">

    <LinearLayout
        android:layout_width="match_parent"
        android:layout_height="wrap_content"
        android:orientation="horizontal">

        <EditText
            android:id="@+id/num"
            android:layout_width="0dp"
            android:layout_height="wrap_content"
            android:layout_weight="1"
            android:hint="请输入刻度值"
            android:inputType="number"
            android:text=""
            android:textSize="20dp" />

        <TextView
            android:id="@+id/setnum"
            android:layout_width="0dp"
            android:layout_height="wrap_content"
            android:layout_weight="1"
            android:inputType="number"
            android:text=""
            android:textSize="30dp" />

        <Button
            android:id="@+id/submit"
            android:layout_width="100dp"
            android:layout_height="wrap_content"
            android:text="提交" />

    </LinearLayout>


    <com.example.myapplication.touch.RulerViewGroup
        android:layout_width="match_parent"
        android:layout_height="200dp">

        <com.example.myapplication.touch.RulerView
            android:id="@+id/ruler"
            android:layout_width="match_parent"
            android:layout_height="wrap_content"
            android:layout_centerInParent="true" />

    </com.example.myapplication.touch.RulerViewGroup>
</LinearLayout>

以上代码放到项目里可以直接用

image.png

相关文章

网友评论

      本文标题:Android 自定义尺子

      本文链接:https://www.haomeiwen.com/subject/aydfdftx.html