自定義ListView實現底部View自動隱藏和消失的功能

来源:http://www.cnblogs.com/ganchuanpu/archive/2017/03/24/6613784.html
-Advertisement-
Play Games

有這樣一個ListView,要求在屏幕底部有一個篩選排序的浮動框: 1、手指下拉隱藏,上滑顯示 ; 2、如果沒做任何操作,2S之後,要自動顯示; 3、滑動到最底部,始終顯示。 首先看其效果圖: 實現上述效果,其實現原理如下: 1、在屏幕頂部固定一個BottomView,XML佈局最好使用Relati ...


有這樣一個ListView,要求在屏幕底部有一個篩選排序的浮動框:

1、手指下拉隱藏,上滑顯示 ;

2、如果沒做任何操作,2S之後,要自動顯示;

3、滑動到最底部,始終顯示。

首先看其效果圖:

實現上述效果,其實現原理如下:

 1、在屏幕頂部固定一個BottomView,XML佈局最好使用RelativeLayout(底部的BottomView並不是 ListView的footView,這個是和footView獨立的,想想為什麼?)

 2、然後自定義ListView控制項,監聽onTouchEvent事件,主要是監聽手指下滑和上滑事件,同時實現onScrollListener,監聽是否滑動到最底部和最頂部

3、 ListView監聽事件中,控制bottomView的顯示和隱藏,所以ListView提供一個介面,設置底部bootomView的內容,然後獲之後,就可以對bottomView進行控制,同時加上動畫效果。

接下來看是如何的具體實現這種效果:

1。底部BottomView的內容如下,這個XML文件的內容是自定義的,根據各項目的內容需求來定義的,我例子中bottom_view.xml:

<?xml version="1.0" encoding="UTF-8"?>  
<LinearLayout xmlns:android="http://schemas.android.com/apk/res/android"  
    android:id="@+id/button_layout"  
    android:layout_width="fill_parent"  
    android:layout_height="50dp"  
    android:background="#cbcbcb"  
    android:gravity="center_vertical"  
    android:orientation="horizontal" >  
  
        <Button android:layout_height="40dp"  
                  android:layout_width="wrap_content"  
                  android:layout_weight="1"  
                  android:text="價格"  />  
  
    <Button android:layout_height="40dp"  
              android:layout_width="wrap_content"  
              android:layout_weight="1"  
              android:text="好評"  />  
  
    <Button android:layout_height="40dp"  
            android:layout_width="wrap_content"  
            android:layout_weight="1"  
            android:text="篩選"  /> 
  
</LinearLayout>  

2、main.xml如下

<?xml version="1.0" encoding="utf-8"?>  
<RelativeLayout xmlns:android="http://schemas.android.com/apk/res/android"  
              android:orientation="vertical"  
              android:layout_width="fill_parent"  
              android:layout_height="fill_parent"  
        >  
  
    <com.example.BottomFloatListView.BottomFloatListView  
            android:id="@+id/listView"  
            android:layout_width="fill_parent"  
            android:layout_height="fill_parent"  
            android:fadingEdge="none"  
            />  
  
    <include  
            android:id="@+id/bottombar"  
            android:layout_width="match_parent"  
            android:layout_height="wrap_content"  
            android:layout_alignParentBottom="true"  
            layout="@layout/bottom_view"  
            >  
    </include>  
</RelativeLayout

3、自定義ListView控制項BottomFloatListView

package com.example.BottomFloatListView;  
  
import android.content.Context;  
import android.os.Handler;  
import android.util.AttributeSet;  
import android.util.Log;  
import android.view.MotionEvent;  
import android.view.View;  
import android.view.ViewGroup;  
import android.view.animation.Animation;  
import android.view.animation.OvershootInterpolator;  
import android.view.animation.TranslateAnimation;  
import android.widget.*;  
import android.widget.AbsListView.OnScrollListener;  
  
/** 
 * 底部View自動隱藏和消失listview(其他ListView可以繼承該類,如CtripBottomRefreshListView類等) 
 *  
 */  
public class BottomFloatListView extends ListView implements OnScrollListener {  
  
    public View mBottomBar;  
    private int mCurrentScrollState;  
    private boolean bIsMoved = false;  
    private boolean bIsDown = false;  
    private int mDeltaY;  
    private float mMotionY;  
    private int oldFirstVisibleItem = 0;  
    private Handler mHandler = new Handler();  
    private static final String TAG = "BottomFloatListView";  
  
    public BottomFloatListView(Context context) {  
        this(context, null);  
        super.setOnScrollListener(this);  
    }  
  
