自定義組件—ListView_加頭去頭,加腳去腳、添加或刪除ListView中的數據、 -开发者知识库

自定義組件—ListView_加頭去頭,加腳去腳、添加或刪除ListView中的數據、 -开发者知识库,第1张

該組件的功能有三個:

(1)       任意加頭去頭,加腳去腳。

我們知道ListView在setAdapter之后再調用addHeader方法會拋出異常,而加腳有時管用,有時不管用。Android開發文檔中也明確指出ListView在setAdapter之后不應該再進行setHeader和setFooter方法。這明顯不能滿足我們的實際需求。

我的解決方案是:在setAdapter之前給ListView先加上一個空頭布局和空腳布局,布局高度設為wrap_content,這樣當頭或腳布局中沒有任何組件時,頭和腳是看不到的。當需要顯示頭和腳時,直接向頭和腳布局中添加要顯示的組件即可。

(2)       可任意添加或刪除ListView中的數據

有過實際開發經驗的同學可能會有所體會,我們每次改變數據后都要調一次adapter.notifyDataSetChanged(),而且當ListView添加或刪除數據的操作未完成時,再來一次添加或刪除數據操作的話會報異常。比如用ListView顯示網絡獲取的數據時,不斷的刷新數據就會出現這種情況。這時候“同步“獲取數據的線程是無法避免這個問題的,因為當線程獲取網絡數據特別快時還是會出現Listview添加數據操作的同時發生。

我的解決辦法是:在該組件中自己實現添加和刪除數據的方法並用一個變量來標記當前ListView是否在進行添加或刪除數據操作,是的話則不允許在進行數據操作。

(3)       實現了向下滑動出現一個顯示正在加載的頭布局,手離開屏幕時頭布局自動隱藏的功能。如YiBo微博首頁的下拉刷新效果。效果圖如下:

      

自定義組件—ListView_加頭去頭,加腳去腳、添加或刪除ListView中的數據、 -开发者知识库,第2张 

拉動前圖片

自定義組件—ListView_加頭去頭,加腳去腳、添加或刪除ListView中的數據、 -开发者知识库,第3张

按下拉動后圖片

代碼:

package diy.ts.wader.widget;

 

import java.util.Collection;

import java.util.List;

 

import android.content.Context;

import android.graphics.Color;

import android.util.AttributeSet;

import android.view.Gravity;

import android.view.MotionEvent;

import android.view.View;

import android.widget.BaseAdapter;

import android.widget.LinearLayout;

import android.widget.ListView;

import android.widget.ProgressBar;

import android.widget.TextView;

 

/******************************************************************

 * 文件名稱 : MyListView.java

 * 作者 : wader

 * 創建時間 : 2011-7-20上午10:40:05

 * 文件描述 :

 * 實現了下拉顯示組件頭、任意添加頭腳、添加刪除數據功能的ListView組件

 ******************************************************************/

public class MyListView extends ListView {

    private BaseAdapter adapter;

    private List<Object> dataList;

    private Context context;

    private LinearLayout header;

    private LinearLayout footer;

    /*

     * 在touch時間后的move動作時顯示的頭部動畫

     */

    private LinearLayout headerContent;

    ProgressBar headerProgressBar;

    TextView headertextView;

 

    private OnHeadShowOrHideAcion onHeadShowOrHideAcion = null;

    /*

     * 在init時是否加頭布局,在init方法前設置

     */

    private boolean addHeader = false;

    /*

     * 在init時是否加腳布局,在init方法前設置

     */

    private boolean addFooter = false;

    /*

     * 在touch時間后的move動作時是否顯示頭部動畫

     */

    private boolean showAnimationHead = false;

    /*

     * 在顯示頭部動畫時是否執行HeadShowOrHideAcion的doActionOnShowHead方法

     */

    private boolean doActionOnShowHead = true;

    /*

     * 在顯示頭部動畫時是否執行HeadShowOrHideAcion的doActionOnHideHead方法

     */

    private boolean doActionOnHideHead = true;

    /*

     * 頭布局中是否已有內容(headerContent!=null)並已顯示出來

     */

    private boolean haveHead = false;

    /*

     * 是否可以對list進行添加或刪除數據操作,保證list數據同步

     */

    private boolean ableOperateData = true;

    private float initY = 0;

 

