Android自定义渐变式炫酷ListView下拉刷新动画
程序员文章站
2023-12-20 18:01:58
本文实例为大家分享了自定义渐变式炫酷动画的listview下拉刷新,供大家参考,具体内容如下
主要要点
listview刷新过程中主要有三个步骤当前:状态为下拉刷新,当...
本文实例为大家分享了自定义渐变式炫酷动画的listview下拉刷新,供大家参考,具体内容如下
主要要点
listview刷新过程中主要有三个步骤当前:状态为下拉刷新,当前状态为下拉刷新,当前状态为放开刷新,当前状态为正在刷新;主要思路为三个步骤分别对应三个自定义的view;即iburefreshfirststepview,iburefreshsecondstepview,iburefreshthirdstepview。
效果图
iburefreshfirststepview代码,例如:
private bitmap initialbitmap; private float mcurrentprogress; private bitmap scaledbitmap; public iburefreshfirststepview(context context, attributeset attrs, int defstyle) { super(context, attrs, defstyle); init(context); } public iburefreshfirststepview(context context, attributeset attrs) { super(context, attrs); init(context); } public iburefreshfirststepview(context context) { super(context); init(context); } private void init(context context) { //这个就是那个火箭图片 initialbitmap = bitmap.createbitmap(bitmapfactory.decoderesource(getresources(), r.drawable.img_huojian1)); } /** * 重写onmeasure方法主要是设置wrap_content时 view的大小 * @param widthmeasurespec * @param heightmeasurespec */ @override protected void onmeasure(int widthmeasurespec, int heightmeasurespec) { //根据设置的宽度来计算高度 设置为符合第二阶段娃娃图片的宽高比例 setmeasureddimension(measurewidth(widthmeasurespec),measurewidth(widthmeasurespec)*initialbitmap.getheight()/initialbitmap.getwidth()); } /** * 当wrap_content的时候,宽度即为第二阶段娃娃图片的宽度 * @param widmeasurespec * @return */ private int measurewidth(int widmeasurespec){ int result = 0; int size = measurespec.getsize(widmeasurespec); int mode = measurespec.getmode(widmeasurespec); if (mode == measurespec.exactly){ result = size; }else{ result = initialbitmap.getwidth(); if (mode == measurespec.at_most){ result = math.min(result,size); } } return result; } /** * 在onlayout里面获得测量后view的宽高 * @param changed * @param left * @param top * @param right * @param bottom */ @override protected void onlayout(boolean changed, int left, int top, int right, int bottom) { super.onlayout(changed, left, top, right, bottom); // 给火箭图片进行等比例的缩放 scaledbitmap = bitmap.createscaledbitmap(initialbitmap,89,110, false); } @override protected void ondraw(canvas canvas) { super.ondraw(canvas); //这个方法是对画布进行缩放,从而达到椭圆形图片的缩放,第一个参数为宽度缩放比例,第二个参数为高度缩放比例, // canvas.scale(mcurrentprogress, mcurrentprogress, measuredwidth/2, measuredheight/2); //将等比例缩放后的椭圆形画在画布上面 canvas.drawbitmap(scaledbitmap,90,dip2px(getcontext(),80*mcurrentprogress),null); } /** * 根据手机的分辨率从 dp 的单位 转成为 px(像素) */ public static int dip2px(context context, float dpvalue) { final float scale = context.getresources().getdisplaymetrics().density; return (int) (dpvalue * scale + 0.5f); } /** * 设置缩放比例,从0到1 0为最小 1为最大 * @param currentprogress */ public void setcurrentprogress(float currentprogress){ mcurrentprogress = currentprogress; } }
iburefreshsecondstepview代码,例如:
private bitmap endbitmap,scaledbitmap; public iburefreshsecondstepview(context context, attributeset attrs, int defstyle) { super(context, attrs, defstyle); init(); } public iburefreshsecondstepview(context context, attributeset attrs) { super(context, attrs); init(); } public iburefreshsecondstepview(context context) { super(context); init(); } private void init() { endbitmap = bitmap.createscaledbitmap(bitmapfactory.decoderesource(getresources(), r.drawable.img_huojian2), 89, 110, false); } @override protected void onmeasure(int widthmeasurespec, int heightmeasurespec) { setmeasureddimension(measurewidth(widthmeasurespec), measurewidth(widthmeasurespec) * endbitmap.getheight() / endbitmap.getwidth()); } @override protected void onlayout(boolean changed, int left, int top, int right, int bottom) { super.onlayout(changed, left, top, right, bottom); scaledbitmap = bitmap.createscaledbitmap(endbitmap, 89, 110, false); } @override protected void ondraw(canvas canvas) { super.ondraw(canvas); canvas.drawbitmap(endbitmap, 90, dip2px(getcontext(), 80 * 1), null); } /** * 根据手机的分辨率从 dp 的单位 转成为 px(像素) */ public static int dip2px(context context, float dpvalue) { final float scale = context.getresources().getdisplaymetrics().density; return (int) (dpvalue * scale + 0.5f); } private int measurewidth(int widthmeasurespec){ int result = 0; int size = measurespec.getsize(widthmeasurespec); int mode = measurespec.getmode(widthmeasurespec); if (mode == measurespec.exactly) { result = size; }else { result = endbitmap.getwidth(); if (mode == measurespec.at_most) { result = math.min(result, size); } } return result; } }
iburefreshthirdstepview代码,例如:
private bitmap endbitmap,scaledbitmap; public iburefreshthirdstepview(context context, attributeset attrs, int defstyle) { super(context, attrs, defstyle); init(); } public iburefreshthirdstepview(context context, attributeset attrs) { super(context, attrs); init(); } public iburefreshthirdstepview(context context) { super(context); init(); } private void init() { endbitmap = bitmap.createscaledbitmap(bitmapfactory.decoderesource(getresources(), r.drawable.img_huojian3), 89, 170, false); } @override protected void ondraw(canvas canvas) { super.ondraw(canvas); canvas.drawbitmap(endbitmap, 90, dip2px(getcontext(), 40 * 1), null); } /** * 根据手机的分辨率从 dp 的单位 转成为 px(像素) */ public static int dip2px(context context, float dpvalue) { final float scale = context.getresources().getdisplaymetrics().density; return (int) (dpvalue * scale + 0.5f); } @override protected void onmeasure(int widthmeasurespec, int heightmeasurespec) { setmeasureddimension(measurewidth(widthmeasurespec), measurewidth(widthmeasurespec)*endbitmap.getheight()/endbitmap.getwidth()); } private int measurewidth(int widthmeasurespec){ int result = 0; int size = measurespec.getsize(widthmeasurespec); int mode = measurespec.getmode(widthmeasurespec); if (mode == measurespec.exactly) { result = size; }else { result = endbitmap.getwidth(); if (mode == measurespec.at_most) { result = math.min(result, size); } } return result; }
代码块
ibulistview 代码,例如:
private static final int done = 0; private static final int pull_to_refresh = 1; private static final int release_to_refresh = 2; private static final int refreshing = 3; private static final int ratio = 3; private relativelayout headerview; private int headerviewheight; private float starty; private float offsety; private textview tv_pull_to_refresh; private onmeituanrefreshlistener monrefreshlistener; private int state; private int mfirstvisibleitem; private boolean isrecord; private boolean isend; private boolean isrefreable; private framelayout manimcontainer; // private animation animation; private simpledateformat format; private iburefreshfirststepview mfirstview; private iburefreshsecondstepview msecondview; private animationdrawable secondanim; private iburefreshthirdstepview mthirdview; private animationdrawable thirdanim; public ibulistview(context context) { super(context); init(context); } public ibulistview(context context, attributeset attrs) { super(context, attrs); init(context); } public ibulistview(context context, attributeset attrs, int defstyleattr) { super(context, attrs, defstyleattr); init(context); } public interface onmeituanrefreshlistener{ void onrefresh(); } /** * 回调接口,想实现下拉刷新的listview实现此接口 * @param onrefreshlistener */ public void setonmeituanrefreshlistener(onmeituanrefreshlistener onrefreshlistener){ monrefreshlistener = onrefreshlistener; isrefreable = true; } /** * 刷新完毕,从主线程发送过来,并且改变headerview的状态和文字动画信息 */ public void setonrefreshcomplete(){ //一定要将isend设置为true,以便于下次的下拉刷新 isend = true; state = done; changeheaderbystate(state); } private imageview imageviewback,imageview_b; private void init(context context) { setoverscrollmode(view.over_scroll_never); setonscrolllistener(this); headerview = (relativelayout) layoutinflater.from(context).inflate(r.layout.ibu_item, null, false); imageviewback= (imageview) headerview.findviewbyid(r.id.icon_back); imageview_b= (imageview) headerview.findviewbyid(r.id.image_b); mfirstview = (iburefreshfirststepview) headerview.findviewbyid(r.id.first_view); tv_pull_to_refresh = (textview) headerview.findviewbyid(r.id.tv_pull_to_refresh); msecondview = (iburefreshsecondstepview) headerview.findviewbyid(r.id.second_view); mthirdview = (iburefreshthirdstepview) headerview.findviewbyid(r.id.third_view); measureview(headerview); addheaderview(headerview); headerviewheight = headerview.getmeasuredheight(); headerview.setpadding(0, -headerviewheight, 0, 0); log.i("zhangqi","headerviewheight="+headerviewheight); state = done; isend = true; isrefreable = false; } @override public void onscrollstatechanged(abslistview abslistview, int i) { } @override public void onscroll(abslistview abslistview, int firstvisibleitem, int visibleitemcount, int totalitemcount) { mfirstvisibleitem = firstvisibleitem; } @override public boolean ontouchevent(motionevent ev) { if (isend) {//如果现在时结束的状态,即刷新完毕了,可以再次刷新了,在onrefreshcomplete中设置 if (isrefreable) {//如果现在是可刷新状态 在setonmeituanlistener中设置为true switch (ev.getaction()){ //用户按下 case motionevent.action_down: //如果当前是在listview顶部并且没有记录y坐标 if (mfirstvisibleitem == 0 && !isrecord) { //将isrecord置为true,说明现在已记录y坐标 isrecord = true; //将当前y坐标赋值给starty起始y坐标 starty = ev.gety(); } imageview_b.setvisibility(visible); break; //用户滑动 case motionevent.action_move: //再次得到y坐标,用来和starty相减来计算offsety位移值 float tempy = ev.gety(); //再起判断一下是否为listview顶部并且没有记录y坐标 if (mfirstvisibleitem == 0 && !isrecord) { isrecord = true; starty = tempy; } //如果当前状态不是正在刷新的状态,并且已经记录了y坐标 if (state!=refreshing && isrecord ) { //计算y的偏移量 offsety = tempy - starty; //计算当前滑动的高度 float currentheight = (-headerviewheight+offsety/3); //用当前滑动的高度和头部headerview的总高度进行比 计算出当前滑动的百分比 0到1 float currentprogress = 1+currentheight/headerviewheight; //如果当前百分比大于1了,将其设置为1,目的是让第一个状态的椭圆不再继续变大 if (currentprogress>=1) { currentprogress = 1; } //如果当前的状态是放开刷新,并且已经记录y坐标 if (state == release_to_refresh && isrecord) { setselection(0); //如果当前滑动的距离小于headerview的总高度 if (-headerviewheight+offsety/ratio<0) { //将状态置为下拉刷新状态 state = pull_to_refresh; //根据状态改变headerview,主要是更新动画和文字等信息 changeheaderbystate(state); //如果当前y的位移值小于0,即为headerview隐藏了 }else if (offsety<=0) { //将状态变为done state = done; //根据状态改变headerview,主要是更新动画和文字等信息 changeheaderbystate(state); } } //如果当前状态为下拉刷新并且已经记录y坐标 if (state == pull_to_refresh && isrecord) { setselection(0); //如果下拉距离大于等于headerview的总高度 if (-headerviewheight+offsety/ratio>=0) { //将状态变为放开刷新 state = release_to_refresh; //根据状态改变headerview,主要是更新动画和文字等信息 changeheaderbystate(state); //如果当前y的位移值小于0,即为headerview隐藏了 }else if (offsety<=0) { //将状态变为done state = done; //根据状态改变headerview,主要是更新动画和文字等信息 changeheaderbystate(state); } } //如果当前状态为done并且已经记录y坐标 if (state == done && isrecord) { //如果位移值大于0 if (offsety>=0) { //将状态改为下拉刷新状态 state = pull_to_refresh; } } //如果为下拉刷新状态 if (state == pull_to_refresh) { //则改变headerview的padding来实现下拉的效果 headerview.setpadding(0,(int)(-headerviewheight+offsety/ratio) ,0,0); //给第一个状态的view设置当前进度值 mfirstview.setcurrentprogress(currentprogress); //重画 mfirstview.postinvalidate(); } //如果为放开刷新状态 if (state == release_to_refresh) { //改变headerview的padding值 headerview.setpadding(0,(int)(-headerviewheight+offsety/ratio) ,0, 0); //给第一个状态的view设置当前进度值 mfirstview.setcurrentprogress(currentprogress); //重画 mfirstview.postinvalidate(); } } break; //当用户手指抬起时 case motionevent.action_up: //如果当前状态为下拉刷新状态 if (state == pull_to_refresh) { //平滑的隐藏headerview this.smoothscrollby((int)(-headerviewheight+offsety/ratio)+headerviewheight, 500); //根据状态改变headerview changeheaderbystate(state); } //如果当前状态为放开刷新 if (state == release_to_refresh) { //平滑的滑到正好显示headerview this.smoothscrollby((int)(-headerviewheight+offsety/ratio), 500); //将当前状态设置为正在刷新 state = refreshing; //回调接口的onrefresh方法 monrefreshlistener.onrefresh(); //根据状态改变headerview changeheaderbystate(state); } //这一套手势执行完,一定别忘了将记录y坐标的isrecord改为false,以便于下一次手势的执行 isrecord = false; break; } } } return super.ontouchevent(ev); } private animation animation; /** * 根据状态改变headerview的动画和文字显示 * @param state */ private void changeheaderbystate(int state){ switch (state) { case done://如果的隐藏的状态 //设置headerview的padding为隐藏 headerview.setpadding(0, -headerviewheight, 0, 0); //第一状态的view显示出来 mfirstview.setvisibility(view.visible); imageview_b.setvisibility(visible); tv_pull_to_refresh.settext("下拉刷新"); //第二状态的view隐藏起来 msecondview.setvisibility(view.gone); //停止第二状态的动画 secondanim.stop(); //第三状态的view隐藏起来 mthirdview.setvisibility(view.gone); //停止第三状态的动画 thirdanim.stop(); break; case release_to_refresh://当前状态为放开刷新 //文字显示为放开刷新 tv_pull_to_refresh.settext("放开刷新"); //第一状态view隐藏起来 mfirstview.setvisibility(view.gone); //第二状态view显示出来 msecondview.setvisibility(view.visible); //播放第二状态的动画 secondanim.start(); //第三状态view隐藏起来 mthirdview.setvisibility(view.gone); //停止第三状态的动画 thirdanim.stop(); break; case pull_to_refresh://当前状态为下拉刷新 imageview_b.setvisibility(visible); //设置文字为下拉刷新 tv_pull_to_refresh.settext("下拉刷新"); //第一状态view显示出来 mfirstview.setvisibility(view.visible); //第二状态view隐藏起来 msecondview.setvisibility(view.gone); //第二状态动画停止 secondanim.stop(); //第三状态view隐藏起来 mthirdview.setvisibility(view.gone); //第三状态动画停止 thirdanim.stop(); break; case refreshing://当前状态为正在刷新 //文字设置为正在刷新 tv_pull_to_refresh.settext("正在刷新"); //第一状态view隐藏起来 mfirstview.setvisibility(view.gone); //第三状态view显示出来 mthirdview.setvisibility(view.visible); //第二状态view隐藏起来 msecondview.setvisibility(view.gone); //停止第二状态动画 secondanim.stop(); //启动第三状态view thirdanim.start(); imageview_b.setvisibility(gone); animation = new translateanimation(0, 0, 0, 600); animation.setduration(3000); imageviewback.setanimation(animation); break; default: break; } } private void measureview(view child) { viewgroup.layoutparams p = child.getlayoutparams(); if (p == null) { p = new viewgroup.layoutparams(viewgroup.layoutparams.match_parent, viewgroup.layoutparams.wrap_content); } int childwidthspec = viewgroup.getchildmeasurespec(0, 0 + 0, p.width); int lpheight = p.height; int childheightspec; if (lpheight > 0) { childheightspec = measurespec.makemeasurespec(lpheight, measurespec.exactly); } else { childheightspec = measurespec.makemeasurespec(0, measurespec.unspecified); } child.measure(childwidthspec, childheightspec); } }
github代码:
项目代码下载(https://github.com/molu0007/ibu_listview)
以上就是本文的全部内容,希望对大家的学习有所帮助,也希望大家多多支持。