您的位置:首页 > 其它

ListView 中 getSelectedView() 和 getSelectedItem() 区别

2015-11-11 16:44 447 查看
本文是基于作者遇到的一个bug而来,如果正常情况下,可以不考虑本文做法。

从官方的注释上看
getSelectedView()
好像是得到当前选中的 item 的
view
getSelectedItem()
得到的当前选中的 item 所绑定的数据。这两个得到的数据类型都不相同怎么比较?

首先,看到
getSelectedItem()
的源码 实现:

[code]    /**
     * @return The data corresponding to the currently selected item, or
     * null if there is nothing selected.
     */
    public Object getSelectedItem() {
        T adapter = getAdapter();
        int selection = getSelectedItemPosition();
        if (adapter != null && adapter.getCount() > 0 && selection >= 0) {
            return adapter.getItem(selection);
        } else {
            return null;
        }
    }


可以看到 return 的是
adapter.getItem(selection)
,也就是我们要重写的 Adapter 里面的
getItem()
函数。如果重写的时候我们返回的不是
data
数据,而是当前选中的
itemView
(自定义的view)的话,就可以与
getSelectedView()
相比较了(在重写
getView()
里面,已经把自定义的
itemView
设置为了
convertView
tag
了,也就是
(getSelectedView().getTag() instanceof itemView)
)。

再接着看
int selection = getSelectedItemPosition();
,点击看到
getSelectedItemPosition()
的源码:

[code]    public int getSelectedItemPosition() {
        return mNextSelectedPosition;
    }


返回的是
mNextSelectedPosition
!下一个位置!

再看到
getSelectedView()
的源码

[code]public View getSelectedView() {
        if (mItemCount > 0 && mSelectedPosition >= 0) {
            return getChildAt(mSelectedPosition - mFirstPosition);
        } else {
            return null;
        }
    }


由于一般
mFirstPosition
的值为0,所以也可以看作是返回
getChildAt(mSelectedPosition)
当前选中的位置!

根据源码可以看出这两个方法得到的数据是有一点区别的,可是我们平时用的时候好像完全感觉不到,直到遇到特定的情况的时候,也就是我遇到的bug。

项目有个需求,是在右边的
Fragment
切换时,左边的菜单
ListView
会刷新选中项,并且选中项改变时,做一些效果(选中和失去)。我给
ListView
注册了一个监听器
OnFocusChangeListener
,代码如下:

[code]OnFocusChangeListener onFocusChangeListner = new OnFocusChangeListener() {
    @Override
    public void onFocusChange(View v, boolean hasFocus) {
        Log.d(TAG, "hasFocus = " + hasFocus + ", pos = " + menuListView.getSelectedItemPosition());
        Log.d(TAG, "getSelectedView = " + menuListView.getSelectedView().getTag());
        Log.d(TAG, "getSelectedItem = " + menuListView.getSelectedItem());

        if (hasFocus) {
            //给菜单ListView选中项设置为“第一焦点”
            setFirstFocus();
        } else {
            //给菜单ListView选中项设置为“第二焦点”
            setSecondFocus();
        }
    }
};

menuListView.setOnFocusChangeListener(onFocusChangeListner);


为什么要这样做,就是因为
menuListView
有两种状态的焦点,一种是选中时并且也得到焦点时(称为“第一焦点”),另一种是选中时但是焦点不在上面(称为“第二焦点”)。


第一焦点

第二焦点

接下来执行操作,当选中项为“媒体”且焦点不在
ListView
上时,切换右侧
Fragment
到“应用”,这个时候理想状况是“第二焦点”状态转移到“应用”。

我的做法是:在
setFirstFocus()
中得到当前选中
menuListView.getSelectedView().getTag()
设置为第一焦点文字颜色;在
setSecondFocus()
中得到当前选中
menuListView.getSelectedView().getTag()
设置为第二焦点文字颜色。(这里不考虑红色块背景以及右侧红色条,因为不属于ListView里面的部分,为了有滑动动画,是用
ImageView
另外做的)。

当两个方法使用的都是
getSelectedView()
时,效果变成了这个样子:



看打印发现
onFocusChange
调用了两次,第一次打印
hasFocus = true, pos = 2
;第二次打印
hasFocus = false, pos = 2


getSelectedView().getTag()
得到的
itemView
pos = 1
view
getSelectedItem()
得到的
itemView
pos = 2
view
。(怎么知道的?通过打印
getView()
里面所有
position
itemView
对比 id 号得出)

如前言所述,
getSelectedItem()
得到的是
getSelectedView()
的下一项!

可以根据现象证明,两次调用第一次把“媒体”设置为了第一焦点,第二次把“媒体”设置为了第二焦点。这显然不是我想要的结果。根据“应用”选项放大也可以看出现在选中项是“应用”。

如果这样调整:在
setFirstFocus()
setSecondFocus()
中把
menuListView.getSelectedView().getTag()
替换为
menuListView.getSelectedItem()


效果变成了:



很明显,应该改成
setFirstFocus()
里面调用
menuListView.getSelectedView().getTag()
setSecondFocus()
里面调用
menuListView.getSelectedItem()


完整效果图示:

1.作为第一焦点时



2.按右,作为第二焦点时



3.按下,第二焦点切换



[code]/**
 * ━━━━━━神兽出没━━━━━━
 *    ┏┓   ┏┓
 *   ┏┛┻━━━┛┻┓
 *   ┃       ┃
 *   ┃   ━   ┃
 *   ┃ ┳┛ ┗┳ ┃
 *   ┃       ┃
 *   ┃   ┻   ┃
 *   ┗━┓   ┏━┛  看不懂,没关系..
 *     ┃   ┃    
 *     ┃   ┗━━━┓
 *     ┃       ┣┓
 *     ┃       ┏┛
 *     ┗┓┓┏━┳┓┏┛
 *      ┃┫┫ ┃┫┫
 *      ┗┻┛ ┗┻┛
 *
 * ━━━━━━神兽保佑,代码无bug━━━━━━
 */
内容来自用户分享和网络整理,不保证内容的准确性,如有侵权内容,可联系管理员处理 点击这里给我发消息
标签: