addHeaderView的一些注意点

在ListView中有时会需要添加addHeaderView或addFootView,或者两者兼或;

首先,我来一份简单的代码

TextView TextView=new TextView(this);
textView.setText("Hello");
listView.addHeaderView(textView);
自定义一个TextView,让他显示一句话"Hello",然后将它添加到Header中

这时候添加item点击事件,在点击事件中

PopwindowRightAdapter adapter = (PopwindowRightAdapter) parent.getAdapter();
想要获取Adapter,结果却报错

java.lang.ClassCastException: android.widget.HeaderViewListAdapter cannot be cast to 

说是HeaderViewListAdapter 不能被转化为我们自定义的那个Adapter,我这里的就是PopwindowRightAdapter

去addHeaderView中看一下源码

public void addHeaderView(View v, Object data, boolean isSelectable) {
        final FixedViewInfo info = new FixedViewInfo();
        info.view = v;
        info.data = data;
        info.isSelectable = isSelectable;
        mHeaderViewInfos.add(info);
        mAreAllItemsSelectable &= isSelectable;

        // Wrap the adapter if it wasn't already wrapped.
        if (mAdapter != null) {
            if (!(mAdapter instanceof HeaderViewListAdapter)) {
                mAdapter = new HeaderViewListAdapter(mHeaderViewInfos, mFooterViewInfos, mAdapter);
            }

            // In the case of re-adding a header view, or adding one later on,
            // we need to notify the observer.
            if (mDataSetObserver != null) {
                mDataSetObserver.onChanged();
            }
        }
    }

adapter被转化为了 HeaderViewListAdapter,就不是我们之前的那个adapter,

看一下他的构造方法:

public HeaderViewListAdapter(ArrayList<ListView.FixedViewInfo> headerViewInfos,
                                 ArrayList<ListView.FixedViewInfo> footerViewInfos,
                                 ListAdapter adapter) {
        mAdapter = adapter;
        mIsFilterable = adapter instanceof Filterable;

        if (headerViewInfos == null) {
            mHeaderViewInfos = EMPTY_INFO_LIST;
        } else {
            mHeaderViewInfos = headerViewInfos;
        }

        if (footerViewInfos == null) {
            mFooterViewInfos = EMPTY_INFO_LIST;
        } else {
            mFooterViewInfos = footerViewInfos;
        }

        mAreAllFixedViewsSelectable =
                areAllListInfosSelectable(mHeaderViewInfos)
                && areAllListInfosSelectable(mFooterViewInfos);
    }

我也看不太懂,大概意思就是把header放到一个List中,footer放到一个List当中,然后和之前的数据集合到一块整合成一个新的Adapter;不过,位置是不同的,一个放头部,一个放底部

再回到之前的那个报错问题,我在网上查了一下,有人给出如下方案:

地址:http://blog.csdn.net/sunxingzhesunjinbiao/article/details/9952997

ListView listView = getListView();
                //ConversationListAdapter adapter = (ConversationListAdapter) listView.getAdapter();
    ConversationListAdapter adapter = null;
    if(listView.getAdapter() instanceof HeaderViewListAdapter) {
    HeaderViewListAdapter listAdapter=(HeaderViewListAdapter)listView.getAdapter();
adapter = (ConversationListAdapter) listAdapter.getWrappedAdapter();
    } else {
    adapter = (ConversationListAdapter) listView.getAdapter();
    }    
大概意思就是他们遇到的问题是在setAdapter之后才addHeaderView导致的问题
还有一个解决方案:

地址;http://www.xuebuyuan.com/984745.html

cannot be cast to android.widget.HeaderViewListAdapter
用listview设置header或footerview,通常发生该异常。

如果你没有发生,那是碰巧。但是你可能不知道原因。

如果在listview.setAdapter(adapter)方法之后 添加头或尾view,

即addHeaderView或 addFooterView,

那么在你listView.removeHearderView或removeFooterView时就会报该异常。

