android之listview懸浮topBar

雖然listview是過去式,但由於項目中還是有用listview,百度一番都是scrollview中的懸浮bar,沒有看到有listview的懸浮bar,所以自己寫一個懸浮bar;參照夏大神的scrollview的懸浮demo

http://blog.csdn.net/xiaanming/article/details/17761431

效果如下:


自定義的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不同之處:scrollyscrollview.getTop(),parent的座標沒變,只是手指向上滾動時就是scrollview滾出屏幕,但是top還是距離parent的距離,所以那裏用max取最大值
        //listview手指向上滑動屏幕時會導致headRoottop爲負值,因爲head是滾出屏幕的head部分並不是listviewitem重用機制
        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) {//當手指從上往下滑動屏幕到達最頂端時,但還有一段可滑行的距離放手後又回到起始位置,跟系統有關
            //此時這個listviewTop是負值所以要減去-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()方法的邏輯:

可以看看夏大神的實現

  1. public void onScroll(int scrollY) {  
  2.         int mBuyLayout2ParentTop = Math.max(scrollY, mBuyLayout.getTop());  
  3.         mTopBuyLayout.layout(0, mBuyLayout2ParentTop, mTopBuyLayout.getWidth(), mBuyLayout2ParentTop + mTopBuyLayout.getHeight());  
  4.     }  
  5.   
他這裏是直接使用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如下:

http://download.csdn.net/detail/zhongwn/9691531






發表評論
所有評論
還沒有人評論,想成為第一個評論的人麼? 請在上方評論欄輸入並且點擊發布.
相關文章