仿IOS版QQ的下拉刷新头实现原理
2015-10-29 16:10
615 查看
一直很好奇苹果版QQ的下拉刷新头,那种水滴状的感觉,特别有弹性的感觉,于是趁着项目比较松的时候也来实现一下,这是实现后的图
最主要的要知道这个图形的画法,我使用的是Path路径来做的,然后使用填充画笔,把他全部填充
主要使用两个半圆和两条二次曲线构成
于是引入关键代码
补充一下,path中绘制圆弧用的是arcTo方法,不仅可以绘制圆弧也可以绘制椭圆圆弧,传入矩形区域和角度变化即可,值得注意的是圆弧的方向,用法不当会导致曲线无法闭合。至于二次曲线就不说了
这就是主要的绘制方法,剩下的就好办啦,重写触摸事件,使他下拉时,移动小圆的圆心位置,并且根据两个圆的圆心距,改变两个圆的半径,初始时,两个园大小是一致的,随着距离的增大,小圆半径缩小的更快。当手抬起后,开启线程重置刷新头。
下面是所有的代码:
如想用用在下拉刷新处也是非常简单的,监听到下拉的距离,用此来设置圆心距即可、~
如有问题,或者更好的实现方法也可以分享一下,谢谢~
最主要的要知道这个图形的画法,我使用的是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();
}
}
}
}
}
如想用用在下拉刷新处也是非常简单的,监听到下拉的距离,用此来设置圆心距即可、~
如有问题,或者更好的实现方法也可以分享一下,谢谢~
相关文章推荐
- 使用C++实现JNI接口需要注意的事项
- Android IPC进程间通讯机制
- Android Manifest 用法
- [转载]Activity中ConfigChanges属性的用法
- Android之获取手机上的图片和视频缩略图thumbnails
- Android之使用Http协议实现文件上传功能
- Android学习笔记(二九):嵌入浏览器
- android string.xml文件中的整型和string型代替
- i-jetty环境搭配与编译
- android之定时器AlarmManager
- android wifi 无线调试
- Android Native 绘图方法
- Android java 与 javascript互访(相互调用)的方法例子
- android 代码实现控件之间的间距
- android FragmentPagerAdapter的“标准”配置
- Android"解决"onTouch和onClick的冲突问题
- android:installLocation简析
- android searchView的关闭事件
- SourceProvider.getJniDirectories