您好,登錄后才能下訂單哦!
本文實例為大家分享了Android實現頂部粘性下拉刷新效果的具體代碼,供大家參考,具體內容如下
學習:視頻地址
activity_view_mv代碼
<?xml version="1.0" encoding="utf-8"?> <RelativeLayout xmlns:android="http://schemas.android.com/apk/res/android" xmlns:app="http://schemas.android.com/apk/res-auto" android:id="@+id/rl_view" android:layout_width="match_parent" android:layout_height="wrap_content" > <trunk.doi.base.ui.activity.test.TouchPullView android:id="@+id/cs_view" android:layout_width="match_parent" android:layout_height="wrap_content" app:pColor="@color/cff3e19" app:pContentDrawable="@drawable/shape_circle" app:pContentDrawableMargin="2dp" app:pDragHeight="100dp" app:pTangentAngle="110" app:pRadius="15dp" app:pTargetGravityHeight="4dp" app:pTargetWidth="200dp" /> <trunk.doi.base.ui.activity.test.TestViewBezer android:layout_width="match_parent" android:visibility="gone" android:layout_height="wrap_content" /> </RelativeLayout>
ViewMvActivity代碼
import android.os.Bundle; import android.support.annotation.Nullable; import android.view.MotionEvent; import android.view.View; import android.widget.RelativeLayout; import butterknife.BindView; import trunk.doi.base.R; import trunk.doi.base.base.BaseActivity; public class ViewMvActivity extends BaseActivity { @BindView(R.id.cs_view) TouchPullView csView; @BindView(R.id.rl_view) RelativeLayout rl_view; private float mTouchStartY; private static final float TOUCH_MOVE_MAX_Y=600; @Override protected int initLayoutId() { return R.layout.activity_view_mv; } @Override protected void initView(@Nullable Bundle savedInstanceState) { rl_view.setOnTouchListener(new View.OnTouchListener() { @Override public boolean onTouch(View v, MotionEvent event) { int action=event.getActionMasked(); switch (action){ case MotionEvent.ACTION_DOWN: mTouchStartY=event.getY(); return true; case MotionEvent.ACTION_MOVE: float y=event.getY(); if(y>=mTouchStartY){ float moveSize= y-mTouchStartY; float progress=moveSize>=TOUCH_MOVE_MAX_Y?1:moveSize/TOUCH_MOVE_MAX_Y; csView.setProgress(progress); } return true; case MotionEvent.ACTION_UP: csView.release(); return true; default: break; } return false; } }); } @Override protected void setListener() { } @Override protected void initData() { } }
TouchPullView代碼
import android.animation.ValueAnimator; import android.content.Context; import android.content.res.TypedArray; import android.graphics.Canvas; import android.graphics.Paint; import android.graphics.Path; import android.graphics.drawable.Drawable; import android.os.Build; import android.support.annotation.Nullable; import android.support.annotation.RequiresApi; import android.support.v4.view.animation.PathInterpolatorCompat; import android.util.AttributeSet; import android.util.Log; import android.view.View; import android.view.animation.DecelerateInterpolator; import android.view.animation.Interpolator; import trunk.doi.base.R; /** * 作者:Mr.Lee on 2017-9-27 11:57 * 郵箱:569932357@qq.com */ public class TouchPullView extends View { //圓的畫筆 private Paint mCirclePaint; //圓的半徑 private int mCircleRadius=50; private float mCirclePointX; private float mCirclePointY; private float mProgress; //可拖拽高度 private int mDragHeigh=800; //目標寬度 private int mTargetWidth=400; //貝塞爾曲線 private Path mPath=new Path(); private Paint mPathPaint; //重心點最終高度,決定控制點的Y坐標 private int mTargetGravityHeight=10; //角度變換 0-135 private int mTangentAngle=100; private Interpolator mProgressInterpolator=new DecelerateInterpolator(); private Interpolator mTanentAngleInterpolator; private Drawable mContent=null; private int mContentMargin=0; public TouchPullView(Context context) { super(context); init(null); } public TouchPullView(Context context, @Nullable AttributeSet attrs) { super(context, attrs); init(attrs); } public TouchPullView(Context context, @Nullable AttributeSet attrs, int defStyleAttr) { super(context, attrs, defStyleAttr); init(attrs); } @RequiresApi(api = Build.VERSION_CODES.LOLLIPOP) public TouchPullView(Context context, @Nullable AttributeSet attrs, int defStyleAttr, int defStyleRes) { super(context, attrs, defStyleAttr, defStyleRes); init(attrs); } /** * 初始化 */ private void init(AttributeSet attrs){ final Context context=getContext(); TypedArray array=context.obtainStyledAttributes(attrs, R.styleable.TouchPullView,0,0); int color=array.getColor(R.styleable.TouchPullView_pColor,0x20000000); mCircleRadius=(int)array.getDimension(R.styleable.TouchPullView_pRadius,mCircleRadius); mDragHeigh=array.getDimensionPixelOffset(R.styleable.TouchPullView_pDragHeight,mDragHeigh); mTangentAngle=array.getInteger(R.styleable.TouchPullView_pTangentAngle,mTangentAngle); mTargetWidth=array.getDimensionPixelOffset(R.styleable.TouchPullView_pDragHeight,mTargetWidth); mTargetGravityHeight=array.getDimensionPixelOffset(R.styleable.TouchPullView_pTargetGravityHeight,mTargetGravityHeight); mContent=array.getDrawable(R.styleable.TouchPullView_pContentDrawable); mContentMargin=array.getDimensionPixelOffset(R.styleable.TouchPullView_pContentDrawableMargin,0); array.recycle(); Paint p=new Paint(Paint.ANTI_ALIAS_FLAG); //抗鋸齒 p.setAntiAlias(true); //防抖動 p.setDither(true); //填充方式 p.setStyle(Paint.Style.FILL); p.setColor(color); mCirclePaint=p; //初始化路徑部分畫筆 p=new Paint(Paint.ANTI_ALIAS_FLAG); //抗鋸齒 p.setAntiAlias(true); //防抖動 p.setDither(true); //填充方式 p.setStyle(Paint.Style.FILL); p.setColor(color); mPathPaint=p; //切角路徑插值器 mTanentAngleInterpolator= PathInterpolatorCompat.create( (mCircleRadius*2.0f)/mDragHeigh, 90.0f/mTangentAngle ); } @Override protected void onSizeChanged(int w, int h, int oldw, int oldh) { super.onSizeChanged(w, h, oldw, oldh); updatePathLayout(); } @Override protected void onMeasure(int widthMeasureSpec, int heightMeasureSpec) { // super.onMeasure(widthMeasureSpec, heightMeasureSpec); int widthMode=MeasureSpec.getMode(widthMeasureSpec); int width=MeasureSpec.getSize(widthMeasureSpec); int heighMode=MeasureSpec.getMode(heightMeasureSpec); int heigh=MeasureSpec.getSize(heightMeasureSpec); int iHeigh=(int)((mDragHeigh*mProgress+0.5)+ 2*mCircleRadius+getPaddingTop()+getPaddingBottom()); int iWidth=2*mCircleRadius+getPaddingLeft()+getPaddingRight(); int measureWidth,measureHeigh; if(widthMode==MeasureSpec.EXACTLY){ measureWidth=width; }else if(widthMode==MeasureSpec.AT_MOST){ measureWidth=Math.min(iWidth,width); }else{ measureWidth=iWidth; } if(heighMode==MeasureSpec.EXACTLY){ measureHeigh=heigh; }else if(heighMode==MeasureSpec.AT_MOST){ measureHeigh=Math.min(iHeigh,heigh); }else{ measureHeigh=iHeigh; } setMeasuredDimension(measureWidth,measureHeigh); } @Override protected void onDraw(Canvas canvas) { super.onDraw(canvas); int count=canvas.save(); float tranX=(getWidth()-getValueByLine(getWidth(),mTargetWidth,mProgress))/2; canvas.translate(tranX,0); canvas.drawPath(mPath,mPathPaint); //畫圓 canvas.drawCircle(mCirclePointX,mCirclePointY,mCircleRadius,mCirclePaint); Drawable drawable=mContent; if(drawable!=null){ canvas.save(); //剪切矩形區域 canvas.clipRect(drawable.getBounds()); //繪制 drawable.draw(canvas); canvas.restore(); } canvas.restoreToCount(count); } /** * 設置進度 * @param progress */ public void setProgress(float progress){ Log.e("TAG","progress="+progress); mProgress=progress; //重新請求測量 requestLayout(); } private void updatePathLayout(){ final float progress=mProgressInterpolator.getInterpolation(mProgress); //獲取可繪制區域高度寬度 final float w=getValueByLine(getWidth(),mTargetWidth,mProgress); final float h=getValueByLine(0,mDragHeigh,mProgress); //X對稱軸的參數,圓的圓心X final float cPointX=w/2; //圓的半徑 final float cRadius=mCircleRadius; //圓的圓心Y坐標 final float cPointY =h-cRadius; //控制點結束Y坐標 final float endControlY=mTargetGravityHeight; mCirclePointX=cPointX; mCirclePointY= cPointY; final Path path=mPath; //重置 path.reset(); path.moveTo(0,0); //左邊部分的結束點和控制點 float lEndPointX,lEndPointY; float lControlPointX,lControlPointY; //角度轉弧度 float angle=mTangentAngle*mTanentAngleInterpolator.getInterpolation(progress); double radian=Math.toRadians(angle); float x=(float) (Math.sin(radian)*cRadius); float y=(float) (Math.cos(radian)*cRadius); lEndPointX=cPointX-x; lEndPointY= cPointY +y; //控制點y坐標變化 lControlPointY=getValueByLine(0,endControlY,progress); //控制點與結束定之前的高度 float tHeigh=lEndPointY-lControlPointY; //控制點與x坐標的距離 float tWidth= (float) (tHeigh/Math.tan(radian)); lControlPointX=lEndPointX-tWidth; //左邊貝塞爾曲線 path.quadTo(lControlPointX,lControlPointY,lEndPointX,lEndPointY); //連接到右邊 path.lineTo(cPointX+(cPointX-lEndPointX),lEndPointY); //右邊貝塞爾曲線 path.quadTo(cPointX+cPointX-lControlPointX,lControlPointY,w,0); //更新內容部分Drawable updateContentLayout(cPointX,cPointY,cRadius); } /** * 對內容部分進行測量并設置 * @param cx * @param cy * @param radius */ private void updateContentLayout(float cx,float cy,float radius){ Drawable drawable=mContent; if(drawable!=null){ int margin=mContentMargin; int l=(int)(cx-radius+margin); int r=(int)(cx+radius-margin); int t=(int)(cy-radius+margin); int b=(int)(cy+radius-margin); drawable.setBounds(l,t,r,b); } } //釋放動畫 private ValueAnimator valueAnimator; /** * 添加釋放動作 */ public void release(){ if(valueAnimator==null){ ValueAnimator animator=ValueAnimator.ofFloat(mProgress,0f); animator.setInterpolator(new DecelerateInterpolator()); animator.setDuration(400); animator.addUpdateListener(new ValueAnimator.AnimatorUpdateListener() { @Override public void onAnimationUpdate(ValueAnimator animation) { Object val=animation.getAnimatedValue(); if(val instanceof Float){ setProgress((Float) val); } } }); valueAnimator=animator; }else{ valueAnimator.cancel(); valueAnimator.setFloatValues(mProgress,0f); } valueAnimator.start(); } /** * 獲取當前值 * @param start * @param end * @param progress * @return */ private float getValueByLine(float start,float end ,float progress){ return start+(end-start)*progress; } }
TestViewBezer代碼
import android.content.Context; import android.graphics.Canvas; import android.graphics.Paint; import android.graphics.Path; import android.os.Build; import android.support.annotation.Nullable; import android.support.annotation.RequiresApi; import android.util.AttributeSet; import android.view.View; /** * 作者:Mr.Lee on 2017-9-27 18:08 * 郵箱:569932357@qq.com */ public class TestViewBezer extends View { private Paint mPaint=new Paint(Paint.ANTI_ALIAS_FLAG); private Path mPath=new Path(); public TestViewBezer(Context context) { super(context); init(); } public TestViewBezer(Context context, @Nullable AttributeSet attrs) { super(context, attrs); init(); } public TestViewBezer(Context context, @Nullable AttributeSet attrs, int defStyleAttr) { super(context, attrs, defStyleAttr); init(); } @RequiresApi(api = Build.VERSION_CODES.LOLLIPOP) public TestViewBezer(Context context, @Nullable AttributeSet attrs, int defStyleAttr, int defStyleRes) { super(context, attrs, defStyleAttr, defStyleRes); init(); } private void init(){ Paint paint=mPaint; paint.setAntiAlias(true); paint.setDither(true); mPaint.setColor(0xff000000); paint.setStyle(Paint.Style.STROKE); paint.setStrokeWidth(10); Path path=mPath; path.moveTo(100,100); path.lineTo(400,400); path.quadTo(600,100,800,400); path.moveTo(400,800); path.cubicTo(500,600,700,1200,800,800); } @Override protected void onDraw(Canvas canvas) { super.onDraw(canvas); canvas.drawPath(mPath,mPaint); canvas.drawPoint(600,100,mPaint); canvas.drawPoint(500,600,mPaint); canvas.drawPoint(700,1200,mPaint); } }
attr_pull.xml代碼
<declare-styleable name="TouchPullView"> <attr name="pColor" format="color" /> <attr name="pRadius" format="dimension" /> <attr name="pDragHeight" format="dimension"></attr> <attr name="pTangentAngle" format="integer" /> <attr name="pTargetWidth" format="dimension" /> <attr name="pTargetGravityHeight" format="dimension" /> <attr name="pContentDrawable" format="reference" /> <attr name="pContentDrawableMargin" format="dimension" /> </declare-styleable>
shape_circle代碼
<?xml version="1.0" encoding="utf-8"?> <shape xmlns:android="http://schemas.android.com/apk/res/android" android:shape="oval" > <solid android:color="#fff" /> </shape>
以上就是本文的全部內容,希望對大家的學習有所幫助,也希望大家多多支持億速云。
免責聲明:本站發布的內容(圖片、視頻和文字)以原創、轉載和分享為主,文章觀點不代表本網站立場,如果涉及侵權請聯系站長郵箱:is@yisu.com進行舉報,并提供相關證據,一經查實,將立刻刪除涉嫌侵權內容。