在Listview的源码中如果设置了adapter,那么它会强转成HeaderViewListAdapter,所以就会报错。

if (mAdapter != null && ((HeaderViewListAdapter) mAdapter).removeHeader(v)) {
     if (mDataSetObserver != null) {
         mDataSetObserver.onChanged();
     }
     result = true;
}

。

所以你一定要在setAdapter之前调用addHeaderView或addFooterVeiw.
都是顺序问题,导致发生了Adapter转换;之前的源码能看到

if (mAdapter != null) {
            if (!(mAdapter instanceof HeaderViewListAdapter)) {
                mAdapter = new HeaderViewListAdapter(mHeaderViewInfos, mFooterViewInfos, mAdapter);
            }

            // In the case of re-adding a header view, or adding one later on,
            // we need to notify the observer.
            if (mDataSetObserver != null) {
                mDataSetObserver.onChanged();
            }
        }
mAdapter不为空的时候直接转换了,
还看到一个转换的blog,地址: http://blog.sina.com.cn/s/blog_6d45d11f01014n1c.html
private OnItemClickListener mItemClickListener = new OnItemClickListener() {
@Override
public void onItemClick(AdapterView<?> parent, View view, int position,
long id) {
HeaderViewListAdapter ha = (HeaderViewListAdapter) parent.getAdapter();
JobsAdapter ad = (JobsAdapter) ha.getWrappedAdapter();
ad.toggle(position-1);
}
};

HeaderViewListAdapter有个方法getWrappedAdapter,该方法能返回被包装的HeaderViewListAdapter的ListAdapter。

说实话,这句话我没看懂,我还是不知道getWrappedAdapter是干什么用的,看了一下它的API说明

Returns the adapter wrapped by this list adapter.

我理解的意思就是返回当前包装的adapter,大概就是转换成当前的adapter的意思吧,猜的。。。估计差不远

我用面的方式试了一下,除了这个toggle搞不出来,其余的差不多

那个报错解决完之后,还有一个顺序的问题,添加了一个header,他的position就是0了,然后之前的顺移,这样就需要用到那个toggle,不过我失败了,怎么也找不到这方法,然后我就用下面的

JBean pCarea = adapter.getItem(position-1);
,这样就可以依次取到之前的item的点击事件了,然后问题又来了,因为header也在,点击她的时候,她的position就是-1了,当时我想的是专门针对这个-1处理一下,做个判断处理一下,随后又感觉到不行,这只是一个header,如果有多个呢,然后又去找了一下资料,发现addView还有另一个重载方法addheadView(),对,就是最开始那个

我最初是用的这个

 public void addHeaderView(View v) {
        addHeaderView(v, null, true);
    }

后来才发现另一个重载方法的

public void addHeaderView(View v, Object data, boolean isSelectable)
主要在于最有一个参数,他设置header不被选中,就不会触发点击事件也就是-1也没事;

设置多个addHeaderView的时候就可以给header添加点击事件OncliickListener,用来覆盖onItemClickListener,同时,之前的item获取item的时候,需要用position减去header的个数

然后又有一个问题,那就是item中的子控件焦点之争;

地址:http://blog.csdn.net/iblade/article/details/50958295

当使用itemClickListener的时候,item里面的子控件如button会夺取焦点,这时候就有一个方法:

setDescendantFocusability(ViewGroup.FOCUS_BLOCK_DESCENDANTS);


在ListView的xml中也可以设置

地址:http://www.cnblogs.com/eyu8874521/archive/2012/10/17/2727882.html

android:descendantFocusability
它有三个可选值:

beforeDescendants:viewgroup会优先其子类控件而获取到焦点

        afterDescendants:viewgroup只有当其子类控件不需要获取焦点时才获取焦点

        blocksDescendants:viewgroup会覆盖子类控件而直接获得焦点


这样,应该是差不多了。




  • 0
    点赞
  • 1
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值