自定义组件—ListView_加头去头,加脚去脚、添加或删除ListView中的数据、

来源:互联网 发布:邻家女孩服饰淘宝网 编辑:程序博客网 时间:2024/06/06 23:18

该组件的功能有三个:

(1)       任意加头去头,加脚去脚。

我们知道ListView在setAdapter之后再调用addHeader方法会抛出异常,而加脚有时管用,有时不管用。Android开发文档中也明确指出ListView在setAdapter之后不应该再进行setHeader和setFooter方法。这明显不能满足我们的实际需求。

我的解决方案是:在setAdapter之前给ListView先加上一个空头布局和空脚布局,布局高度设为wrap_content,这样当头或脚布局中没有任何组件时,头和脚是看不到的。当需要显示头和脚时,直接向头和脚布局中添加要显示的组件即可。

(2)       可任意添加或删除ListView中的数据。

有过实际开发经验的同学可能会有所体会,我们每次改变数据后都要调一次adapter.notifyDataSetChanged(),而且当ListView添加或删除数据的操作未完成时,再来一次添加或删除数据操作的话会报异常。比如用ListView显示网络获取的数据时,不断的刷新数据就会出现这种情况。这时候“同步“获取数据的线程是无法避免这个问题的,因为当线程获取网络数据特别快时还是会出现Listview添加数据操作的同时发生。

我的解决办法是:在该组件中自己实现添加和删除数据的方法并用一个变量来标记当前ListView是否在进行添加或删除数据操作,是的话则不允许在进行数据操作。

(3)       实现了向下滑动出现一个显示正在加载的头布局,手离开屏幕时头布局自动隐藏的功能。如YiBo微博首页的下拉刷新效果。效果图如下:

      

 

拉动前图片

按下拉动后图片

代码:

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 0
原创粉丝点击
热门问题 老师的惩罚 人脸识别 我在镇武司摸鱼那些年 重生之率土为王 我在大康的咸鱼生活 盘龙之生命进化 天生仙种 凡人之先天五行 春回大明朝 姑娘不必设防,我是瞎子 墙壁被小孩用彩色笔画花了怎么办 传图识字里有些字识别不了怎么办 一岁四个月宝宝智力发育迟缓怎么办 小打架受伤对方家长不配合怎么办 宝宝要上幼儿园了家长该怎么办 断奶涨奶怎么办又能防止乳房变形 孩子在幼儿园被小朋友打了怎么办 孩子在幼儿园被小朋友咬了怎么办 孩子被同学打了家长该怎么办? 孩子把同学打了打人家长该怎么办 孩子和同学发生矛盾家长该怎么办 孩子同学给孩子要东西家长该怎么办 如果遇到不讲理的孩子和家长怎么办 孩子调皮又被老师留校了怎么办 孩子拼音f和sh发音不清怎么办 自己在家生的孩子怎么办出生证明 在家念地藏经招来众生不走怎么办 家是济宁孩子上学想在济南上怎么办 高一孩子成绩严重下滑家长怎么办 商铺租客不交租金又不搬走怎么办 考试试卷找不到了明天要交怎么办 8个月宝宝不爱吃蔬菜泥怎么办 5个月的宝宝拉肚怎么办 一岁宝宝大便拉不出来怎么办 八个月宝宝便秘拉不出来怎么办 10个月宝宝大便拉水怎么办 4个月的孩子大便拉水怎么办 五个多月宝宝大便拉水怎么办 七个月宝宝大便还没成行怎么办 宝宝一岁了还没长牙怎么办 宝宝什么都会就差不会独占怎么办 两岁宝宝肚子不舒服还吐怎么办 两岁宝宝吃坏肚子吐怎么办 1岁半儿童牙烂了怎么办 一岁宝宝吃了就吐怎么办 两岁宝宝龋齿门牙掉了怎么办 一岁宝宝冻着了呕吐怎么办 两岁宝宝喉咙有痰呼呼响怎么办 1岁宝宝吐的水水怎么办 宝宝吐了5 6次了怎么办 7岁儿童吃了就吐怎么办