前两天测试组反馈一个bug,列表(实质上是一个ListView)在OPPO R6手机上无法显示底部:ListView可以滑动,但是底部的选项框无法显示。
ListView用法科普
ListView相信很多人都使用过,甚至有些小伙伴都已经开始使用RecyclerView了,它经常用来做列表。基本用法如下:
ListView listView = findViewById(resId);
BaseAdapter adapter = new MyBaseAdapter(Context, Arraylist);
listView.setAdapter(adapter);
adapter.notifyDataSetChanged();
但是如果需要在顶部/底部展示一个不同于其他item的view该怎么办呢?两种办法:
- 方法一:复写BaseAdapter的getItemViewType(int position);getViewTypeCount()两个方法,不具体展开,与本文无关。
- 方法二:使用ListView.addHeadView(headView),ListView.addFootView(footView)。用法如下:
ListView listView = findViewById(resId);
BaseAdapter adapter = new MyBaseAdapter(Context, Arraylist);
listView.setAdapter(adapter);
View headView = (View) LayoutInflater.from(this).inflate(R.layout.headview, null);
View footView = (View) LayoutInflater.from(this).inflate(R.layout.footview, null);
listView.addHeadView(headView);
listView.addFootView(footView);
adapter.notifyDataSetChanged();
Demo效果如下图:
结果,我们的项目在OPPO R6手机上超出了一屏,只能滑动显示到最后一个normal item,却无法查看到底部的footView,其他手机上正常显示。Why???
纠结了一下,将以上方法二的代码修改如下:
ListView listView = findViewById(resId);
BaseAdapter adapter = new MyBaseAdapter(Context, Arraylist);
View headView = (View) LayoutInflater.from(this).inflate(R.layout.headview, null);
View footView = (View) LayoutInflater.from(this).inflate(R.layout.footview, null);
listView.addHeadView(headView);
listView.addFootView(footView);
listView.setAdapter(adapter);// 将设置适配器的操作延后
adapter.notifyDataSetChanged();
一行代码的改动,OPPO R6上FootView神奇的显示出来了!!!
源码分析
请看ListView.setAdapter(adapter)部分源码:
...
if (mHeaderViewInfos.size() > 0|| mFooterViewInfos.size() > 0) {// 如果headView的集合,或者footView的集合不为空,就进行Adapter转换
mAdapter = new HeaderViewListAdapter(mHeaderViewInfos, mFooterViewInfos, adapter);
} else {
mAdapter = adapter;// 没有执行添加头部和尾部的操作
}
...
请看ListView.addFootView(footView)部分源码;
...
// Wrap the adapter if it wasn't already wrapped.
if (mAdapter != null) {// 执行过了setAdapter(adapter)
if (!(mAdapter instanceof HeaderViewListAdapter)) {// 如果Adapter没进行过转换,就转换
mAdapter = new HeaderViewListAdapter(mHeaderViewInfos, mFooterViewInfos, mAdapter);
}
...
}
由以上源码可以看出,无论是先添加FootView还是先setAdapter,mAdapter都会被转换成HeaderViewListAdapter,其中HeaderViewListAdapter和BaseAdapter一样,都是ListAdapter的实现类,是对BaseAdapter的二次封装。
我的推断
所以我推断,有可能是在OPPO的framework源码中,ListView.addFootView(footview)方法中,有可能是这样的:
...
// Wrap the adapter if it wasn't already wrapped.
if (mAdapter != null) {// 执行过了setAdapter(adapter)
if (!(mAdapter instanceof HeaderViewListAdapter)) {// 如果Adapter没进行过转换,就转换
// mAdapter = new HeaderViewListAdapter(mHeaderViewInfos, mFooterViewInfos, mAdapter);// 这行代码被人无意中注释或删除了
}
...
}
不知道是否猜测正确,仅供参考。
解决办法
所以,解决ListView的底部在OPPO等手机上无法显示的办法就是,将setAdaper(adapter)操作放在addFootView(footview)之后进行。希望对大家有所帮助。