在android中自定义的下拉刷新很常用,尤其是在刷新页面更新数据的时候,b比较炫酷的下拉刷新可以赋予一个页面比较好的交互体验;
1
下面先来看几个效果图(在代码中自定义了属性,可以在xml中随意配置实现不同的效果):
下面介绍功能:
1.利用贝塞尔的二阶来实现粘性头,即水滴样式的下拉刷新按钮
2.随着主布局的手势下滑来刷新页面手离开屏幕粘性头自己回滚,细心的有注意我有加插补器哦
3.实现自定义属性;稍候会讲到
2
下面来看代码部分;
2.1首先是相关属性(attrs)的初始化<之后可以在xml中实现自定义属性来私人定制>:
ok~在res->values->attrs下创建自定义属性:
<?xml version="1.0" encoding="utf-8"?>
<resources>
<declare-styleable name="CirclePullView">
<attr name="pColor" format="color"/>
<attr name="pRadius" format="dimension"/>
<attr name="pTarHeight" format="dimension"/>
<attr name="pTarAngle" format="integer"/>
<attr name="pTarWidth" format="dimension"/>
<attr name="pTarDraHeight" format="dimension"/>
<attr name="pContebDrawable" format="reference"/>
<attr name="pContentDrawableMargin" format="dimension"/>
</declare-styleable>
</resources>
2.2初始化自定义类;
首先创建一个自定义的view类 CirclePullView:创建一个圆形的view 用于粘性头的顶端实现并且初始化一些数据:
public class CirclePullView extends View {
private Paint mCirclePaint;
private int mCircleRadius;
private float mCircleX;
private float mCircleY;
private float mProgress;
//设置最大高度
private int maxHeight;
//目标宽度
private int mTargetWidth;
//贝塞尔曲线的路径和画笔
private Paint mBzrPaint = new Paint(Paint.ANTI_ALIAS_FLAG);
private Path mBzrPath = new Path();
//重心点的最终高度,决定控制点的Y坐标
private int mTargetGravityHeight;
//角度变换 0~135
private int mTargetC = 120;
//添加插值器 由快到慢
private Interpolator mProgressIn = new DecelerateInterpolator();
//弧度插值器
private Interpolator mAnlg;
private Context mContext;
private int color = Color.RED;
private Drawable mDrawable;
private float mMargin;
public CirclePullView(Context context) {
this(context,null);
}
public CirclePullView(Context context, @Nullable AttributeSet attrs) {
this(context, attrs,0);
}
public CirclePullView(Context context, @Nullable AttributeSet attrs, int defStyleAttr) {
super(context, attrs, defStyleAttr);
init(attrs);
}
private void init(AttributeSet attrs) {
//初始化上下文
mContext = getContext();
mCircleRadius = (int) TypedValue.applyDimension(TypedValue.COMPLEX_UNIT_DIP,
20,getResources().getDisplayMetrics());
//可拉动的最大高度
maxHeight = (int) TypedValue.applyDimension(TypedValue.COMPLEX_UNIT_DIP,
80,getResources().getDisplayMetrics());
//目标宽度
mTargetWidth = (int) TypedValue.applyDimension(TypedValue.COMPLEX_UNIT_DIP,
50,getResources().getDisplayMetrics());
mTargetGravityHeight = (int) TypedValue.applyDimension(TypedValue.COMPLEX_UNIT_DIP,
5,getResources().getDisplayMetrics());
//初始化弧度插值器--->切角插值器
mAnlg = PathInterpolatorCompat.create((mCircleRadius * 2.0f)/maxHeight,90.0f/mTargetC);
//初始化attrs自定义属性
initAttrs(attrs);
//设置画笔
mCirclePaint = new Paint(Paint.ANTI_ALIAS_FLAG);
//添加防抖动+防锯齿
mCirclePaint.setDither(true);
mCirclePaint.setAntiAlias(true);
mCirclePaint.setColor(color);
mCirclePaint.setStyle(Paint.Style.FILL);
//初始化贝塞尔的画笔和path
//添加防抖动+防锯齿
mBzrPaint.setDither(true);
mBzrPaint.setAntiAlias(true);
mBzrPaint.setColor(color);
mBzrPaint.setStyle(Paint.Style.FILL);
//mBzrPaint.setStrokeWidth(10);
}
}
在以上代码中初始化了基本要用到的所有类型,并且赋值为默认值,而且初始化了两个插补器,第一个是由快到慢的插补器;第二个比较特殊,不过在下面要讲到所以耐心往下看;在初始化完毕之后;开始在intattrs()中初始化自定义view在attrs中的自定义属性
private void initAttrs(AttributeSet attrs) {
// <attr name="pColor" format="color"/>
// <attr name="pRadius" format="dimension"/>
// <attr name="pTarHeight" format="dimension"/>
// <attr name="pTarAngle" format="integer"/>
// <attr name="pTarWidth" format="dimension"/>
// <attr name="pTarDraHeight" format="dimension"/>
// <attr name="pContebDrawable" format="reference"/>
// <attr name="pContentDrawableMargin" format="dimension"/>
TypedArray type = mContext.getTheme().
obtainStyledAttributes(attrs, R.styleable.CirclePullView, 0, 0);
color = type.getColor(R.styleable.CirclePullView_pColor,color);
mCircleRadius = (int) type.getDimension(R.styleable.CirclePullView_pRadius,mCircleRadius);
maxHeight = (int) type.getDimension(R.styleable.CirclePullView_pTarHeight,maxHeight);
mTargetC = type.getInt(R.styleable.CirclePullView_pTarAngle,mTargetC);
mTargetWidth = (int) type.getDimension(R.styleable.CirclePullView_pTarWidth, mTargetWidth);
mTargetGravityHeight = (int) type.getDimension(R.styleable.CirclePullView_pTarDraHeight,mTargetGravityHeight);
mDrawable = type.getDrawable(R.styleable.CirclePullView_pContebDrawable);
mMargin = type.getDimension(R.styleable.CirclePullView_pContentDrawableMargin, 0);
}
在这里可以看到,首先取属性中的对应值如果没有在xml中自定义设置则选择之前初始化好的默认值;
接着在onDrawa方法中绘制一个圆形的view:
canvas.drawCircle(mCircleX,mCircleY,mCircleRadius,mCirclePaint);
2.2设置MainActivity滑动手势控制自定义控件的滑出事件;首先在MainActivity中设置设置滑动最大值 通过位移量设置progress传入CirclePullView中控制滑动的进度,这里是通过传入的progress来不停的请求测量 ,然后高度动态变化实现粘性头的效果;
首先来看MainActivity’的监听事件:
main.setOnTouchListener(new View.OnTouchListener() {
@Override
public boolean onTouch(View view, MotionEvent motionEvent) {
int action = motionEvent.getAction();
switch (action){
case MotionEvent.ACTION_DOWN:
mStartY = motionEvent.getY();
break;
case MotionEvent.ACTION_MOVE:
float y = motionEvent.getY();
float moveY = y - mStartY;
//if (moveY > 0)
float progress = moveY>=maxDy?1:moveY/maxDy;
circlePullView.setProgress(progress);
break;
case MotionEvent.ACTION_UP:
//当抬起时候当进行属性的回缩动画
circlePullView.release();
break;
}
return true;
}
});
上面的核心代码如下:
float progress = moveY>=maxDy?1:moveY/maxDy;
maxDy是自定义的一个最大滑动距离;ok~比较简单继续看代码:
在CirclePullView中,通过set方法获取progress然后刷新布局重新测量:
//Main中传过来
public void setProgress(float progress) {
this.mProgress = progress;
//请求重新布局
requestLayout();
}
通过requestLayout()只要传入progress就重新测量:下面来看测量的方法:
@Override
protected void onMeasure(int widthMeasureSpec, int heightMeasureSpec) {
super.onMeasure(widthMeasureSpec, heightMeasureSpec);
int widthMode = MeasureSpec.getMode(widthMeasureSpec);
int widthSize = MeasureSpec.getSize(widthMeasureSpec);
int heightMode = MeasureSpec.getMode(heightMeasureSpec);
int heightSize = MeasureSpec.getSize(heightMeasureSpec);
int mWidth = mCircleRadius * 2 + getPaddingLeft() + getPaddingRight();
int mHeight = (int) (maxHeight * mProgress + 0.5f) + getPaddingTop() + getPaddingBottom();
//Log.i("==onMeasure",mProgress + "");
int w ;
int h ;
//判断
if (widthMode == MeasureSpec.EXACTLY){
w = widthSize;
}else if (widthMode == MeasureSpec.AT_MOST){
w = Math.min(widthSize,mWidth);
}else {
w = mWidth;
}
if (heightMode == MeasureSpec.EXACTLY){
h = heightSize;
}else if (heightMode == MeasureSpec.AT_MOST){
h = Math.min(heightSize,mHeight);
}else {
h = mHeight;
}
setMeasuredDimension(w,h);
}
通过MeasureSpc的getMode获取mode,然后根据mode的不同来赋值宽高;这里提示一下,EXACTLY是match_parent,AT_MOST是具体的dp,另外一种市对应wrap_contents;
这样就初步实现了圆形view的滑动;
2.3开始进行贝塞尔曲线的ui实现和逻辑的实现
在实现之前 先来看一个类:
/**
* 当绘制图形大小改变的时候调用*/
@Override
protected void onSizeChanged(int w, int h, int oldw, int oldh) {
super.onSizeChanged(w, h, oldw, oldh);
//x = getMeasuredWidth()/2;
//y = getMeasuredHeight()/2;
updataLayout();
}
不错就是onSizeChanged,在View绘制的过程中,只要大小改变则走这个类,所以一些成员变量可以在这里赋值,这样就避免重复的代码操作,ok~我们的贝塞尔逻辑在这里实现,不从就是updataLayout();下面来看代码的实现:
private void updataLayout() {
//获取进度
float progress = mProgressIn.getInterpolation(mProgress);
//float progress = mProgress;
//获取当前的宽度和高度
float currW = calculteWh(getWidth(), mTargetWidth, mProgress);
float currY = calculteWh(0,maxHeight,mProgress);
//获取圆心坐标
int mWidth = (int) ((getWidth() - currW) / 2);
mCircleX = currW/2;
mCircleY = currY - mCircleRadius;
//获取起始点和重点的坐标 只需要求出X 轴就好 Y 为0
//float startX = mWidth;
//float endX = getWidth() - mWidth;
//求出弧度
float anlg = mAnlg.getInterpolation(progress) * mTargetC;
double C = Math.toRadians(anlg);
b
//获取左半边贝塞尔的终点
float dx = (float) (mCircleRadius * Math.sin(C));
float dy = (float) (mCircleRadius * Math.cos(C));
float leftEndX = mCircleX - dx;
float leftEndY = mCircleY + dy;
//左边控制点的坐标
float mLeftControY = calculteWh(0,mTargetGravityHeight,progress);
float mLeftControX = (float) (leftEndX - (leftEndY - mLeftControY)/Math.tan(C));
Log.i("==calculteWh==",mLeftControX + "");
//右边控制点的坐标
float rightStartX = mCircleX + dx;
float mRightControX = (float) (rightStartX + (leftEndY - mLeftControY)/Math.tan(C));
//初始化path
mBzrPath.reset();
mBzrPath.moveTo(0,0);
mBzrPath.quadTo(mLeftControX,mLeftControY,leftEndX,leftEndY);
mBzrPath.lineTo(rightStartX,leftEndY);
mBzrPath.quadTo(mRightControX,mLeftControY,currW,0);
initDrawable(mCircleX,mCircleY,mCircleRadius);
}
然后最后设置了图片 就是替换圆形view的bg,也是定制属性的一部分;
private void initDrawable(float mCircleX, float mCircleY, int mCircleRadius) {
int l = (int) (mCircleX - mCircleRadius + mMargin);
int r = (int) (mCircleX + mCircleRadius - mMargin);
int t = (int) (mCircleY - mCircleRadius + mMargin);
int b = (int) (mCircleY + mCircleRadius - mMargin);
if (mDrawable != null ){
mDrawable.setBounds(l,t,r,b);
}
}
当然最后不要忘记在CirclePullView中定义停止刷新的方法 :
public ValueAnimator anim;
public void release(){
anim= ValueAnimator.ofFloat(mProgress, 0f);
if (anim != null){
anim.setInterpolator(new DecelerateInterpolator());
anim.setDuration(400);
anim.addUpdateListener(new ValueAnimator.AnimatorUpdateListener() {
@Override
public void onAnimationUpdate(ValueAnimator valueAnimator) {
Object animatedValue = valueAnimator.getAnimatedValue();
setProgress((Float) animatedValue);
}
});
}else {
anim.cancel();
anim.setFloatValues(mProgress,0f);
}
anim.start();
}
这样到这里,一自定义粘性头就编写完毕了,编写一次可以在你的各种页面中定制实现:
<com.example.stickyrefresh.customView.CirclePullView
android:id="@+id/circlerPull"
android:visibility="visible"
android:layout_width="match_parent"
android:layout_height="wrap_content"
app:pContebDrawable="@mipmap/ic_launcher"
app:pTarHeight="150dp"
app:pTarWidth="50dp"
app:pTarAngle="110"
app:pRadius="30dp"
app:pColor="@color/colorPrimary"
app:pTarDraHeight="20dp"
app:pContentDrawableMargin="5dp"/>
3
下面看完整代码:
//CirclePullView
package com.example.stickyrefresh.customView;
import android.animation.ValueAnimator;
import android.content.Context;
import android.content.res.TypedArray;
import android.graphics.Canvas;
import android.graphics.Color;
import android.graphics.Paint;
import android.graphics.Path;
import android.graphics.drawable.Drawable;
import android.support.annotation.Nullable;
import android.support.v4.math.MathUtils;
import android.support.v4.view.animation.PathInterpolatorCompat;
import android.util.AttributeSet;
import android.util.Log;
import android.util.TypedValue;
import android.view.Display;
import android.view.View;
import android.view.animation.DecelerateInterpolator;
import android.view.animation.Interpolator;
import com.example.stickyrefresh.R;
/**
* Created by houruixiang on 2017/8/8.
*/
public class CirclePullView extends View {
private Paint mCirclePaint;
private int mCircleRadius;
private float mCircleX;
private float mCircleY;
private float mProgress;
//设置最大高度
private int maxHeight;
//目标宽度
private int mTargetWidth;
//贝塞尔曲线的路径和画笔
private Paint mBzrPaint = new Paint(Paint.ANTI_ALIAS_FLAG);
private Path mBzrPath = new Path();
//重心点的最终高度,决定控制点的Y坐标
private int mTargetGravityHeight;
//角度变换 0~135
private int mTargetC = 120;
//添加插值器 由快到慢
private Interpolator mProgressIn = new DecelerateInterpolator();
//弧度插值器
private Interpolator mAnlg;
private Context mContext;
private int color = Color.RED;
private Drawable mDrawable;
private float mMargin;
public CirclePullView(Context context) {
this(context,null);
}
public CirclePullView(Context context, @Nullable AttributeSet attrs) {
this(context, attrs,0);
}
public CirclePullView(Context context, @Nullable AttributeSet attrs, int defStyleAttr) {
super(context, attrs, defStyleAttr);
init(attrs);
}
private void init(AttributeSet attrs) {
//初始化上下文
mContext = getContext();
mCircleRadius = (int) TypedValue.applyDimension(TypedValue.COMPLEX_UNIT_DIP,
20,getResources().getDisplayMetrics());
//可拉动的最大高度
maxHeight = (int) TypedValue.applyDimension(TypedValue.COMPLEX_UNIT_DIP,
80,getResources().getDisplayMetrics());
//目标宽度
mTargetWidth = (int) TypedValue.applyDimension(TypedValue.COMPLEX_UNIT_DIP,
50,getResources().getDisplayMetrics());
mTargetGravityHeight = (int) TypedValue.applyDimension(TypedValue.COMPLEX_UNIT_DIP,
5,getResources().getDisplayMetrics());
//初始化弧度插值器--->切角插值器
mAnlg = PathInterpolatorCompat.create((mCircleRadius * 2.0f)/maxHeight,90.0f/mTargetC);
//初始化attrs自定义属性
initAttrs(attrs);
//设置画笔
mCirclePaint = new Paint(Paint.ANTI_ALIAS_FLAG);
//添加防抖动+防锯齿
mCirclePaint.setDither(true);
mCirclePaint.setAntiAlias(true);
mCirclePaint.setColor(color);
mCirclePaint.setStyle(Paint.Style.FILL);
//初始化贝塞尔的画笔和path
//添加防抖动+防锯齿
mBzrPaint.setDither(true);
mBzrPaint.setAntiAlias(true);
mBzrPaint.setColor(color);
mBzrPaint.setStyle(Paint.Style.FILL);
//mBzrPaint.setStrokeWidth(10);
}
private void initAttrs(AttributeSet attrs) {
// <attr name="pColor" format="color"/>
// <attr name="pRadius" format="dimension"/>
// <attr name="pTarHeight" format="dimension"/>
// <attr name="pTarAngle" format="integer"/>
// <attr name="pTarWidth" format="dimension"/>
// <attr name="pTarDraHeight" format="dimension"/>
// <attr name="pContebDrawable" format="reference"/>
// <attr name="pContentDrawableMargin" format="dimension"/>
TypedArray type = mContext.getTheme().
obtainStyledAttributes(attrs, R.styleable.CirclePullView, 0, 0);
color = type.getColor(R.styleable.CirclePullView_pColor,color);
mCircleRadius = (int) type.getDimension(R.styleable.CirclePullView_pRadius,mCircleRadius);
maxHeight = (int) type.getDimension(R.styleable.CirclePullView_pTarHeight,maxHeight);
mTargetC = type.getInt(R.styleable.CirclePullView_pTarAngle,mTargetC);
mTargetWidth = (int) type.getDimension(R.styleable.CirclePullView_pTarWidth, mTargetWidth);
mTargetGravityHeight = (int) type.getDimension(R.styleable.CirclePullView_pTarDraHeight,mTargetGravityHeight);
mDrawable = type.getDrawable(R.styleable.CirclePullView_pContebDrawable);
mMargin = type.getDimension(R.styleable.CirclePullView_pContentDrawableMargin, 0);
}
@Override
protected void onMeasure(int widthMeasureSpec, int heightMeasureSpec) {
super.onMeasure(widthMeasureSpec, heightMeasureSpec);
int widthMode = MeasureSpec.getMode(widthMeasureSpec);
int widthSize = MeasureSpec.getSize(widthMeasureSpec);
int heightMode = MeasureSpec.getMode(heightMeasureSpec);
int heightSize = MeasureSpec.getSize(heightMeasureSpec);
int mWidth = mCircleRadius * 2 + getPaddingLeft() + getPaddingRight();
int mHeight = (int) (maxHeight * mProgress + 0.5f) + getPaddingTop() + getPaddingBottom();
//Log.i("==onMeasure",mProgress + "");
int w ;
int h ;
//判断
if (widthMode == MeasureSpec.EXACTLY){
w = widthSize;
}else if (widthMode == MeasureSpec.AT_MOST){
w = Math.min(widthSize,mWidth);
}else {
w = mWidth;
}
if (heightMode == MeasureSpec.EXACTLY){
h = heightSize;
}else if (heightMode == MeasureSpec.AT_MOST){
h = Math.min(heightSize,mHeight);
}else {
h = mHeight;
}
setMeasuredDimension(w,h);
}
@Override
protected void onDraw(Canvas canvas) {
super.onDraw(canvas);
int save = canvas.save();
float tranx = (getWidth() - calculteWh(getWidth(),mTargetWidth,mProgress))/2;
canvas.translate(tranx,0);
//canvas.translate(getWidth() - tranx,0);
canvas.drawCircle(mCircleX,mCircleY,mCircleRadius,mCirclePaint);
canvas.drawPath(mBzrPath,mCirclePaint);
//绘制drawable
if (mDrawable != null){
//mDrawable.
canvas.save();
canvas.clipRect(mDrawable.getBounds());
mDrawable.draw(canvas);
canvas.restore();
}
canvas.restoreToCount(save);
}
/**
* 当绘制图形大小改变的时候调用*/
@Override
protected void onSizeChanged(int w, int h, int oldw, int oldh) {
super.onSizeChanged(w, h, oldw, oldh);
//x = getMeasuredWidth()/2;
//y = getMeasuredHeight()/2;
updataLayout();
}
private void updataLayout() {
//获取进度
float progress = mProgressIn.getInterpolation(mProgress);
//float progress = mProgress;
//获取当前的宽度和高度
float currW = calculteWh(getWidth(), mTargetWidth, mProgress);
float currY = calculteWh(0,maxHeight,mProgress);
//获取圆心坐标
int mWidth = (int) ((getWidth() - currW) / 2);
mCircleX = currW/2;
mCircleY = currY - mCircleRadius;
//获取起始点和重点的坐标 只需要求出X 轴就好 Y 为0
//float startX = mWidth;
//float endX = getWidth() - mWidth;
//求出弧度
float anlg = mAnlg.getInterpolation(progress) * mTargetC;
double C = Math.toRadians(anlg);
// Log.i("==calculteWh==",C + "");
//获取左半边贝塞尔的终点
float dx = (float) (mCircleRadius * Math.sin(C));
float dy = (float) (mCircleRadius * Math.cos(C));
float leftEndX = mCircleX - dx;
float leftEndY = mCircleY + dy;
// Log.i("==calculteWh==",leftEndX + "===" + leftEndY);
//左边控制点的坐标
float mLeftControY = calculteWh(0,mTargetGravityHeight,progress);
float mLeftControX = (float) (leftEndX - (leftEndY - mLeftControY)/Math.tan(C));
Log.i("==calculteWh==",mLeftControX + "");
//右边控制点的坐标
float rightStartX = mCircleX + dx;
float mRightControX = (float) (rightStartX + (leftEndY - mLeftControY)/Math.tan(C));
//初始化path
mBzrPath.reset();
mBzrPath.moveTo(0,0);
mBzrPath.quadTo(mLeftControX,mLeftControY,leftEndX,leftEndY);
mBzrPath.lineTo(rightStartX,leftEndY);
mBzrPath.quadTo(mRightControX,mLeftControY,currW,0);
//Log.i("==mRightControX",currW + "==" + currY + "==" + mLeftControX + "==" + mLeftControY + "==" + leftEndX + "==" + leftEndY + "");
initDrawable(mCircleX,mCircleY,mCircleRadius);
}
private void initDrawable(float mCircleX, float mCircleY, int mCircleRadius) {
int l = (int) (mCircleX - mCircleRadius + mMargin);
int r = (int) (mCircleX + mCircleRadius - mMargin);
int t = (int) (mCircleY - mCircleRadius + mMargin);
int b = (int) (mCircleY + mCircleRadius - mMargin);
if (mDrawable != null ){
mDrawable.setBounds(l,t,r,b);
}
}
private float calculteWh(float max,float min,float progress){
return max + (min - max) *progress;
}
//Main中传过来
public void setProgress(float progress) {
this.mProgress = progress;
//请求重新布局
requestLayout();
}
public ValueAnimator anim;
public void release(){
anim= ValueAnimator.ofFloat(mProgress, 0f);
if (anim != null){
anim.setInterpolator(new DecelerateInterpolator());
anim.setDuration(400);
anim.addUpdateListener(new ValueAnimator.AnimatorUpdateListener() {
@Override
public void onAnimationUpdate(ValueAnimator valueAnimator) {
Object animatedValue = valueAnimator.getAnimatedValue();
setProgress((Float) animatedValue);
}
});
}else {
anim.cancel();
anim.setFloatValues(mProgress,0f);
}
anim.start();
}
}
//MainActivity
package com.example.stickyrefresh;
import android.support.v7.app.AppCompatActivity;
import android.os.Bundle;
import android.util.TypedValue;
import android.view.MotionEvent;
import android.view.View;
import android.widget.LinearLayout;
import com.example.stickyrefresh.customView.CirclePullView;
public class MainActivity extends AppCompatActivity {
private LinearLayout main;
private CirclePullView circlePullView;
private float maxDy;
private float mStartY;
@Override
protected void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
setContentView(R.layout.activity_main);
initView();
initEvent();
}
private void initView() {
maxDy = TypedValue.applyDimension(TypedValue.COMPLEX_UNIT_DIP, 100,
getResources().getDisplayMetrics());
main = (LinearLayout) findViewById(R.id.activity_main);
circlePullView = (CirclePullView) findViewById(R.id.circlerPull);
}
private void initEvent() {
main.setOnTouchListener(new View.OnTouchListener() {
@Override
public boolean onTouch(View view, MotionEvent motionEvent) {
int action = motionEvent.getAction();
switch (action){
case MotionEvent.ACTION_DOWN:
mStartY = motionEvent.getY();
break;
case MotionEvent.ACTION_MOVE:
float y = motionEvent.getY();
float moveY = y - mStartY;
//if (moveY > 0)
float progress = moveY>=maxDy?1:moveY/maxDy;
circlePullView.setProgress(progress);
break;
case MotionEvent.ACTION_UP:
//当抬起时候当进行属性的回缩动画
circlePullView.release();
break;
}
return true;
}
});
}
}
//attrs
<?xml version="1.0" encoding="utf-8"?>
<resources>
<declare-styleable name="CirclePullView">
<attr name="pColor" format="color"/>
<attr name="pRadius" format="dimension"/>
<attr name="pTarHeight" format="dimension"/>
<attr name="pTarAngle" format="integer"/>
<attr name="pTarWidth" format="dimension"/>
<attr name="pTarDraHeight" format="dimension"/>
<attr name="pContebDrawable" format="reference"/>
<attr name="pContentDrawableMargin" format="dimension"/>
</declare-styleable>
</resources>
加班到现在,写了一篇博客,建议如果不懂贝塞尔原理可以自己搜集资料画图理解下就ok,感谢阅读,期待共同进步.希望提出宝贵意见