欢迎您访问程序员文章站本站旨在为大家提供分享程序员计算机编程知识!
您现在的位置是: 首页  >  移动技术

android之listview悬浮topBar效果

程序员文章站 2024-02-11 20:35:34
虽然listview是过去式,但由于项目中还是有用listview,百度一番都是scrollview中的悬浮bar,没有看到有listview的悬浮bar,所以自己写一个悬...

虽然listview是过去式,但由于项目中还是有用listview,百度一番都是scrollview中的悬浮bar,没有看到有listview的悬浮bar,所以自己写一个悬浮bar;参照夏大神的

效果如下:

android之listview悬浮topBar效果

自定义的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

以上就是本文的全部内容,希望对大家的学习有所帮助,也希望大家多多支持。