Android控件PullRefreshViewGroup实现下拉刷新和上拉加载
程序员文章站
2023-12-13 17:39:52
本文实例为大家分享了android实现下拉刷新和上拉加载更多的具体代码,供大家参考,具体内容如下
先分享下源码:android实现下拉刷新和上拉加载更多
实现思路:由p...
本文实例为大家分享了android实现下拉刷新和上拉加载更多的具体代码,供大家参考,具体内容如下
先分享下源码:android实现下拉刷新和上拉加载更多
实现思路:由pullrefreshviewgroup控件来接管标准控件(比如recyclerview、listview等)的滑动,调用标准控件的内部方法进行短距离滑动,不再由标准控件自己来处理事件,而完全由pullrefreshviewgroup控件来处理触摸事件。标准控件内部的滑动距离等属性,通过反射获得computeverticalscrollextent、computeverticalscrollrange、computeverticalscrolloffset这三个方法来获得。
pullrefreshviewgroup控件的布局如下
部分代码实现
触摸滑动事件处理
@override public boolean onintercepttouchevent(motionevent ev) { boolean bret = false; switch (ev.getaction()) { case motionevent.action_down: { mprey = ev.gety(); log.d(tag, "mprey:" + string.valueof(mprey)); } break; case motionevent.action_move: { float cury = ev.gety(); float distance = cury - mprey; if (math.abs(distance) >= mtouchslop) { msliding = bret = true; //修正第一次滑动的卡顿 if (distance > 0) { mprey += mtouchslop; } else { mprey -= mtouchslop; } if (!mscroller.isfinished()) { mscroller.abortanimation(); } } else { msliding = bret = false; } } break; case motionevent.action_up: case motionevent.action_cancel: { bret = msliding; } break; } return bret ? true : super.onintercepttouchevent(ev); } @override public boolean ontouchevent(motionevent event) { boolean bret = false; vtracker.addmovement(event); switch (event.getaction()) { case motionevent.action_down: { mprey = event.gety(); bret = true; } break; case motionevent.action_move: { float cury = event.gety(); float distance = cury - mprey; log.d(tag, "mprey:" + string.valueof(mprey) + " distance:" + string.valueof(distance)); if (distance != 0) { bret = true; if (msrcheighthead == -1 && mhaspullrefresh) { view child0view = mheadview; msrcheighthead = child0view.getheight(); } scrollby(distance); } mprey = cury; } break; case motionevent.action_up: case motionevent.action_cancel: { mprecury = 0; view child0view = mheadview; int child0height = null != child0view ? child0view.getheight() : 0; int child0height2 = null != child0view ? child0view.getlayoutparams().height : 0; //视图的最终高度是有这个来决定的,请看onmeasure 函数的实现 // int child0height3 = child0view.getmeasuredheight(); if (child0height2 != child0height) { child0height = child0height2; } int child0top = null != child0view ? child0view.gettop() : 0; int dy = child0height - msrcheighthead + (msrcheighthead - math.abs(child0top)); log.d(tag, "ontouchevent()action_up child0height:" + string.valueof(child0height) + " msrcheighthead:" + string.valueof(msrcheighthead) + " child0top:" + string.valueof(child0top)); if (dy > 0) {//恢复拉伸视图的位置 if (!mloadingmore && dy > mcanrefreshheight && child0top + child0height2 > mcanrefreshheight && mrefreshload != null) { dy -= mcanrefreshheight; if (!mpullrefreshloading) { mpullrefreshloading = true; mtvrefreshinfo.settext("正在加载..."); mrefreshload.pullrefreshstartload(); } } mscroller.startscroll(0, 0, 0, -dy); invalidate(); } else { vtracker.computecurrentvelocity(1000); float yvel = vtracker.getyvelocity(); if (yvel != 0) {//为了满足内部视图的快速滚动( 中间内容视图 ) mscroller.fling(0, 0, 0, (int) yvel, 0, 0, integer.min_value, integer.max_value); invalidate(); } } vtracker.clear(); bret = true; } break; } return bret ? true : super.ontouchevent(event); }
小距离滑动代码
private void scrollby(float distance) { view child0view = mheadview; view child1view = getchildat(null == mheadview ? 0 : 1); float distanceremain = 0; int child0top = null != child0view ? child0view.gettop() : 0; // int child0height = child0view.getheight(); if (distance < 0) {//向上 int child1top = child1view.gettop(); // int child1height = child1view.getheight(); //child0view 缩小 if (-1 != msrcheighthead && null != child0view && child0view.getheight() > msrcheighthead) { float off = distance; if (child0view.getheight() + distance < msrcheighthead) { off = -(child0view.getheight() - msrcheighthead); distance -= off; } else { distance = 0; } child0view.getlayoutparams().height += (int) off; child1top += (int) off; //child0view 缩小的同时, child1view 的高度也会随之上升 这里很重要 requestlayout(); child1view.offsettopandbottom((int) off); if (null != mtailview) { mtailview.offsettopandbottom((int) off); } } if (distance != 0) { if (child0top + msrcheighthead + distance <= 0) { distanceremain = -(distance + (child0top + msrcheighthead));//正数 distance = -(child0top + msrcheighthead);//负数 } //可以显示加载更多吗? boolean bdirectdown = false; boolean bcanscroll = child1view.canscrollvertically(1) || child1view.canscrollvertically(-1); if (!bcanscroll) { int child1childcount = 0; if (child1view instanceof viewgroup) { child1childcount = ((viewgroup) child1view).getchildcount(); } if (child1childcount > 0) { viewgroup viewgroupchild1 = (viewgroup) child1view; view child1lastitem = viewgroupchild1.getchildat(child1childcount - 1); int child1viewbottom = viewgroupchild1.getbottom(); int child1lastitembottom = child1lastitem.getbottom() + child1top; //相对于 imagescaleviewgroup 的位置 //增加 child1viewbottom > getheight() 来控制 scrollview if (child1lastitembottom == getheight()) { bdirectdown = true; } } } //正在下拉刷新的时候,不能显示加载更多 if ((bcanscroll || bdirectdown) && null != mtailview && !mpullrefreshloading) { int nverticalscrollextent = 0, nverticalscrollrange = 0, nverticalscrolloffset = 0; class c = null; try { c = class.forname(child1view.getclass().getname()); } catch (exception ex) { } try { if (null == mcomputeverticalscrollextent) { method computeverticalscrollextent = findcomputeverticalmethod(c, "computeverticalscrollextent"); computeverticalscrollextent.setaccessible(true); mcomputeverticalscrollextent = computeverticalscrollextent; } nverticalscrollextent = (int) mcomputeverticalscrollextent.invoke(child1view); } catch (exception ex) { } try { if (null == mcomputeverticalscrollrange) { method computeverticalscrollrange = findcomputeverticalmethod(c, "computeverticalscrollrange"); computeverticalscrollrange.setaccessible(true); mcomputeverticalscrollrange = computeverticalscrollrange; } nverticalscrollrange = (int) mcomputeverticalscrollrange.invoke(child1view); } catch (exception ex) { } try { if (null == mcomputeverticalscrolloffset) { method computeverticalscrolloffset = findcomputeverticalmethod(c, "computeverticalscrolloffset"); computeverticalscrolloffset.setaccessible(true); mcomputeverticalscrolloffset = computeverticalscrolloffset; } nverticalscrolloffset = (int) mcomputeverticalscrolloffset.invoke(child1view); } catch (exception ex) { } int range = nverticalscrollrange - nverticalscrollextent; if (nverticalscrolloffset + distanceremain > range) { float noff = distanceremain - (range - nverticalscrolloffset); distanceremain = range - nverticalscrolloffset; distance -= noff; } int child3bottom = mtailview.getbottom(); if (child3bottom + distance < getheight()) { distance = getheight() - child3bottom; } } if (!bcanscroll) { distanceremain = 0; } } } else {//向下 int nscrolloffset = 0; try { class c = class.forname(child1view.getclass().getname()); method computeverticalscrolloffset = findcomputeverticalmethod(c, "computeverticalscrolloffset");//c.getdeclaredmethod("computeverticalscrolloffset"); computeverticalscrolloffset.setaccessible(true); nscrolloffset = (int) computeverticalscrolloffset.invoke(child1view); } catch (exception ex) { } int child2top = null != mtailview ? mtailview.gettop() : getheight();//注意默认值 if (child2top < getheight()) { if (child2top + distance > getheight()) { distanceremain = distance - (getheight() - child2top); distance = getheight() - child2top; } } else if (nscrolloffset > 0) {//内部有滚动,那么就要计算内部滚动距离,其他分配给整体滚动 if (nscrolloffset - distance <= 0) { distanceremain = -nscrolloffset; // distance = distance - nscrolloffset; distance = 0; //内部能滚动,不让外部去滚动 if (!mscroller.isfinished()) { mscroller.abortanimation(); //内部滚动完后,立即停止 } } else { distanceremain = -distance;//负数 distance = 0; } } else { if (child0top + distance > 0) {//child0放大,child1移动 int off = (int) (child0top + distance); distance = -child0top; if (null != child0view) { child0view.getlayoutparams().height += off; requestlayout(); } else { off = 0; } child1view.offsettopandbottom(off); if (null != mtailview) { mtailview.offsettopandbottom(off); } } } } if (0 != (int) distance) { if (null != child0view) { child0view.offsettopandbottom((int) distance); } child1view.offsettopandbottom((int) distance); if (null != mtailview) { mtailview.offsettopandbottom((int) distance); } requestlayout();//奇酷360这里必须调用, 否则显示有点问题 } scrollbyformidview(distanceremain);//外部无法滚动的时候,内部滚动 if (!mpullrefreshloading && !mloadingmore) { int tailviewtop = null != mtailview ? mtailview.gettop() : getheight();//注意默认值 if (tailviewtop < getheight() && mhasloadmore) {//加载更多 mloadingmore = true; if (mrefreshload != null) { mrefreshload.pullupstartloadmore(); } } else { if (mhaspullrefresh) { if (distance < 0) { int child0bottom = child0view.getbottom(); if (child0bottom < mcanrefreshheight) { mtvrefreshinfo.settext("下拉刷新"); } } else { int child0bottom = child0view.getbottom(); if (child0bottom > mcanrefreshheight) { mtvrefreshinfo.settext("松开刷新"); } } } } } }
处理标准控件小距离滚动代码,这里listview有点特殊。
private void scrollbyformidview(float distanceremain) { if (0 != (int) distanceremain) { view child1view = getchildat(null == mheadview ? 0 : 1); if (child1view instanceof listview) { ((listview) child1view).smoothscrollby((int) distanceremain, 0); } /*else if (child1view instanceof scrollview){ ((scrollview) child1view).smoothscrollby(0,(int) distanceremain); }*/ else { child1view.scrollby(0, (int) distanceremain); } } }
以上就是本文的全部内容,希望对大家的学习有所帮助,也希望大家多多支持。