    public MyListView(Context context) {

       super(context);

    }

 

    public MyListView(Context context, AttributeSet attrs) {

       this(context, attrs, 0);

    }

 

    public MyListView(Context context, AttributeSet attrs, int defStyle) {

       super(context, attrs, defStyle);

    }

 

    /*

     * 設置在init時是否加頭布局,在init方法前設置

     */

    public void setAddHeader(boolean addHeader) {

       this.addHeader = addHeader;

    }

 

    /*

     * 設置在init時是否加腳布局,在init方法前設置

     */

    public void setAddFooter(boolean addFooter) {

       this.addFooter = addFooter;

    }

 

    /*

     * 設置在touch時間后的move動作時是否顯示頭部動畫

     */

    public void setShowAnimationHead(boolean param) {

       this.showAnimationHead = param;

    }

 

    /*

     * 設置在顯示頭部動畫時是否執行HeadShowOrHideAcion的doActionOnShowHead方法

     */

    public void setDoActionOnShowHead(boolean param) {

       this.doActionOnShowHead = param;

    }

 

    /*

     * 設置在隱藏頭部動畫時是否執行HeadShowOrHideAcion的doActionOnHideHead方法

     */

    public void setDoActionOnHideHead(boolean param) {

       this.doActionOnHideHead = param;

    }

 

    /*

     * 對listview進行初始化,在使用該組件前必須先執行這個方法

     */

    public void init(Context context) {

       this.context = context;

       this.addHeaderAndFooterLayout();

    }

 

    /*

     * 加頭布局和腳布局

     */

    private void addHeaderAndFooterLayout() {

       if (addHeader) {

           header = new LinearLayout(context);

           addHeaderView(header);

           header.setVisibility(View.GONE);

       }

       if (addFooter) {

           footer = new LinearLayout(context);

           addFooterView(footer);

           footer.setVisibility(View.GONE);

       }

    }

 

    /*

     * 顯示指定的頭內容

     */

    public void showHeader(View view) {

       if (view.getLayoutParams() == null) {

           view.setLayoutParams(new LinearLayout.LayoutParams(

                  LinearLayout.LayoutParams.WRAP_CONTENT,

                  LinearLayout.LayoutParams.WRAP_CONTENT));

       }

       header.setVisibility(View.VISIBLE);

       if (header.getChildCount() <= 0)

           header.addView(view);

       this.postInvalidate();

    }

 

    /*

     * 顯示指定的頭動畫

     */

    public void showAnimationHeader() {

       if (!haveHead && addHeader) {

           if (headerContent == null) {

              headerContent = new LinearLayout(context);

              headerContent.setLayoutParams(new LinearLayout.LayoutParams(

                     LinearLayout.LayoutParams.FILL_PARENT,

                     LinearLayout.LayoutParams.FILL_PARENT));

              headerContent.setBackgroundColor(Color.LTGRAY);

              headerContent.setGravity(Gravity.CENTER);

              headerContent.setOrientation(LinearLayout.HORIZONTAL);

 

           } else

              headerContent.removeAllViews();

           if (headertextView == null) {

              headertextView = new TextView(context);

              headertextView.setTextColor(Color.BLACK);

              headertextView.setTextSize(20);

              headertextView.setText("松開即可更新");

           }

           headerProgressBar = new ProgressBar(context);

           headerProgressBar.setPadding(0, 3, 20, 3);

           headerContent.addView(headerProgressBar);

           headerContent.addView(headertextView);

 

           this.showHeader(headerContent);

           haveHead = true;

           if (onHeadShowOrHideAcion != null && doActionOnShowHead) {

              doActionOnShowHead = false;

              onHeadShowOrHideAcion.doActionOnShowHead(this);

           }

       }

    }

 

    /*

     * 刪除頭內容

     */

    public void hideHeader() {

       if (addHeader) {

           header.removeAllViews();

           haveHead = false;

           header.setVisibility(View.GONE);

           this.postInvalidate();

           if (onHeadShowOrHideAcion != null && doActionOnHideHead)

              onHeadShowOrHideAcion.doActionOnHideHead(this);

       }

    }

 

    /*

     * 顯示指定的腳內容

     */

