美文网首页Android自定义ViewiOS
自定义View仿iOS菜单栏箭头动画

自定义View仿iOS菜单栏箭头动画

作者: 贝贝beibei96 | 来源:发表于2018-05-07 12:08 被阅读247次

    这个是iOS菜单栏的箭头, 拖动的时候会有动画, 因为懒我就不上GIF图了


    iOS菜单栏箭头

    这个是我自定义模仿的View, 效果如下:


    ArrowView

    先做一波分析:
    附上一张分解图
    1.把1/2箭头X轴的长度把控件切分成四份, 箭头所占Y轴的长度切分成四份
    2.控件的高度是宽度的1/3
    3.图中直线明显看出是圆头
    4.确定每条直线的startX、startY、stopX、stopY, 注意因为为了更方便快捷控制弯曲程度所以控制点只有一个, 意思就是两条直线的stopX、stopY是同一个X、Y, 这样子只要改变这个点的Y参数就能达到改变弯曲程度了
    5.看图能看出左一直线的startX为控件宽度1/4、startY为控制高度2/4, 左二startX为控件宽度3/4、startY为控件高度2/4, stopX都为控件宽度2/4、stopY都为控件高度3/4


    分解

    分解完毕, 开始写代码:

    测量控件宽高, 经过调试较佳效果为高是宽的1/3

     @Override
        protected void onMeasure(int widthMeasureSpec, int heightMeasureSpec) {
            super.onMeasure(widthMeasureSpec, heightMeasureSpec);
            int size = MeasureSpec.getSize(widthMeasureSpec);
            // 高是宽的30%
            setMeasuredDimension(size, size / 3);
    
        }
    

    设置画笔线头形状为圆头

    // 设置线头形状为圆头
            mPaint.setStrokeCap(Paint.Cap.ROUND);
    

    确定X、Y位置

        @Override
        protected void onSizeChanged(int w, int h, int oldw, int oldh) {
            super.onSizeChanged(w, h, oldw, oldh);
            startX = w / 4;
            startY = h / 4;
            
            setStopX(startX * 2);
            setStopY(startY * 3);
    
        }
    

    绘制直线

       canvas.drawLine((float) startX, (float) startY * 2,
                    (float) getStopX(), (float) getStopY(), mPaint);
            canvas.drawLine((float) startX * 3, (float) startY * 2,
                    (float) getStopX(), (float) getStopY(), mPaint);
    

    滑动屏幕的时候会改变箭头的弯曲程度, 重写要滑动View的onTouchEvent事件

    /**
         * BottomView的触摸事件
         * 记得return true消费该事件
         */
        private class BottomViewOnTouchEvent implements OnTouchListener {
    
            int downY;
            // Y的距离差
            float distanceDifference;
    
            @SuppressLint("ClickableViewAccessibility")
            @Override
            public boolean onTouch(View v, MotionEvent event) {
                switch (event.getAction()) {
                    case MotionEvent.ACTION_DOWN:
                        downY = (int) event.getRawY();
    
                        break;
                    case MotionEvent.ACTION_MOVE:
                        // Y轴距离差
                        distanceDifference = event.getRawY() - downY;
                        // 箭头弯曲比例是屏幕宽度3.5
                        double ratio = width / 3.5;
    
                        // 判断手指是向下滑动
                        if (event.getRawY() > downY) {
                            // bottomView随手指移动
                            bottomView.layout(0, (int) (event.getRawY() - downY),
                                    width, (int) (height + (event.getRawY() - downY)));
    
                            // 箭头随手指移动改变弯曲率, 控制在最高点和最低点范围内移动
                            if ((ratio - distanceDifference) / 7 >= mArrowView.getStartY()
                                    && (ratio - distanceDifference) / 7 <= mArrowView.getStartY() * 3) {
                                mArrowView.setStopY((ratio - distanceDifference) / 7);
    
                            }
    
                        }
    
                        break;
                    case MotionEvent.ACTION_UP:
                        // Y轴距离差大于200, bottomView向下滑动收起
                        if (distanceDifference >= 200) {
                            bottomView.layout(0, height, width, height * 2);
                            roundView.layout(0, height, roundViewSize, roundViewSize + height);
                            mArrowView.setStopY(mArrowView.getStartY() * 3);
                            roundView.setVisibility(VISIBLE);
    
                            // 不大于200, 弹回顶部
                        } else {
                            bottomView.layout(0, 0, width, height);
                            mArrowView.setStopY(mArrowView.getStartY() * 3);
    
                        }
    
                        break;
                }
                return true;
            }
        }
    

    xml引用要注意不需要指定高度

     <cn.startrails.webb.widget.ArrowView
                    android:id="@+id/av_bottom"
                    android:layout_width="55dp"
                    android:layout_height="wrap_content"
                    app:layout_constraintLeft_toLeftOf="parent"
                    app:layout_constraintRight_toRightOf="parent"
                    app:layout_constraintTop_toTopOf="parent" />
    



    post上源码:

    package cn.startrails.webb.widget;
    
    import android.content.Context;
    import android.graphics.Canvas;
    import android.graphics.Color;
    import android.graphics.Paint;
    import android.support.annotation.Nullable;
    import android.util.AttributeSet;
    import android.view.View;
    
    /**
     * 箭头View
     * 建议xml中宽高为
     * android:layout_width="55dp"
     * android:layout_height="wrap_content"
     *
     * @author WebbLin(林恩)
     * @date 2018/5/5  17:49
     * @email Webb@starcc.cc
     */
    
    public class ArrowView extends View {
    
        private Paint mPaint;
        private double startX, startY, stopX, stopY;
    
    
        public ArrowView(Context context) {
            super(context);
            init();
    
        }
    
        public ArrowView(Context context, @Nullable AttributeSet attrs) {
            super(context, attrs);
            init();
    
        }
    
        public ArrowView(Context context, @Nullable AttributeSet attrs, int defStyleAttr) {
            super(context, attrs, defStyleAttr);
            init();
    
        }
    
        private void init() {
            mPaint = new Paint(Paint.ANTI_ALIAS_FLAG);
            // 设置笔划宽度
            mPaint.setStrokeWidth(12);
            // 设置线头形状为圆头
            mPaint.setStrokeCap(Paint.Cap.ROUND);
            mPaint.setColor(Color.parseColor("#808080"));
    
        }
    
    
        @Override
        protected void onSizeChanged(int w, int h, int oldw, int oldh) {
            super.onSizeChanged(w, h, oldw, oldh);
            startX = w / 4;
            startY = h / 4;
    
            setStopX(startX * 2);
            setStopY(startY * 3);
    
        }
    
    
        @Override
        protected void onDraw(Canvas canvas) {
            super.onDraw(canvas);
    
            canvas.drawLine((float) startX, (float) startY * 2,
                    (float) getStopX(), (float) getStopY(), mPaint);
            canvas.drawLine((float) startX * 3, (float) startY * 2,
                    (float) getStopX(), (float) getStopY(), mPaint);
    
        }
    
    
        @Override
        protected void onMeasure(int widthMeasureSpec, int heightMeasureSpec) {
            super.onMeasure(widthMeasureSpec, heightMeasureSpec);
            int size = MeasureSpec.getSize(widthMeasureSpec);
            // 高是宽的1/3
            setMeasuredDimension(size, size / 3);
    
        }
    
    
        public double getStartX() {
            return startX;
        }
    
        public void setStartX(double startX) {
            this.startX = startX;
        }
    
        public double getStartY() {
            return startY;
        }
    
        public void setStartY(double startY) {
            this.startY = startY;
        }
    
        public double getStopX() {
            return stopX;
        }
    
        public void setStopX(double stopX) {
            this.stopX = stopX;
            invalidate();
        }
    
        public double getStopY() {
            return stopY;
        }
    
        public void setStopY(double stopY) {
            this.stopY = stopY;
            invalidate();
        }
    
    }
    
    

    相关文章

      网友评论

        本文标题:自定义View仿iOS菜单栏箭头动画

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