    public BottomFloatListView(Context context, AttributeSet attrs) {  
        this(context, attrs, 0);  
        super.setOnScrollListener(this);  
    }  
  
    public BottomFloatListView(Context context, AttributeSet attrs, int defStyle) {  
        super(context, attrs, defStyle);  
        super.setOnScrollListener(this);  
    }  
  
    @Override  
    public void setAdapter(ListAdapter adapter) {  
        super.setAdapter(adapter);  
    }  
  
    @Override  
    public void onScroll(AbsListView view, int firstVisibleItem, int visibleItemCount, int totalItemCount) {  
  
        showBottomViewOnBottom(visibleItemCount, totalItemCount, firstVisibleItem);  
  
    }  
  
    @Override  
    public void onScrollStateChanged(AbsListView view, int scrollState) {  
  
        hideBottomViewOnScrollStateChanged(view, scrollState);  
  
    }  
  
    @Override  
    public boolean onTouchEvent(MotionEvent ev) {  
          
         float y = ev.getY();  
         float x = ev.getX();  
         Log.d("FloatListView", "onTouchEvent" + "" + x + "" + y);  
         int action = ev.getAction() & MotionEvent.ACTION_MASK;  
         switch (action) {  
             case MotionEvent.ACTION_DOWN:  
                 action_down(y);  
                 break;  
             case MotionEvent.ACTION_MOVE:  
                 mDeltaY = (int) (y - mMotionY);  
                 bIsMoved = true;  
                 //移動的時候,要移除掉顯示bottomView的消息  
                 mHandler.removeCallbacks(showBottomBarRunnable);  
                 //補齊action_down事件,因為有的時候,action_down 事件沒有執行  
                 action_down(y);  
                 break;  
             case MotionEvent.ACTION_UP:  
                 bIsMoved = false;  
                 bIsDown = false;  
                 if (!bIsMoved && !bIsDown) {  
                     // 如果屏幕上什麼沒做,則過2s之後要顯示bottomView  
                     mHandler.postDelayed(showBottomBarRunnable, 2000);  
                 }  
                 if (mDeltaY < 0) { //下滑影藏  
                     hideBottomBar();  
                 } else {  //上滑顯示  
                     showBottomBar();  
                 }  
  
                 bIsMoved = false;  
                 break;  
         }  
  
        return super.onTouchEvent(ev);  
    }  
      
      
    private void action_down(float y){  
          mMotionY = y;  
          bIsDown = true;  
          Log.d(TAG, "action down execed");  
          mHandler.removeCallbacks(showBottomBarRunnable);  
    }  
  
    /** 
     * 滑動到頂部時,要隱藏bottomView 
     * @param view 
     * @param scrollState 
     */  
    private void hideBottomViewOnScrollStateChanged(AbsListView view, int scrollState) {  
        mCurrentScrollState = scrollState;  
        if(view!=null){  
             if (view.getFirstVisiblePosition() == 0 && scrollState == SCROLL_STATE_IDLE) {  
                 hideBottomBar();  
                 Log.d(TAG, "hide bottom view");  
             }  
        }  
     
    }  
  
    /** 
     * 顯示底部浮動欄 
     */  
    public void showBottomBar() {  
  
        if (mBottomBar != null && mBottomBar.getVisibility() == View.GONE) {  
            mBottomBar.setVisibility(View.INVISIBLE);  
            Animation translateAnimation = new TranslateAnimation(mBottomBar.getLeft(), mBottomBar.getLeft(),30, 0);  
            translateAnimation.setDuration(300);  
            translateAnimation.setInterpolator(new OvershootInterpolator(0.6f));  
            mBottomBar.startAnimation(translateAnimation);  
            translateAnimation.setAnimationListener(new Animation.AnimationListener() {  
                @Override  
                public void onAnimationStart(Animation animation) {  
                }  
  
                @Override  
                public void onAnimationRepeat(Animation animation) {  
                }  
  
                @Override  
                public void onAnimationEnd(Animation animation) {  
                    mBottomBar.setVisibility(View.VISIBLE);  
                }  
            });  
        }  
    }  
  
    /** 
     * 隱藏浮動底部欄 
     */  
    private void hideBottomBar() {  
          
        if (mBottomBar != null && mBottomBar.getVisibility() == View.VISIBLE) {  
            Animation translateAnimation = new TranslateAnimation(mBottomBar.getLeft(), mBottomBar.getLeft(), 0, 30);  
            translateAnimation.setDuration(300);  
            translateAnimation.setInterpolator(new OvershootInterpolator(0.6f));  
            mBottomBar.startAnimation(translateAnimation);  
            translateAnimation.setAnimationListener(new Animation.AnimationListener() {  
                @Override  
                public void onAnimationStart(Animation animation) {  
                }  
  
                @Override  
                public void onAnimationRepeat(Animation animation) {  
                }  
  
                @Override  
                public void onAnimationEnd(Animation animation) {  
                    mBottomBar.setVisibility(View.GONE);  
                }  
            });  
        }  
    }  
  