    public void showFooter(View view) {

       if (addFooter) {

           if (view.getLayoutParams() == null) {

              view.setLayoutParams(new LinearLayout.LayoutParams(

                     LinearLayout.LayoutParams.WRAP_CONTENT,

                     LinearLayout.LayoutParams.WRAP_CONTENT));

           }

           footer.setVisibility(View.VISIBLE);

           if (footer.getChildCount() <= 0)

              footer.addView(view);

           this.postInvalidate();

           this.postInvalidate();

       }

    }

 

    /*

     * 刪除腳內容

     */

    public void hideFooter(View view) {

       if (addFooter) {

           footer.removeAllViews();

           footer.setVisibility(View.GONE);

           this.postInvalidate();

       }

    }

 

    /*

     * 為listview設置adapter和與該adapter相關的list,應該在init方法之后執行

     */

    @SuppressWarnings("unchecked")

    public void setData(BaseAdapter adapter, List<? extends Object> dataList) {

       this.adapter = adapter;

       this.dataList = (List<Object>) dataList;

       setAdapter(adapter);

    }

 

    /*

     * 在list最后添加新數據

     */

    public void addData(Collection<? extends Object> c) {

       if (ableOperateData) {

           ableOperateData = false;

           if (dataList == null || adapter == null)

              throw new NullPointerException(

                     "You do not call the setData() method");

           dataList.addAll(c);

           adapter.notifyDataSetChanged();

       }

       ableOperateData = true;

    }

 

    /*

     * 在list的指定位置添加新數據

     */

    public void addData(int index, Collection<? extends Object> c) {

       if (ableOperateData) {

           ableOperateData = false;

           if (dataList == null || adapter == null)

              throw new NullPointerException(

                     "You don not call the setData() method or the Adapter or List param in setData() is null");

           dataList.addAll(index, c);

           adapter.notifyDataSetChanged();

       }

       ableOperateData = true;

    }

 

    /*

     * 刪除list中指定位置的數據

     */

    public void deleteData(int index) {

       if (ableOperateData) {

           ableOperateData = false;

           dataList.remove(index);

           adapter.notifyDataSetChanged();

       }

       ableOperateData = true;

    }

 

    /*

     * 刪除list中的全部數據

     */

    public void deleteAll() {

       if (ableOperateData) {

           ableOperateData = false;

           dataList.clear();

           adapter.notifyDataSetChanged();

       }

       ableOperateData = true;

    }

 

    /*

     * 觸屏事件,主要是為了顯示頭動畫

     */

    public void touchEventAction(MotionEvent ev) {

       switch (ev.getAction()) {

       case MotionEvent.ACTION_MOVE:

           if (this.getFirstVisiblePosition() == 0 && (ev.getY() - initY > 30)

                  && !haveHead) {// 當向下滑動30個單位時顯示頭部動畫

              showAnimationHeader();

 

           }

           break;

       case MotionEvent.ACTION_UP:

           hideHeader();

           break;

       case MotionEvent.ACTION_DOWN:

           initY = ev.getY();

           break;

       }

    }

 

    @Override

    public boolean dispatchTouchEvent(MotionEvent ev) {

       if (showAnimationHead)

           this.touchEventAction(ev);

       super.dispatchTouchEvent(ev);

       return true;

    }

 

    /*

     * 設置在顯示頭部動畫時要執行HeadShowOrHideAcion

     */

    public void setHeadShowOrHideAcion(

           OnHeadShowOrHideAcion paramOnHeadShowOrHideAcion) {

       this.onHeadShowOrHideAcion = paramOnHeadShowOrHideAcion;

    }

 

    /*

     * 自定義內部接口

     */

    public abstract interface OnHeadShowOrHideAcion {

       public void doActionOnShowHead(ListView paramListView);

 

       public void doActionOnHideHead(ListView paramListView);

    }

}

 

  注:

    (1)OnHeadShowOrHideAcion接口是為了實現當下拉刷新時要進行的操作,如啟動線程獲取網絡數據。

         (2)ListView加頭布局后item下標是從1開始而不是從0開始

         (3)該組件用起來可能比較麻煩,大家可以根據自身需要對它進行瘦身和改造。


轉自 http://blog.csdn.net/t80t90s/article/details/8194100?utm_source=tuicool

最佳答案:

本文经用户投稿或网站收集转载,如有侵权请联系本站。

发表评论

0条回复