android之listview悬浮topBar效果
虽然listview是过去式,但由于项目中还是有用listview,百度一番都是scrollview中的悬浮bar,没有看到有listview的悬浮bar,所以自己写一个悬浮bar;参照夏大神的
效果如下:
自定义的listview和scrollview没什么区别都是重写onscrollchange()然后在里边调用自己实现的接口,是对外提供的接口吧,这里没有封装,需要的可以自己将其封装,然后在自己项目中使用。
重点的方法:
onscrollchanged()方法:是在listview和scrollview在滚动时会回调的方法并且能获取到当前最新的top left和上一次的top 和left
getviewtreeobservew().addongloballayoutlister():这是view都有的方法,可以监控改view的变化(如显示、隐藏)都会回调以及在view被绘制时会被回调。
思路如下:
一、可以使用getviewtreeobservew().addongloballayoutlister():方法在第一次进入到这个页面后将悬浮的bar与目标view绘制重合。防止显示隐藏会有一闪的情况
二、在onscrollchaged()方法中回调自定义的接口onscrolllistener的方法onscroll()在这里通过layout()方法不断重新绘制悬浮bar的位置。
基本就如此
package com.example.zwr.listviewfloatbardemo; import android.app.activity; import android.os.bundle; import android.util.log; import android.view.view; import android.view.viewtreeobserver.ongloballayoutlistener; import android.widget.imageview; import android.widget.linearlayout; /** * @author zhongwr */ public class mainactivity extends activity implements floatlistview.onscrolllistener { protected static final string tag = "floatlistview"; /** * 自定义的listview */ private floatlistview lvfloat; /** * listview中的headview中要悬浮的view */ private linearlayout mfloattargetlayout; /** * 悬浮的view,跟headview的要一致 */ private linearlayout mfloattoplayout; private view head; @suppresswarnings("deprecation") @override protected void oncreate(bundle savedinstancestate) { super.oncreate(savedinstancestate); setcontentview(r.layout.activity_main); lvfloat = (floatlistview) findviewbyid(r.id.scrollview); head = getlayoutinflater().inflate(r.layout.buy_layout_head, null); lvfloat.addheaderview(head); mfloattargetlayout = (linearlayout) findviewbyid(r.id.buy); mfloattoplayout = (linearlayout) findviewbyid(r.id.top_buy_layout); lvfloat.setonscrolllistener(this); // 当布局的状态或者控件的可见性发生改变回调的接口:当布局都绘制好后会执行一次 findviewbyid(r.id.parent_layout).getviewtreeobserver().addongloballayoutlistener(new ongloballayoutlistener() { @override public void ongloballayout() { // 这一步很重要,一开始让目标悬浮的view和要悬浮的view重合一起,之后悬浮view跟随一起目标view一起移动 onscroll(lvfloat.getscrolly()); } }); lvfloat.setadapter(new datalistadapter(this)); } @override public void onscroll(int scrolly) { // srcollview和这个listview不同之处:scrolly是scrollview.gettop(),parent的坐标没变,只是手指向上滚动时就是scrollview滚出屏幕,但是top还是距离parent的距离,所以那里用max取最大值 //listview手指向上滑动屏幕时会导致headroot的top为负值,因为head是滚出屏幕的head部分并不是listview中item重用机制 int headtop = head.gettop(); if (headtop <= 0 && math.abs(headtop) <= mfloattargetlayout.gettop() && scrolly >= 0) {//手指向上滑动屏幕 mfloattoplayout.layout(0, mfloattargetlayout.gettop() + headtop, mfloattoplayout.getwidth(), mfloattargetlayout.gettop() + headtop + mfloattoplayout.getheight()); } else if (headtop == 0) {//当手指从上往下滑动屏幕到达最顶端时,但还有一段可滑行的距离放手后又回到起始位置,跟系统有关 //此时这个listview的top是负值所以要减去-scrolly:注这个scrolly=listview.gettop();让悬浮的title跟随实际的title一起浮动 mfloattoplayout.layout(0, mfloattargetlayout.gettop() - scrolly, mfloattoplayout.getwidth(), mfloattargetlayout.gettop() - scrolly + mfloattoplayout.getheight()); } else if (headtop < 0) {//由于手指向上滑动屏幕的很快会导致title悬浮不到顶部,所以要强制其在顶部 mfloattoplayout.layout(0, 0, mfloattoplayout.getwidth(), mfloattoplayout.getheight()); } //这种方式会导致闪跳的现象,可以通过动画来实现 } }
主要是onscroll()方法的逻辑:
可以看看夏大神的实现
public void onscroll(int scrolly) { int mbuylayout2parenttop = math.max(scrolly, mbuylayout.gettop()); mtopbuylayout.layout(0, mbuylayout2parenttop, mtopbuylayout.getwidth(), mbuylayout2parenttop + mtopbuylayout.getheight()); }
他这里是直接使用scrolly(其实是scrollview的最新top值)和目标view的top值去最大,因为scrollview是滑出屏幕的,但是其parent的位置没变,所以scrollview的top会越来越大而且是正值。所以可以通过这种方式来绘制悬浮的bar。
但是listview的机制不一样,滑动出屏幕时item由于是重用机制,所以listview中的top并没有改变;巧的是head的机制有点像scrollview滑出的机制,但是又不一样得到的head的top值是负值,猜测相对坐标由于listview这个父布局没动但是head已经滑出屏幕所以是负值。根据这个值处理我们想要的结果,剩下的onscroll()方法的注释写的很清楚了。
自定义的listview代码如下
package com.example.zwr.listviewfloatbardemo; import android.content.context; import android.util.attributeset; import android.util.log; import android.widget.listview; /** * * @author zhongwr * */ public class floatlistview extends listview { private static final string tag = "floatlistview"; private onscrolllistener onscrolllistener; public floatlistview(context context) { this(context, null); } public floatlistview(context context, attributeset attrs) { this(context, attrs, 0); } public floatlistview(context context, attributeset attrs, int defstyle) { super(context, attrs, defstyle); } /** * 设置滚动接口 * @param onscrolllistener */ public void setonscrolllistener(onscrolllistener onscrolllistener) { this.onscrolllistener = onscrolllistener; } @override protected void onsizechanged(int w, int h, int oldw, int oldh) { // log.d(tag, "w = "+w); // log.d(tag, "h = "+h); super.onsizechanged(w, h, oldw, oldh); } /** * 滚动时会执行 * @param l 新的getleft * @param t 新的gettop * @param oldl * @param oldt */ @override protected void onscrollchanged(int l, int t, int oldl, int oldt) { super.onscrollchanged(l, t, oldl, oldt); // log.d(tag, "onscrollchanged l = " + l + " t = " + t); // log.d(tag, "onscrollchanged oldl = " + oldl + " oldt = " + oldt); if (onscrolllistener != null) { onscrolllistener.onscroll(t); } } /** * * 滚动的回调接口 * * @author xiaanming * */ public interface onscrolllistener{ /** * 回调方法, 返回myscrollview滑动的y方向距离 * @param scrolly * 、 */ public void onscroll(int scrolly); } }
没什么逻辑,就是重写了onsizechaged()方法,然后在里边写了调用接口的回调。
就是这么简单!!
demo如下:listview悬浮topbar
以上就是本文的全部内容,希望对大家的学习有所帮助,也希望大家多多支持。