zoukankan      html  css  js  c++  java
  • 仿IOS版QQ的下拉刷新头实现原理

    一直很好奇苹果版QQ的下拉刷新头,那种水滴状的感觉,特别有弹性的感觉,于是趁着项目比较松的时候也来实现一下,这是实现后的图


    最主要的要知道这个图形的画法,我使用的是Path路径来做的,然后使用填充画笔,把他全部填充

    主要使用两个半圆和两条二次曲线构成



    于是引入关键代码

    补充一下,path中绘制圆弧用的是arcTo方法,不仅可以绘制圆弧也可以绘制椭圆圆弧,传入矩形区域和角度变化即可,值得注意的是圆弧的方向,用法不当会导致曲线无法闭合。至于二次曲线就不说了

    protected void onDraw(Canvas canvas) {
            super.onDraw(canvas);
    
             //路径重置
            mPath.reset();
    
            //绘制大圆圆弧
            mPath.arcTo(new RectF(viewwdith / 2 - GreatCircleRadius, GreatCircleY - GreatCircleRadius,
                    viewwdith / 2 + GreatCircleRadius, GreatCircleY + GreatCircleRadius), 0, -180);
            //绘制左边的二次曲线
            mPath.quadTo(viewwdith / 2 - SmallCircleRadius, (GreatCircleY + SmallCircleY) / 2, viewwdith / 2 - SmallCircleRadius, SmallCircleY);
            //把点移动到大半圆的右边
            mPath.moveTo(viewwdith / 2 + GreatCircleRadius, GreatCircleY);
            //绘制右边的二次曲线
            mPath.quadTo(viewwdith / 2 + SmallCircleRadius, (GreatCircleY + SmallCircleY) / 2, viewwdith / 2 + SmallCircleRadius, SmallCircleY);
            //绘制小圆圆弧
            mPath.arcTo(new RectF(viewwdith / 2 - SmallCircleRadius, SmallCircleY - SmallCircleRadius,
                    viewwdith / 2 + SmallCircleRadius, SmallCircleY + SmallCircleRadius), 0, 180);
    
            canvas.drawPath(mPath, mPaint);
        }


    这就是主要的绘制方法,剩下的就好办啦,重写触摸事件,使他下拉时,移动小圆的圆心位置,并且根据两个圆的圆心距,改变两个圆的半径,初始时,两个园大小是一致的,随着距离的增大,小圆半径缩小的更快。当手抬起后,开启线程重置刷新头。


    下面是所有的代码:

    package com.example.kaifa.myapplication;
    
    import android.content.Context;
    import android.graphics.Canvas;
    import android.graphics.Paint;
    import android.graphics.Path;
    import android.graphics.RectF;
    import android.util.AttributeSet;
    import android.util.Log;
    import android.view.MotionEvent;
    import android.view.View;
    
    /**
     * TODO: document your custom view class.
     */
    public class MyView extends View {
    
    
        private Paint mPaint;
        /**
         * 下拉进度
         */
        private float progress = 0;
        /**
         * view的宽高
         */
        private int viewheight, viewwdith;
    
        /**
         * 大圆半径
         */
        private float GreatCircleRadius = 50;
        /**
         * 小圆半径
         */
        private float SmallCircleRadius = 50;
        /**
         * 大圆和小圆分别Y轴的坐标
         */
        private float GreatCircleY = 60, SmallCircleY = 60;
        /**
         * 绘制路径
         */
        private Path mPath;
        /**
         * 第一次按下的Y轴坐标
         */
        float firstY = 0;
    
        public MyView(Context context) {
            super(context);
            init(null, 0);
        }
    
        public MyView(Context context, AttributeSet attrs) {
            super(context, attrs);
            init(attrs, 0);
        }
    
        public MyView(Context context, AttributeSet attrs, int defStyle) {
            super(context, attrs, defStyle);
            init(attrs, defStyle);
        }
    
        private void init(AttributeSet attrs, int defStyle) {
            // Load attributes
            mPaint = new Paint();
            mPaint.setAntiAlias(true);
            mPaint.setColor(0xff0000ff);
            mPaint.setStyle(Paint.Style.FILL);
            mPath = new Path();
    
        }
    
        @Override
        protected void onSizeChanged(int w, int h, int oldw, int oldh) {
            super.onSizeChanged(w, h, oldw, oldh);
            viewwdith = w;
            viewheight = h;
    
        }
    
        @Override
        protected void onMeasure(int widthMeasureSpec, int heightMeasureSpec) {
            super.onMeasure(widthMeasureSpec, heightMeasureSpec);
        }
    
        @Override
        protected void onDraw(Canvas canvas) {
            super.onDraw(canvas);
    
             //路径重置
            mPath.reset();
    
            //绘制大圆圆弧
            mPath.arcTo(new RectF(viewwdith / 2 - GreatCircleRadius, GreatCircleY - GreatCircleRadius,
                    viewwdith / 2 + GreatCircleRadius, GreatCircleY + GreatCircleRadius), 0, -180);
            //绘制左边的二次曲线
            mPath.quadTo(viewwdith / 2 - SmallCircleRadius, (GreatCircleY + SmallCircleY) / 2, viewwdith / 2 - SmallCircleRadius, SmallCircleY);
            //把点移动到大半圆的右边
            mPath.moveTo(viewwdith / 2 + GreatCircleRadius, GreatCircleY);
            //绘制右边的二次曲线
            mPath.quadTo(viewwdith / 2 + SmallCircleRadius, (GreatCircleY + SmallCircleY) / 2, viewwdith / 2 + SmallCircleRadius, SmallCircleY);
            //绘制小圆圆弧
            mPath.arcTo(new RectF(viewwdith / 2 - SmallCircleRadius, SmallCircleY - SmallCircleRadius,
                    viewwdith / 2 + SmallCircleRadius, SmallCircleY + SmallCircleRadius), 0, 180);
    
            canvas.drawPath(mPath, mPaint);
        }
    
        @Override
        public boolean onTouchEvent(MotionEvent event) {
    
            switch (event.getAction()) {
                case MotionEvent.ACTION_DOWN:
                    firstY = event.getY();
                    break;
                case MotionEvent.ACTION_MOVE:
                    float dy = event.getY() - firstY;
                    if (Math.abs(dy) > 2 &&(SmallCircleY-GreatCircleY)<viewheight) {
                        if (dy<0&&SmallCircleY<GreatCircleY){
    
                        }else{
    
                            SmallCircleY = SmallCircleY + dy;
                            if (SmallCircleY<GreatCircleY)
                                SmallCircleY=GreatCircleY;
                        }
                        jisuanR();
                    }
                    firstY = event.getY();
                    Log.v("xingyun", "dy=" + dy);
                    invalidate();
                    break;
    
                case MotionEvent.ACTION_UP:
                    //开启线程匀速返回
                   new MyTread().start();
                    break;
    
            }
            return true;
        }
    
        /**
         * 根据下拉的距离来计算两个圆的半径
         */
        private void jisuanR(){
            float dy=SmallCircleY-GreatCircleY;
    
            progress=dy/(viewheight);
            SmallCircleRadius=(float)(50*(1-0.9*progress));
            GreatCircleRadius= (float) (50*(1-0.5*progress));
    
        }
    
        /**
         * 回弹的线程
         */
        class MyTread extends Thread{
            @Override
            public void run() {
                while (SmallCircleY-GreatCircleY>0){
                    SmallCircleY=SmallCircleY-10;
                    if (SmallCircleY<GreatCircleY){
                        SmallCircleY=GreatCircleY;
                    }
                    jisuanR();
                    postInvalidate();
                    try {
                        Thread.sleep(10);
                    } catch (InterruptedException e) {
                        e.printStackTrace();
                    }
    
                }
            }
        }
    
    
    }
    

    如想用用在下拉刷新处也是非常简单的,监听到下拉的距离,用此来设置圆心距即可、~

    如有问题,或者更好的实现方法也可以分享一下,谢谢~







  • 相关阅读:
    springboot注册为win服务特别简单
    mybatis-generator 自动生成代码
    springboot_+jpa 控制台输出sql
    java实现pdf转word(文字)
    Springboot项目使用aop添加日志
    利用chrome浏览器调试Web网页程序
    ORACLE 两表关联更新三种方式
    oracle有关函数 rank(),row_number(),dense_rank(),over()使用小结
    标量子查询要注意的坑
    Oracle分析函数KEEP、DENSE_RANK的使用
  • 原文地址:https://www.cnblogs.com/xingyun1992/p/5021088.html
Copyright © 2011-2022 走看看