Android ListView selected默认选中第一个position解决办法
最近在做一个实验键盘完成一个购物的流程,其中就涉及到使用键盘方向键控制ListView中的Item选中状态。本以为通过实现OnItemSelectedListener接口就可以实现功能,事实上并不能满足需求。
出现的问题是这样的: 每次进入页面,都会选中第一条,但是这时按下方向键“下”也会选中第一条,但是这时候却不会触发
OnItemSelectedListener
接口中的onItemSelected
方法,所以使用方向键“下”首次无法监听到事件。到处百度、谷歌了很久未果,就自定义了一个ListView,解决了问题。之所以出现默认选中position==0,肯定出在焦点问题上。虽然不知道google当时为什么默认选中第一个,但是确实给开发者造成了一定的困扰,有时候我们不想要那么智能,灵活性好我们能做的会更多更好。既然是焦点问题,我们就要重写
protected void onFocusChanged(boolean gainFocus, int direction,Rect previouslyFocusedRect)
方法。出现问题的地方只是在position==0
和position==size-1
,即首末两个item
,我们只需要关注这两个即可,也就是
getSelectedItemPosition()
== 0 || getSelectedItemPosition() == getCount()-1
再去执行我们处理的方法就行了。
- 思路有了,下面上代码:
package com.wz.tv;
import android.content.Context;
import android.graphics.Rect;
import android.util.AttributeSet;
import android.util.Log;
import android.view.KeyEvent;
import android.view.View;
import android.widget.AdapterView;
import android.widget.ListView;
/**
* Created by zhangzhenguo on 2017/2/17.
* 支持键盘操作的ListView
*/
public class TVListView extends ListView {
private EventListener mEventListener;
/**
* 当前选中的item
*/
private int mSelectPosition = -1;
/**
* 失去焦点时选中的position
*/
private int mLastSelectPosition = -1;
public TVListView(Context context) {
this(context,null);
}
public TVListView(Context context, AttributeSet attrs) {
this(context, attrs,0);
}
public TVListView(Context context, AttributeSet attrs, int defStyleAttr) {
super(context, attrs, defStyleAttr);
EventItemSelectedListener mEventItemSelectedListener = new EventItemSelectedListener();
this.setOnItemSelectedListener(mEventItemSelectedListener);
}
@Override
public boolean dispatchKeyEvent(KeyEvent event) {
if (mEventListener != null) {
if (event.getKeyCode() == KeyEvent.KEYCODE_ENTER && event.getAction() == KeyEvent.ACTION_UP) {
mEventListener.onEnterEvent(mSelectPosition);
}
}
return super.dispatchKeyEvent(event);
}
@Override
protected void onFocusChanged(boolean gainFocus, int direction, Rect previouslyFocusedRect) {
super.onFocusChanged(gainFocus, direction, previouslyFocusedRect);
if (mEventListener == null) {
return;
}
if (gainFocus) {// TODO 为了解决selected事件首次进入即position==0时不执行的问题
if (getSelectedItemPosition() == 0 || getSelectedItemPosition() == getCount()-1) {
//item == 0时,即列表第一条itemView获取焦点时
if (mLastSelectPosition == -1 || mLastSelectPosition == 0){
Log.d("zzg","mLastSelectPosition:"+mLastSelectPosition);
mSelectPosition = getSelectedItemPosition();
setSelect();
}
//item == size-1,即列表最后一条itemView获取焦点时
if (getSelectedItemPosition() == getCount()-1 && mLastSelectPosition == getCount() -1){
Log.d("zzg","mLastSelectPosition:"+mLastSelectPosition);
mSelectPosition = getSelectedItemPosition();
setSelect();
}
}
}else {
mLastSelectPosition = mSelectPosition;
mSelectPosition = -1;
mEventListener.onNextMenu(getSelectedItemPosition());
}
}
/**
* 回调select监听
*/
private void setSelect(){
final int[] location = new int[2];
getSelectedView().getLocationOnScreen(location);
mEventListener.onItemSelected(getSelectedItemPosition(),location[1]);
}
public class EventItemSelectedListener implements OnItemSelectedListener{
@Override
public void onItemSelected(AdapterView<?> parent, View view, final int position, long id) {
mSelectPosition = position;
if (mEventListener != null && isFocused()) {
setSelect();
}
}
@Override
public void onNothingSelected(AdapterView<?> parent) {
mSelectPosition = -1;
}
}
public void setOnEnterEventListener(EventListener eventListener){
this.mEventListener = eventListener;
}
public EventListener getOnEnterEventListener(){
return this.mEventListener;
}
public interface EventListener{
/**
* Enter键监听
* @param position 当前点击的item position,只适用于键盘的Enter键,如果既想使用键盘Enter键又想用鼠标点击请直接实现OnItemClickListener接口
*/
void onEnterEvent(int position);
/**
* item selected监听
* @param position selected item position
* @param rawY 当前选中ItemView 在屏幕中的y轴坐标
*/
void onItemSelected(int position, float rawY);
/**
* 离开ListView时,记录当前选中的position
* @param position 焦点离开ListView时选中的item position
*/
void onNextMenu(int position);
}
}