ListView中的条目获取焦点时更换背景。
需求
最近有一个需求,一个ListView
或者RecyclerView
或者ListPopupWindow
列表。这三个控件都是类似的,其实可以认为是同一个控件,因为本质上其实都是列表展示的控件。列表的item在获取到焦点的时候需要和其他的item区别开来,背景换个颜色。做了好几次尝试,最后找到了比较好的解决办法,这里记录下来。
分析
这里的问题有两个:①是获取到焦点,比如用手柄去控制手机的时候,通过手柄摇杆去控制焦点的移动,这个时候,不会触发click事件。②listview这一类的列表,本身是一个view控件,其每一个item又是一个view,这就存在view之间焦点的转移问题。
解决的逻辑
其实解决的逻辑非常简单:
思路一:既然是获取焦点的时候改变背景,那当然是需要监听焦点变化,
@Override
public View getView(int position, View convertView, ViewGroup parent) {
View view= LayoutInflater.from(context).inflate(R.layout.pop_item_server_ip_layout,parent,false);
view.setOnFocusChangeListener(new View.OnFocusChangeListener() {
@Override
public void onFocusChange(View view, boolean hasFocus) {
if (hasFocus){
view.setBackgroundColor(context.getResources().getColor(R.color.white));
}else{
view.setBackgroundColor(context.getResources().getColor(R.color.transparent));
}
}
});
}
刚开始,我也是按照这样的逻辑去解决的,但是实际上并没有起到效果,时间问题,我并没有深究,但是可以确定的是焦点并没有监听到,这样说来焦点就没有到达这个item
上来。所以不管如何尝试都是没有任何效果,不会改变背景的。
如果一定要,从这个思路解决这个问题,也不是不可以,就是让焦点穿透进来,怎么穿透,listview
的API
里面提供了方法。
可以参考:https://blog.csdn.net/dcqboke/article/details/38588695
思路二:Adapter
的getView()
方法里面是负责绘制item的,改变背景就在这里进行控制,肯定是没问题的。但是哪个item获取到了焦点,它的position
得传递进来,然后Adapter需要notifyDataSetChanged()
,
按照这个思路,
问题来了,怎么监听到哪个item获取到了焦点呢?
非常简单,通过setOnItemSelectedListener
这个监听方法就可以监听到,这个监听在新的API里出现的,之前一直在使用的setOnItemClickListener
这个监听,两个监听可以同时存在和使用。
首先,在Adapter里面写一个方法,getSelectionPosition(int selecPosition)用于将获取到焦点的item的position传递进Adapter。
public class PopServerAdapter extends BaseAdapter {
private Context context;
private List<ServerPopBean> list;
private int selecPosition=-1;
public void setSelecPosition(int selecPosition){
this.selecPosition=selecPosition;
}
public PopServerAdapter(Context context,List<ServerPopBean> list){
this.context=context;
this.list=list;
}
@Override
public int getCount() {
return list.size();
}
@Override
public Object getItem(int position) {
return list.get(position);
}
@Override
public long getItemId(int position) {
return position;
}
@Override
public View getView(int position, View convertView, ViewGroup parent) {
View view= LayoutInflater.from(context).inflate(R.layout.pop_item_server_ip_layout,parent,false);
if (selecPosition==position){
view.setBackgroundColor(context.getResources().getColor(R.color.white));
}else{
view.setBackgroundColor(context.getResources().getColor(R.color.transparent));
}
TextView name=view.findViewById(R.id.item_serverIpTV);
name.setText(list.get(position).getServer_name());
return view;
}
}
其次,在ListPopupWindow 的OnitemSelection监听中调用此方法将获取到焦点的postion传递进Adapter,不能忘记notify整个adapter,否则是没有效果的。
ListPopupWindow listPopupWindow.setOnItemSelectedListener(new AdapterView.OnItemSelectedListener() {
@Override
public void onItemSelected(AdapterView<?> parent, View view, int position, long id) {
// Toast.makeText(ServerSetting2Activity.this, "has focus", Toast.LENGTH_SHORT).show();
// 选中的那一项item背景给设置颜色
popServerAdapter.setSelecPosition(position);
popServerAdapter.notifyDataSetChanged();
}
@Override
public void onNothingSelected(AdapterView<?> parent) {
}
});
结束,这样就完成了需求了。
效果图
demo的GitHub地址
https://github.com/jakezhang1990/ListPopChangeItemBgDemo
参考链接
https://blog.csdn.net/u013894427/article/details/53130397
https://blog.csdn.net/dcqboke/article/details/38588695