自定义粘性下拉刷新

在android中自定义的下拉刷新很常用,尤其是在刷新页面更新数据的时候,b比较炫酷的下拉刷新可以赋予一个页面比较好的交互体验;

1

下面先来看几个效果图(在代码中自定义了属性,可以在xml中随意配置实现不同的效果):
效果图1:bg-green icon-movie

x效果图2 bg--green icon--没有设子

效果图3 bg--blue icon--android

下面介绍功能:
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,感谢阅读,期待共同进步.希望提出宝贵意见

猜你喜欢

转载自blog.csdn.net/soullines/article/details/77014411