GVKun编程网logo

android – 如何将listView标头添加为自定义布局(listview设置标题)

7

本文将介绍android–如何将listView标头添加为自定义布局的详细情况,特别是关于listview设置标题的相关信息。我们将通过案例分析、数据研究等多种方式,帮助您更全面地了解这个主题,同时也

本文将介绍android – 如何将listView标头添加为自定义布局的详细情况,特别是关于listview设置标题的相关信息。我们将通过案例分析、数据研究等多种方式,帮助您更全面地了解这个主题,同时也将涉及一些关于Android ExpandableListView具有自定义项目的复杂布局、Android ListView 疯狂之旅 之 《自定义下拉刷新功能的 ListView》、Android ListView 疯狂之旅 之 《自定义下拉刷新功能的ListView》、android listview 自定义的好处的知识。

本文目录一览:

android – 如何将listView标头添加为自定义布局(listview设置标题)

android – 如何将listView标头添加为自定义布局(listview设置标题)

我想在listView中添加标题我尝试这样我在这里缺少的ids很好.
我在片段中使用它.

ListView lv;

LinearLayout header = (LinearLayout) rootView.findViewById(R.id.header_layout);

lv.addHeaderView(header);
// APP is crashing here?

logcat的

java.lang.classCastException: android.widget.AbsListView$LayoutParams cannot be cast to android.widget.RelativeLayout$LayoutParams
            at android.widget.RelativeLayout$DependencyGraph.findRoots(RelativeLayout.java:1732)
            at android.widget.RelativeLayout$DependencyGraph.getSortedViews(RelativeLayout.java:1677)
            at android.widget.RelativeLayout.sortChildren(RelativeLayout.java:381)
            at android.widget.RelativeLayout.onMeasure(RelativeLayout.java:389)
            at android.view.View.measure(View.java:17547)
            at android.view.ViewGroup.measureChildWithMargins(ViewGroup.java:5535)
            at android.widget.LinearLayout.measureChildBeforeLayout(LinearLayout.java:1436)
            at android.widget.LinearLayout.measureVertical(LinearLayout.java:722)
            at android.widget.LinearLayout.onMeasure(LinearLayout.java:613)
            at android.view.View.measure(View.java:17547)
            at android.view.ViewGroup.measureChildWithMargins(ViewGroup.java:5535)
            at android.widget.FrameLayout.onMeasure(FrameLayout.java:436)
            at android.view.View.measure(View.java:17547)

解决方法:

我们可以向ListView添加标题,如下所示:

LayoutInflater myinflater = getLayoutInflater();
ViewGroup myHeader = (ViewGroup)myinflater.inflate(R.layout.headerlayout, myListView, false);
myListView.addHeaderView(myHeader, null, false);

但是,根据您的错误,您可能已经在xml和java文件中使用了相对布局,您正在使用LinearLayout.

您还必须将ListView初始化为:

lv=(ListView)findViewById(R.id.yourlistview);`

Android ExpandableListView具有自定义项目的复杂布局

Android ExpandableListView具有自定义项目的复杂布局

我正在开发一个android应用程序,但遇到了要实现的复杂布局层次结构.该应用程序将列出一个咖啡厅的菜单.截至目前,菜单如下所示:

enter image description here

该列表实现为RecyclerView.视图的自定义适配器负责每个元素的操作.触摸一个元素会增加定单价格,并将1加到所有选定元素中.您也可以单击数字以获取代答对话框并更改金额.

您可以想象那里有很多代码.

这是我要实现的理论布局:

enter image description here

我专注于内部ExpandableListView.基本上我想按食物,饮料等对菜单项进行分类.

我的问题是我不知道如何保留项目布局的“复杂性”.我已经设法仅使用项目名称创建了一个简单的ExpandableListView,如下所示:

enter image description here

但是我真的不知道如何使用我为ExpandableListView中的先前布局创建的项目适配器.不幸的是,我不能共享太多代码,但是我并不需要代码片段,而是更多关于如何实现此功能的指导,想法,技巧…这是我的第一个Android应用程序:-)

任何帮助将不胜感激.

非常感谢!

解决方法:

好吧,我找到了解决我问题的方法,但最终并没有那么复杂.我会尝试总结一下,以防有人遇到同样的情况.

首先,您将必须为ExpandableListView创建一个自定义适配器.我以前的RecyclerView确实有一个自定义适配器,它使用了ViewHolder模式,这使我感到困惑.

实际上,This示例对于了解如何实现自定义适配器非常有用.覆盖的重要方法是getChildView.用这种方法可以构造整个子视图.

@Override
public View getChildView(int listPosition, final int expandedListPosition,
                             boolean isLastChild, View convertView, ViewGroup parent) {
        final MenuItem item = (MenuItem) getChild(listPosition, expandedListPosition);

        if (convertView == null) {
            LayoutInflater layoutInflater = (LayoutInflater) this.context.getSystemService(Context.LAYOUT_INFLATER_SERVICE);
            convertView = layoutInflater.inflate(R.layout.menu_item, null);
        }

        // Save final reference to be able to access it in inner classes
        final View finalConvertView = convertView;

        // Set the item name
        TextView itemName = (TextView) convertView.findViewById(R.id.item_menu_name);
        itemName.setText(item.getName());

        // Set item price
        TextView itemPrice = (TextView) convertView.findViewById(R.id.item_menu_price);
        itemPrice.setText(item.getFormattedPrice());

这不是完整的代码,但是您可以看到如何在menu_item.xml布局中获取视图并填充它们:-)

在我使用Android data bingind之前,但我不知道如何在没有ViewHolder的情况下使用它.

Android ListView 疯狂之旅 之 《自定义下拉刷新功能的 ListView》

Android ListView 疯狂之旅 之 《自定义下拉刷新功能的 ListView》



效果图:




一 首先创建一个类,继承 ListView,编写其构造方法


public class RefreshListView  extends ListView {
    public RefreshListView(Context context) {
        this(context, null);
    }
    public RefreshListView(Context context, AttributeSet attrs) {
        this(context, attrs, 0);
    }
    public RefreshListView(Context context, AttributeSet attrs, int defStyleAttr) {
        super(context, attrs, defStyleAttr);
        init();
    }
    private void init() {
    }
}


二 在 activity 中使用我们的 RefreshListView 控件


向 ListView 中设置数据的过程与我们 android 中提供的 ListView 设置数据的方式一至,这里就不贴出代码块了

此时运行的效果图


可以看到与我们正常的 ListView 是一样的


三 向 RefresListView 中添加我们下拉刷新使用到的头布局



头布局中的显示,包括显示下拉状态的向下的指示箭头,包括指示正在加载中的圆形进度条,包括显示状态与时间的文本框


定义头布局文件

xlistview_footer.xml 文件中

<pre name="code" class="html"><?xml version="1.0" encoding="utf-8"?>
<LinearLayout xmlns:android="http://schemas.android.com/apk/res/android"
    android:layout_width="fill_parent"
    android:layout_height="wrap_content"
    android:gravity="bottom" >
    <RelativeLayout
        android:id="@+id/xlistview_header_content"
        android:layout_width="fill_parent"
        android:layout_height="60dp" >
        <LinearLayout
            android:layout_width="wrap_content"
            android:layout_height="wrap_content"
            android:layout_centerInParent="true"
            android:gravity="center"
            android:orientation="vertical"
            android:id="@+id/xlistview_header_text">
            <TextView
                android:id="@+id/xlistview_header_hint_textview"
                android:layout_width="wrap_content"
                android:layout_height="wrap_content"
                android:text="下拉刷新" />
            <LinearLayout
                android:layout_width="wrap_content"
                android:layout_height="wrap_content"
                android:layout_marginTop="3dp" >
                <TextView
                    android:layout_width="wrap_content"
                    android:layout_height="wrap_content"
                    android:text="上次更新时间:"
                    android:textSize="12sp" />
                <TextView
                    android:id="@+id/xlistview_header_time"
                    android:layout_width="wrap_content"
                    android:layout_height="wrap_content"
                    android:textSize="12sp" />
            </LinearLayout>
        </LinearLayout>

        <ImageView
            android:id="@+id/xlistview_header_arrow"
            android:layout_width="wrap_content"
            android:layout_height="wrap_content"
            android:layout_alignLeft="@id/xlistview_header_text"
            android:layout_centerVertical="true"
            android:layout_marginLeft="-35dp"
            android:src="@drawable/xlistview_arrow" />

        <ProgressBar
            android:id="@+id/xlistview_header_progressbar"
            android:layout_width="30dp"
            android:layout_height="30dp"
            android:layout_alignLeft="@id/xlistview_header_text"
            android:layout_centerVertical="true"
            android:layout_marginLeft="-40dp"
            android:visibility="visible" />
    </RelativeLayout>

</LinearLayout>


将头布局文件添加给 ListView

在 RefresListView 中

private void init(Context context) {
        View view = View.inflate(context,R.layout.xlistview_header,null);
        this.addHeaderView(view);
    }

四 隐藏我们添加的头布局

首先让系统去帮我们测量头布局的高度,测量好后,我们就可以设置头布局的显示位置

 private void init(Context context) {
        View view = View.inflate(context, R.layout.xlistview_header, null);
        view.measure(0, 0);
        final int measuredHeight = view.getMeasuredHeight();
        view.setPadding(0,-measuredHeight,0,0);
        this.addHeaderView(view);
    }


五 设置头布局与 LisView 的联动

使用我们的控件实现 OnTouchListener 接口,并复写 onTouch 方法

import android.view.View.OnTouchListener;
public class RefreshListView  extends ListView implements OnTouchListener {....

@Override
    public boolean onTouch(View v, MotionEvent event) {
        return true;
    }

}

在 onTouch 方法中我们需要重新设置显示头布局,所以我们需要将部分变量修改为成员变量

private void init(Context context) {
        setOnTouchListener(this);
        //获取头布局
        mHeaderView = View.inflate(context, R.layout.xlistview_header, null);
        //进行测量
        mHeaderView.measure(0, 0);
        //获取头布局的高度
        mHeaderHeight = mHeaderView.getMeasuredHeight();
        //设置头布局显示
        mHeaderView.setPadding(0, -mHeaderHeight, 0, 0);
        //添加到ListView中
        this.addHeaderView(mHeaderView);
    }

在 onTouch 方法中进行设置显示随 ListView 的滑动而显示的头布局

@Override
    public boolean onTouchEvent( MotionEvent event) {
        int downY = 0;
         switch ( event.getAction()) {
             case MotionEvent.ACTION_DOWN:
                 //获取按下时的Y轴的位置
                downY = (int)event.getY();
             break;
             case MotionEvent.ACTION_MOVE:
                int moveY = (int)event.getY();
                 //计算在Y轴方向的滑动偏移量,
                 int diffY = moveY - downY;
                 //计算我们的头布局需要移动的距离
                 int paddingTop = -mHeaderHeight +diffY;
                 //设置显示头布局
                 mHeaderView.setPadding(0,paddingTop,0,0);
             break;
             default:
                 break;
         }
        return true;
    }

注:这里之所以使用使用的是 - mHeaderHeight 高度,是因为我们在上面设置的头布局的 paddingTop 的大小正好是头布局的高度,也就是说刚刚好将头布局显示在屏幕外侧



优化代码

 //设置显示头布局,当显示的条目为第一条的时候并且移动的距离大于0的时候再开时向下移动
                 if(getFirstVisiblePosition()==0&&diffY>0){
                     mHeaderView.setPadding(0,paddingTop,0,0);
                     return  true;
                 }

六 定义更新下拉刷新过程中的头布局显示变化


定义下拉至释放刷新的中的变量

  // 代表下拉刷新状态 
    private final int PULL_REFRESH_STATE = 0;
    // 释放刷新状态
    private final int RELEASE_STATE = 1; 
    // 正在刷新状态
    private final int RELEASEING = 2; 
    // 默认当前是下拉刷新状态
    private int header_current_state = PULL_REFRESH_STATE;

创建更新头布局的方法

//更新头布局的方法
    private void updateHeaderView() {
        switch (header_current_state) {
            case PULL_REFRESH_STATE:   //下拉刷新状态
                break;
            case RELEASE_STATE:        //释放刷新状态
                break;
            case RELEASEING:           //正在刷新的状态
                break;
        }
    }

在 onTouchEvent 方法 中 ACTION_MOVE 事件处理中调用使用我们的更新头布局的方法

case MotionEvent.ACTION_MOVE:
                int moveY = (int)event.getY();
                 //计算在Y轴方向的滑动偏移量,
                 int diffY = moveY - downY;
                 //计算我们的头布局需要移动的距离
                 int paddingTop = -mHeaderHeight +diffY;
                 //设置显示头布局,当显示的条目为第一条的时候并且移动的距离大于0的时候再开时向下移动
                 if(getFirstVisiblePosition()==0&&diffY>0){
                     //判断paddingTop 来更新头布局
                     if (paddingTop > 0 && header_current_state != RELEASE_STATE) {
                         // System.out.println("进入释放刷新状态");
                         header_current_state = RELEASE_STATE;
                         // 更新头布局状态
                         updateHeaderView();
                     } else if (paddingTop < 0
                             && header_current_state != PULL_REFRESH_STATE) {
                         // System.out.println("~~~~下拉刷新状态~~~~");
                         header_current_state = PULL_REFRESH_STATE;
                         updateHeaderView();
                     }
                     mHeaderView.setPadding(0,paddingTop,0,0);
                     return  true;
                 }

然后我们在方法 updateHeaderView 这个方法中对应的状态下更新设置显示我们头布局中的信息

 //显示下拉上拉正在刷新状态的textview
        mXlistviewHeaderHintTextview = (TextView) mHeaderView.findViewById(R.id.xlistview_header_hint_textview);
       //头布局中显示时间的控件
        mXlistviewHeaderTime = (TextView) mHeaderView.findViewById(R.id.xlistview_header_time);
        //头布局中显示的指示箭头
        mXlistviewHeaderArrow = (ImageView) mHeaderView.findViewById(R.id.xlistview_header_arrow);
        //头布局中显示的加载圆形进度条
        mXlistviewHeaderProgressbar = (ProgressBar) mHeaderView.findViewById(R.id.xlistview_header_progressbar);

当头布局出现在屏幕上,但是还没有完全显示在屏幕上的时候,指示箭头应当向下,状太信息应当为下拉刷新

当头布局完全显示在屏幕上的时候,指示箭头指示方向向上,状态为释放刷新

//更新头布局的方法
    private void updateHeaderView() {
        switch (header_current_state) {
            case PULL_REFRESH_STATE:   //下拉刷新状态
                //[1]更改iv状态
                mXlistviewHeaderArrow.startAnimation(downAnimation);
                //[2]设置 tv_update 状态
                mXlistviewHeaderHintTextview.setText("下拉刷新");
                //[3]隐藏头布局
                mHeaderView.setPadding(0, -mHeaderHeight, 0, 0);
                break;
            case RELEASE_STATE:        //释放刷新状态
                mXlistviewHeaderArrow.startAnimation(upAnimation);
                mXlistviewHeaderHintTextview.setText("释放刷新");
                break;
            case RELEASEING:           //正在刷新的状态
                //[1]把动画图片隐藏
                mXlistviewHeaderArrow.setVisibility(View.INVISIBLE);
                mXlistviewHeaderArrow.clearAnimation();
                //[2]显示进度条
                mXlistviewHeaderProgressbar.setVisibility(View.VISIBLE);
                //[3]刷新状态的文字改为 正在刷新
                mXlistviewHeaderHintTextview.setText("正在刷新ing");
                //[4]设置头布局回到屏幕顶部
                mHeaderView.setPadding(0, 0, 0, 0);
                break;
        }




在 onTouchEvent 中处理 ACTION_UP 事件

如果当前的状态是释放刷新,那当手指抬起的时候,我们将要进行正在刷新状态,并进行相关 UI 显示更新操作

case MotionEvent.ACTION_UP:
                     if (header_current_state == PULL_REFRESH_STATE) {
                         updateHeaderView();
                     }else if (header_current_state == RELEASE_STATE) {
                         //[1]把正在刷新状态 赋值给 当前状态
                         header_current_state = RELEASEING;
                         //[2]调用更新头布局的方法
                         updateHeaderView();
                         //[3]更新为下拉状态
//				header_current_state =PULL_REFRESH_STATE;
                     }
             break;



可以看到上面使用到了将指示箭头进行旋转操作的动画,可以在构造中进行初始化操作

 private RotateAnimation upAnimation;
 private RotateAnimation downAnimation;



//初始化头布局 图片旋转的动画
    private void initAnim() {
        //向上旋转的动画
        upAnimation = new RotateAnimation(0, -180, Animation.RELATIVE_TO_SELF, 0.5f, Animation.RELATIVE_TO_SELF, 0.5f);
        upAnimation.setDuration(500);//设置动画执行的时长
        upAnimation.setFillAfter(true);

        //向下旋转的动画
        downAnimation = new RotateAnimation(-180, -360, Animation.RELATIVE_TO_SELF, 0.5f, Animation.RELATIVE_TO_SELF, 0.5f);
        downAnimation.setDuration(500);//设置动画执行的时长
        downAnimation.setFillAfter(true);

    }


七 设置下拉刷新的监听回调接口


 //设置下拉刷新数据的接口
    public interface OnPullDownRefreshListener{
        public void onPullDownRefresh();
    }
    private  OnPullDownRefreshListener mOnPullDownRefreshListener;
    //设置刷新的监听
    public void setOnPullDownRefreshListener(OnPullDownRefreshListener listener){
        mOnPullDownRefreshListener = listener;
    }

然后在 onTouchEvent 方法中的 ACTION_UP 事件中片回调

   if (mOnPullDownRefreshListener!=null) {
                             mOnPullDownRefreshListener.onRefresh();
                         }

八 设置加载数据完成后,隐藏头布局并更新显示时间


ublic void setOnLoadFinish() {
        //[0]进度条隐藏 
        mXlistviewHeaderProgressbar.setVisibility(View.INVISIBLE);
        //[2]在这里更新时间 
        mXlistviewHeaderTime.setText(getCurrentTimerr());
        //[3]隐藏头布局
        mHeaderView.setPadding(0, -mHeaderHeight, 0, 0);
        //[4]把状态置为下拉状态 
        header_current_state = PULL_REFRESH_STATE;
    }
也就是说当我们的数据更新完毕后,需要调用我们设置的方法将显示刷新头布局隐藏,并更新相应的状态与显示信息

更新刷新显示的时间 :

public String getCurrentTimerr(){
     SimpleDateFormat sdf = new SimpleDateFormat("yyyy-MM-dd HH:mm:ss");
     return sdf.format(new Date());
	}

到这里,我们的这个完整的具有下拉刷新功能的 ListView 就可以进行使用了


九 添加上拉加载更多数据功能

private void initFootView() {
        //[1]通过打气筒把一个布局转换成一个view对象
        mfootView = View.inflate(getContext(), R.layout.xlistview_footer, null);
        mfootView.measure(0, 0);
        footHeight = mfootView.getMeasuredHeight();
        //[1]默认情况隐藏脚布局
         mfootView.setPadding(0, -footHeight, 0, 0);
        //[2]添加脚布局
        this.addFooterView(mfootView);
        //[3]给listview设置滑动监听
        this.setOnScrollListener(this);
    }


脚布局文件中 :

<pre name="code" class="html"><?xml version="1.0" encoding="utf-8"?>
    <RelativeLayout xmlns:android="http://schemas.android.com/apk/res/android"
        android:layout_width="fill_parent"
        android:layout_height="wrap_content"
        android:padding="10dp" >

        <TextView
            android:id="@+id/xlistview_footer_hint_textview"
            android:layout_width="wrap_content"
            android:layout_height="wrap_content"
            android:layout_centerInParent="true"
            android:text="@string/xlistview_footer_hint_normal" />
    <ProgressBar
        android:layout_toLeftOf="@id/xlistview_footer_hint_textview"
        android:id="@+id/xlistview_footer_progressbar"
        android:layout_width="wrap_content"
        android:layout_height="wrap_content"
        android:visibility="visible" />
    </RelativeLayout>

可以看到这里设置了一个滑动监听,在这里我们需要将我们的控件实现滑动监听事件

public class RefreshListView  extends ListView implements AbsListView.OnScrollListener {

...



    @Override
    public void onScrollStateChanged(AbsListView view, int scrollState) {

    }

    @Override
    public void onScroll(AbsListView view, int firstVisibleItem, int visibleItemCount, int totalItemCount) {

    }
}

设置上拉加载更多的回调监听

 private OnUpLoadingMoreListener mOnUpLoadingMoreListener;
    public void setOnLoadingMoreListener(OnUpLoadingMoreListener l){
        mOnUpLoadingMoreListener = l;
    }
    public interface OnUpLoadingMoreListener{
        public void onLoadingMore();
    }

在 listView 的滑动监听事件中回调监听方法

@Override
    public void onScrollStateChanged(AbsListView view, int scrollState) {
        if (scrollState== SCROLL_STATE_IDLE ||scrollState == SCROLL_STATE_FLING) {
            //判断lisview 是否滑动到了底部
            if (getLastVisiblePosition()==getCount()-1 ) {
                //[1]把脚布局显示出来
                mfootView.setPadding(0, 0, 0, 0);
                if (mOnUpLoadingMoreListener!=null) {
                    mOnUpLoadingMoreListener.onLoadingMore();
                }
            }
        }
    }

设置加载完成后调用方法来隐藏加载更多的显示布局

 //加载更多完成 需要处理的逻辑
    public void setOnLoadIngMoreFinish() {
        //[1]把加载更多脚布局隐藏
        mfootView.setPadding(0, -footHeight, 0, 0);
    }








点击下载源码

下载密码:uvfr



Android ListView 疯狂之旅  第一季     《自定义侧拉删除》 点击打开链接查看
Android ListView 疯狂之旅  第二季     《分组排序显示数据》   点击打开链接查看



最新脑筋急转:  男人与女人一起比赛猜智力题 ,一般女人会赢,因为” 难得糊涂 “,男的糊涂

本文同步分享在 博客 “早起的年轻人”(CSDN)。
如有侵权,请联系 support@oschina.cn 删除。
本文参与 “OSC 源创计划”,欢迎正在阅读的你也加入,一起分享。

Android ListView 疯狂之旅 之 《自定义下拉刷新功能的ListView》

Android ListView 疯狂之旅 之 《自定义下拉刷新功能的ListView》

效果图:

一 首先创建一个类,继承ListView,编写其构造方法

public class RefreshListView  extends ListView {
    public RefreshListView(Context context) {
        this(context, null);
    }
    public RefreshListView(Context context, AttributeSet attrs) {
        this(context, attrs, 0);
    }
    public RefreshListView(Context context, AttributeSet attrs, int defStyleAttr) {
        super(context, attrs, defStyleAttr);
        init();
    }
    private void init() {
    }
}

二 在activity中使用我们的RefreshListView控件

向ListView中设置数据的过程与我们android中提供的ListView设置数据的方式一至,这里就不贴出代码块了

此时运行的效果图


可以看到与我们正常的ListView是一样的

三 向RefresListView中添加我们下拉刷新使用到的头布局


头布局中的显示,包括显示下拉状态的向下的指示箭头,包括指示正在加载中的圆形进度条,包括显示状态与时间的文本框

定义头布局文件

xlistview_footer.xml文件中

<pre name="code"><?xml version="1.0" encoding="utf-8"?>
<LinearLayout xmlns:android="http://schemas.android.com/apk/res/android"
    android:layout_width="fill_parent"
    android:layout_height="wrap_content"
    android:gravity="bottom" >
    <RelativeLayout
        android:id="@+id/xlistview_header_content"
        android:layout_width="fill_parent"
        android:layout_height="60dp" >
        <LinearLayout
            android:layout_width="wrap_content"
            android:layout_height="wrap_content"
            android:layout_centerInParent="true"
            android:gravity="center"
            android:orientation="vertical"
            android:id="@+id/xlistview_header_text">
            <TextView
                android:id="@+id/xlistview_header_hint_textview"
                android:layout_width="wrap_content"
                android:layout_height="wrap_content"
                android:text="下拉刷新" />
            <LinearLayout
                android:layout_width="wrap_content"
                android:layout_height="wrap_content"
                android:layout_marginTop="3dp" >
                <TextView
                    android:layout_width="wrap_content"
                    android:layout_height="wrap_content"
                    android:text="上次更新时间:"
                    android:textSize="12sp" />
                <TextView
                    android:id="@+id/xlistview_header_time"
                    android:layout_width="wrap_content"
                    android:layout_height="wrap_content"
                    android:textSize="12sp" />
            </LinearLayout>
        </LinearLayout>

        <ImageView
            android:id="@+id/xlistview_header_arrow"
            android:layout_width="wrap_content"
            android:layout_height="wrap_content"
            android:layout_alignLeft="@id/xlistview_header_text"
            android:layout_centerVertical="true"
            android:layout_marginLeft="-35dp"
            android:src="@drawable/xlistview_arrow" />

        <ProgressBar
            android:id="@+id/xlistview_header_progressbar"
            android:layout_width="30dp"
            android:layout_height="30dp"
            android:layout_alignLeft="@id/xlistview_header_text"
            android:layout_centerVertical="true"
            android:layout_marginLeft="-40dp"
            android:visibility="visible" />
    </RelativeLayout>

</LinearLayout>



将头布局文件添加给ListView

在RefresListView中

private void init(Context context) {
        View view = View.inflate(context,R.layout.xlistview_header,null);
        this.addHeaderView(view);
    }

四 隐藏我们添加的头布局

首先让系统去帮我们测量头布局的高度,测量好后,我们就可以设置头布局的显示位置

 private void init(Context context) {
        View view = View.inflate(context, R.layout.xlistview_header, null);
        view.measure(0, 0);
        final int measuredHeight = view.getMeasuredHeight();
        view.setPadding(0,-measuredHeight,0,0);
        this.addHeaderView(view);
    }

五 设置头布局与LisView的联动

使用我们的控件实现OnTouchListener接口,并复写onTouch方法

import android.view.View.OnTouchListener;
public class RefreshListView  extends ListView implements OnTouchListener {....

@Override
    public boolean onTouch(View v, MotionEvent event) {
        return true;
    }

}


在onTouch方法中我们需要重新设置显示头布局,所以我们需要将部分变量修改为成员变量

private void init(Context context) {
        setonTouchListener(this);
        //获取头布局
        mHeaderView = View.inflate(context, R.layout.xlistview_header, null);
        //进行测量
        mHeaderView.measure(0, 0);
        //获取头布局的高度
        mHeaderHeight = mHeaderView.getMeasuredHeight();
        //设置头布局显示
        mHeaderView.setPadding(0, -mHeaderHeight, 0, 0);
        //添加到ListView中
        this.addHeaderView(mHeaderView);
    }

在onTouch方法中进行设置显示随ListView的滑动而显示的头布局

@Override
    public boolean onTouchEvent( MotionEvent event) {
        int downY = 0;
         switch ( event.getAction()) {
             case MotionEvent.ACTION_DOWN:
                 //获取按下时的Y轴的位置
                downY = (int)event.getY();
             break;
             case MotionEvent.ACTION_MOVE:
                int moveY = (int)event.getY();
                 //计算在Y轴方向的滑动偏移量,
                 int diffY = moveY - downY;
                 //计算我们的头布局需要移动的距离
                 int paddingTop = -mHeaderHeight +diffY;
                 //设置显示头布局
                 mHeaderView.setPadding(0,paddingTop,0,0);
             break;
             default:
                 break;
         }
        return true;
    }

注:这里之所以使用使用的是-mHeaderHeight高度,是因为我们在上面设置的头布局的paddingTop的大小正好是头布局的高度,也就是说刚刚好将头布局显示在屏幕外侧


优化代码

 //设置显示头布局,当显示的条目为第一条的时候并且移动的距离大于0的时候再开时向下移动
                 if(getFirstVisiblePosition()==0&&diffY>0){
                     mHeaderView.setPadding(0,paddingTop,0,0);
                     return  true;
                 }

六 定义更新下拉刷新过程中的头布局显示变化

定义下拉至释放刷新的中的变量

  // 代表下拉刷新状态 
    private final int PULL_REFRESH_STATE = 0;
    // 释放刷新状态
    private final int RELEASE_STATE = 1; 
    // 正在刷新状态
    private final int RELEASEING = 2; 
    // 默认当前是下拉刷新状态
    private int header_current_state = PULL_REFRESH_STATE;

创建更新头布局的方法

//更新头布局的方法
    private void updateHeaderView() {
        switch (header_current_state) {
            case PULL_REFRESH_STATE:   //下拉刷新状态
                break;
            case RELEASE_STATE:        //释放刷新状态
                break;
            case RELEASEING:           //正在刷新的状态
                break;
        }
    }

在onTouchEvent方法 中ACTION_MOVE事件处理中调用使用我们的更新头布局的方法

case MotionEvent.ACTION_MOVE:
                int moveY = (int)event.getY();
                 //计算在Y轴方向的滑动偏移量,
                 int diffY = moveY - downY;
                 //计算我们的头布局需要移动的距离
                 int paddingTop = -mHeaderHeight +diffY;
                 //设置显示头布局,当显示的条目为第一条的时候并且移动的距离大于0的时候再开时向下移动
                 if(getFirstVisiblePosition()==0&&diffY>0){
                     //判断paddingTop 来更新头布局
                     if (paddingTop > 0 && header_current_state != RELEASE_STATE) {
                         // System.out.println("进入释放刷新状态");
                         header_current_state = RELEASE_STATE;
                         // 更新头布局状态
                         updateHeaderView();
                     } else if (paddingTop < 0
                             && header_current_state != PULL_REFRESH_STATE) {
                         // System.out.println("~~~~下拉刷新状态~~~~");
                         header_current_state = PULL_REFRESH_STATE;
                         updateHeaderView();
                     }
                     mHeaderView.setPadding(0,paddingTop,0,0);
                     return  true;
                 }

然后我们在方法updateHeaderView这个方法中对应的状态下更新设置显示我们头布局中的信息

 //显示下拉上拉正在刷新状态的textview
        mXlistviewHeaderHintTextview = (TextView) mHeaderView.findViewById(R.id.xlistview_header_hint_textview);
       //头布局中显示时间的控件
        mXlistviewHeaderTime = (TextView) mHeaderView.findViewById(R.id.xlistview_header_time);
        //头布局中显示的指示箭头
        mXlistviewHeaderArrow = (ImageView) mHeaderView.findViewById(R.id.xlistview_header_arrow);
        //头布局中显示的加载圆形进度条
        mXlistviewHeaderProgressbar = (ProgressBar) mHeaderView.findViewById(R.id.xlistview_header_progressbar);

当头布局出现在屏幕上,但是还没有完全显示在屏幕上的时候,指示箭头应当向下,状太信息应当为下拉刷新

当头布局完全显示在屏幕上的时候,指示箭头指示方向向上,状态为释放刷新

//更新头布局的方法
    private void updateHeaderView() {
        switch (header_current_state) {
            case PULL_REFRESH_STATE:   //下拉刷新状态
                //[1]更改iv状态
                mXlistviewHeaderArrow.startAnimation(downAnimation);
                //[2]设置 tv_update 状态
                mXlistviewHeaderHintTextview.setText("下拉刷新");
                //[3]隐藏头布局
                mHeaderView.setPadding(0, -mHeaderHeight, 0, 0);
                break;
            case RELEASE_STATE:        //释放刷新状态
                mXlistviewHeaderArrow.startAnimation(upAnimation);
                mXlistviewHeaderHintTextview.setText("释放刷新");
                break;
            case RELEASEING:           //正在刷新的状态
                //[1]把动画图片隐藏
                mXlistviewHeaderArrow.setVisibility(View.INVISIBLE);
                mXlistviewHeaderArrow.clearanimation();
                //[2]显示进度条
                mXlistviewHeaderProgressbar.setVisibility(View.VISIBLE);
                //[3]刷新状态的文字改为 正在刷新
                mXlistviewHeaderHintTextview.setText("正在刷新ing");
                //[4]设置头布局回到屏幕顶部
                mHeaderView.setPadding(0, 0, 0, 0);
                break;
        }


在onTouchEvent中处理ACTION_UP事件

如果当前的状态是释放刷新,那当手指抬起的时候,我们将要进行正在刷新状态,并进行相关UI显示更新操作

case MotionEvent.ACTION_UP:
                     if (header_current_state == PULL_REFRESH_STATE) {
                         updateHeaderView();
                     }else if (header_current_state == RELEASE_STATE) {
                         //[1]把正在刷新状态 赋值给 当前状态
                         header_current_state = RELEASEING;
                         //[2]调用更新头布局的方法
                         updateHeaderView();
                         //[3]更新为下拉状态
//				header_current_state =PULL_REFRESH_STATE;
                     }
             break;


可以看到上面使用到了将指示箭头进行旋转操作的动画,可以在构造中进行初始化操作

 private RotateAnimation upAnimation;
 private RotateAnimation downAnimation;



//初始化头布局 图片旋转的动画
    private void initAnim() {
        //向上旋转的动画
        upAnimation = new RotateAnimation(0, -180, Animation.RELATIVE_TO_SELF, 0.5f, Animation.RELATIVE_TO_SELF, 0.5f);
        upAnimation.setDuration(500);//设置动画执行的时长
        upAnimation.setFillAfter(true);

        //向下旋转的动画
        downAnimation = new RotateAnimation(-180, -360, Animation.RELATIVE_TO_SELF, 0.5f, Animation.RELATIVE_TO_SELF, 0.5f);
        downAnimation.setDuration(500);//设置动画执行的时长
        downAnimation.setFillAfter(true);

    }


七 设置下拉刷新的监听回调接口

 //设置下拉刷新数据的接口
    public interface OnPullDownRefreshListener{
        public void onPullDownRefresh();
    }
    private  OnPullDownRefreshListener mOnPullDownRefreshListener;
    //设置刷新的监听
    public void setonPullDownRefreshListener(OnPullDownRefreshListener listener){
        mOnPullDownRefreshListener = listener;
    }

然后在onTouchEvent方法中的ACTION_UP事件中片回调

   if (mOnPullDownRefreshListener!=null) {
                             mOnPullDownRefreshListener.onRefresh();
                         }

八 设置加载数据完成后,隐藏头布局并更新显示时间

ublic void setonLoadFinish() {
        //[0]进度条隐藏 
        mXlistviewHeaderProgressbar.setVisibility(View.INVISIBLE);
        //[2]在这里更新时间 
        mXlistviewHeaderTime.setText(getCurrentTimerr());
        //[3]隐藏头布局
        mHeaderView.setPadding(0, -mHeaderHeight, 0, 0);
        //[4]把状态置为下拉状态 
        header_current_state = PULL_REFRESH_STATE;
    }
也就是说当我们的数据更新完毕后,需要调用我们设置的方法将显示刷新头布局隐藏,并更新相应的状态与显示信息

更新刷新显示的时间 :

public String getCurrentTimerr(){
     SimpleDateFormat sdf = new SimpleDateFormat("yyyy-MM-dd HH:mm:ss");
     return sdf.format(new Date());
	}

到这里,我们的这个完整的具有下拉刷新功能的ListView就可以进行使用了

九 添加上拉加载更多数据功能

private void initFootView() {
        //[1]通过打气筒把一个布局转换成一个view对象
        mfootView = View.inflate(getContext(), R.layout.xlistview_footer, null);
        mfootView.measure(0, 0);
        footHeight = mfootView.getMeasuredHeight();
        //[1]默认情况隐藏脚布局
         mfootView.setPadding(0, -footHeight, 0, 0);
        //[2]添加脚布局
        this.addFooterView(mfootView);
        //[3]给listview设置滑动监听
        this.setonScrollListener(this);
    }

脚布局文件中 :

<pre name="code"><?xml version="1.0" encoding="utf-8"?>
    <RelativeLayout xmlns:android="http://schemas.android.com/apk/res/android"
        android:layout_width="fill_parent"
        android:layout_height="wrap_content"
        android:padding="10dp" >

        <TextView
            android:id="@+id/xlistview_footer_hint_textview"
            android:layout_width="wrap_content"
            android:layout_height="wrap_content"
            android:layout_centerInParent="true"
            android:text="@string/xlistview_footer_hint_normal" />
    <ProgressBar
        android:layout_toLeftOf="@id/xlistview_footer_hint_textview"
        android:id="@+id/xlistview_footer_progressbar"
        android:layout_width="wrap_content"
        android:layout_height="wrap_content"
        android:visibility="visible" />
    </RelativeLayout>


可以看到这里设置了一个滑动监听,在这里我们需要将我们的控件实现滑动监听事件

public class RefreshListView  extends ListView implements AbsListView.OnScrollListener {

...



    @Override
    public void onScrollStateChanged(AbsListView view, int scrollState) {

    }

    @Override
    public void onScroll(AbsListView view, int firstVisibleItem, int visibleItemCount, int totalItemCount) {

    }
}

设置上拉加载更多的回调监听

 private OnUpLoadingMoreListener mOnUpLoadingMoreListener;
    public void setonLoadingMoreListener(OnUpLoadingMoreListener l){
        mOnUpLoadingMoreListener = l;
    }
    public interface OnUpLoadingMoreListener{
        public void onl oadingMore();
    }

在listView的滑动监听事件中回调监听方法

@Override
    public void onScrollStateChanged(AbsListView view, int scrollState) {
        if (scrollState== SCROLL_STATE_IDLE ||scrollState == SCROLL_STATE_FLING) {
            //判断lisview 是否滑动到了底部
            if (getLastVisiblePosition()==getCount()-1 ) {
                //[1]把脚布局显示出来
                mfootView.setPadding(0, 0, 0, 0);
                if (mOnUpLoadingMoreListener!=null) {
                    mOnUpLoadingMoreListener.onLoadingMore();
                }
            }
        }
    }

设置加载完成后调用方法来隐藏加载更多的显示布局

 //加载更多完成 需要处理的逻辑
    public void setonLoadIngMoreFinish() {
        //[1]把加载更多脚布局隐藏
        mfootView.setPadding(0, -footHeight, 0, 0);
    }


点击下载源码

下载密码:uvfr

Android ListView 疯狂之旅  第一季     《自定义侧拉删除》 点击打开链接查看
Android ListView 疯狂之旅  第二季     《分组排序显示数据》   点击打开链接查看


最新脑筋急转:  男人与女人一起比赛猜智力题 ,一般女人会赢,因为”难得糊涂“,男的糊涂

android listview 自定义的好处

android listview 自定义的好处


问下,大家android开发的时候,经常要用的ListView,很多人都是自定义的,请问下自定义的时候,一般是重写哪些方法?要注意什么?什么情况下需要自定义?
我看很多同事用的自定义listview,老实说,我不是很看的懂,感觉那些代码也不是他们自己写的,不知道从哪儿抄过来的

今天的关于android – 如何将listView标头添加为自定义布局listview设置标题的分享已经结束,谢谢您的关注,如果想了解更多关于Android ExpandableListView具有自定义项目的复杂布局、Android ListView 疯狂之旅 之 《自定义下拉刷新功能的 ListView》、Android ListView 疯狂之旅 之 《自定义下拉刷新功能的ListView》、android listview 自定义的好处的相关知识,请在本站进行查询。

本文标签: