一直很好奇苹果版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(); } } } } }
如有问题,或者更好的实现方法也可以分享一下,谢谢~