Android自定义实现顶部粘性下拉刷新效果
程序员文章站
2023-12-15 19:18:16
本文实例为大家分享了android实现顶部粘性下拉刷新效果的具体代码,供大家参考,具体内容如下
学习:
activity_view_mv代码
<...
本文实例为大家分享了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>
以上就是本文的全部内容,希望对大家的学习有所帮助,也希望大家多多支持。