    /** 
     * 滑動到底部時直接顯示bottomView 
     * @param visibleItemCount 
     * @param totalItemCount 
     * @param firstVisibleItem 
     */  
    private void showBottomViewOnBottom(int visibleItemCount, int totalItemCount, int firstVisibleItem) {  
          
            Log.d(TAG, "visible bottem item count:"  + "firstVisibleItem:" +  firstVisibleItem + "oldFirstVisibleItem:" + oldFirstVisibleItem + mBottomBar);  
             if(getLastVisiblePosition() ==   totalItemCount -1 && mCurrentScrollState != SCROLL_STATE_IDLE){  
                 showBottomBar();  
             }  
    }  
  
    private Runnable showBottomBarRunnable = new Runnable() {  
  
        @Override  
        public void run() {  
            showBottomBar();  
        }  
  
    };  
  
    /** 
     * 將需要隱藏顯示的view傳入 
     *  
     * @param bottomBar 
     */  
    public void setBottomBar(ViewGroup bottomBar) {  
        this.mBottomBar = bottomBar;  
    }  
  
} 

4、主界面測試的Activity,MainActivity代碼如下

public class MainActivity extends Activity {  
    private  BottomFloatListView mBottomFloatListView;  
  
    @Override  
    public void onCreate(Bundle savedInstanceState) {  
        super.onCreate(savedInstanceState);  
        setContentView(R.layout.main);  
        mBottomFloatListView = (BottomFloatListView)findViewById(R.id.listView)  ;  
        mBottomFloatListView.setAdapter(new ArrayAdapter<String>(this, android.R.layout.simple_expandable_list_item_1,getData()));  
        ViewGroup bottomView = (ViewGroup)findViewById(R.id.bottombar) ;  
        mBottomFloatListView.setBottomBar(bottomView);  
    }  
  
    private List<String> getData(){  
        List<String> data = new ArrayList<String>();  
        for(int i = 0; i <100; i++)      {  
            data.add("測試數據" + i);  
        }  
        return data;  
    }  
}  

ViewGroup bottomView = (ViewGroup)findViewById(R.id.bottombar) ;  
mBottomFloatListView.setBottomBar(bottomView); 
將底部的bottomView傳入到ListView中,就可以讓ListView具有底部View自動隱藏和消失的功能。 

  

  

  


您的分享是我們最大的動力!

-Advertisement-
Play Games
更多相關文章
  • 在Android系統中,BroadcastReceiver的設計初衷就是從全局考慮的,可以方便應用程式和系統、應用程式之間、應用程式內的通信,所以對單個應用程式而言BroadcastReceiver是存在安全性問題的,相應問題及解決如下: 1、當應用程式發送某個廣播時系統會將發送的Intent與系統 ...
  • 1.Android 有自帶的jar包可以生成二維碼core-3.0.0.jar,其中的com.google.zxing包 2.寫一個二維碼生成的工具類,網上搜的話應該一大堆。 1 package com.example.administrator.twocodedemo; 2 3 import an ...
  • 作者:Antonio Leiva 時間:Mar 21, 2017 原文鏈接:https://antonioleiva.com/operator-overload-kotlin/ 就像其他每種語言一樣,在Kotlin中,已經預定義了一些操作符執行一定的操作。 最典型的是加(+),減(-),乘(*),除 ...
  • UINavigationController 返回手勢與 leftBarButtonItem UINavigationController 自帶從屏幕左側邊緣向右滑動的返回手勢,可以通過這個手勢實現 pop,或者 pop 中途取消 pop 而停留在當前控制器(UIViewController)。如果 ...
  • 前言 因為 "實戰項目系列" 涉及到數據持久化,這邊就來補充一下。 如本文有錯或理解偏差歡迎聯繫我,會儘快改正更新! 如有什麼問題,也可直接通過郵箱 [email protected] 聯繫我。 demo鏈接: https://pan.baidu.com/s/1hsspiio 密碼: dk3h 數據持 ...
  • UICollectionView 適配 iPhone 7 Plus 需求:在屏幕上水平放置 5 張正方形圖片,每張圖片的寬度相等,無縫隙排列鋪滿一個屏幕寬度。 看似很簡單的需求。用 UICollectionView 實現的話,把 UICollectionView 的寬度設置為屏幕寬度;屏幕寬度除以 ...
  • 譯者註:由於本人水平有限,譯文中難免會出現概念模糊、晦澀難懂,如果實在沒心思看下去,請發揮你的學習能動性,到原文中自行翻譯,感謝!!!點 "這裡" ,直達英文各種長句的世界。 好了,既然你選擇繼續往下看,那就一起來學習吧!!! 譯者:Noddy 地址: "直流電路理論" 如果你喜歡本譯文,請到項目上 ...
  • 1.應用程式 Android會同一系列核心應用程式包一起發佈,該應用程式包包括email客戶端,SMS短消息程式,日曆,地圖,瀏覽器,聯繫人管理程式等。所有的應用程式都是使用JAVA語言編寫的。 2.應用程式框架 開發人員也可以完全訪問核心應用程式所使用的API框架。該應用程式的架構設計簡化了組件的 ...
一周排行
    -Advertisement-
    Play Games
  • 移動開發(一):使用.NET MAUI開發第一個安卓APP 對於工作多年的C#程式員來說,近來想嘗試開發一款安卓APP,考慮了很久最終選擇使用.NET MAUI這個微軟官方的框架來嘗試體驗開發安卓APP,畢竟是使用Visual Studio開發工具,使用起來也比較的順手,結合微軟官方的教程進行了安卓 ...
  • 前言 QuestPDF 是一個開源 .NET 庫,用於生成 PDF 文檔。使用了C# Fluent API方式可簡化開發、減少錯誤並提高工作效率。利用它可以輕鬆生成 PDF 報告、發票、導出文件等。 項目介紹 QuestPDF 是一個革命性的開源 .NET 庫,它徹底改變了我們生成 PDF 文檔的方 ...
  • 項目地址 項目後端地址: https://github.com/ZyPLJ/ZYTteeHole 項目前端頁面地址: ZyPLJ/TreeHoleVue (github.com) https://github.com/ZyPLJ/TreeHoleVue 目前項目測試訪問地址: http://tree ...
  • 話不多說,直接開乾 一.下載 1.官方鏈接下載: https://www.microsoft.com/zh-cn/sql-server/sql-server-downloads 2.在下載目錄中找到下麵這個小的安裝包 SQL2022-SSEI-Dev.exe,運行開始下載SQL server; 二. ...
  • 前言 隨著物聯網(IoT)技術的迅猛發展,MQTT(消息隊列遙測傳輸)協議憑藉其輕量級和高效性,已成為眾多物聯網應用的首選通信標準。 MQTTnet 作為一個高性能的 .NET 開源庫,為 .NET 平臺上的 MQTT 客戶端與伺服器開發提供了強大的支持。 本文將全面介紹 MQTTnet 的核心功能 ...
  • Serilog支持多種接收器用於日誌存儲,增強器用於添加屬性,LogContext管理動態屬性,支持多種輸出格式包括純文本、JSON及ExpressionTemplate。還提供了自定義格式化選項,適用於不同需求。 ...
  • 目錄簡介獲取 HTML 文檔解析 HTML 文檔測試參考文章 簡介 動態內容網站使用 JavaScript 腳本動態檢索和渲染數據,爬取信息時需要模擬瀏覽器行為,否則獲取到的源碼基本是空的。 本文使用的爬取步驟如下: 使用 Selenium 獲取渲染後的 HTML 文檔 使用 HtmlAgility ...
  • 1.前言 什麼是熱更新 游戲或者軟體更新時,無需重新下載客戶端進行安裝,而是在應用程式啟動的情況下,在內部進行資源或者代碼更新 Unity目前常用熱更新解決方案 HybridCLR,Xlua,ILRuntime等 Unity目前常用資源管理解決方案 AssetBundles,Addressable, ...
  • 本文章主要是在C# ASP.NET Core Web API框架實現向手機發送驗證碼簡訊功能。這裡我選擇是一個互億無線簡訊驗證碼平臺,其實像阿裡雲,騰訊雲上面也可以。 首先我們先去 互億無線 https://www.ihuyi.com/api/sms.html 去註冊一個賬號 註冊完成賬號後,它會送 ...
  • 通過以下方式可以高效,並保證數據同步的可靠性 1.API設計 使用RESTful設計,確保API端點明確,並使用適當的HTTP方法(如POST用於創建,PUT用於更新)。 設計清晰的請求和響應模型,以確保客戶端能夠理解預期格式。 2.數據驗證 在伺服器端進行嚴格的數據驗證,確保接收到的數據符合預期格 ...