ListView 中 getSelectedView() 和 getSelectedItem() 区别

来源:互联网 发布:淘宝试用官网 编辑:程序博客网 时间:2024/06/11 18:09

本文是基于作者遇到的一个bug而来,如果正常情况下,可以不考虑本文做法。


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

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

    /**     * @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设置为了convertViewtag了,也就是(getSelectedView().getTag() instanceof itemView) )。

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

    public int getSelectedItemPosition() {        return mNextSelectedPosition;    }

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

再看到getSelectedView()的源码

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

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

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


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

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()得到的itemViewpos = 1viewgetSelectedItem()得到的itemViewpos = 2view。(怎么知道的?通过打印getView()里面所有positionitemView对比 id 号得出)

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

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


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

效果变成了:
这里写图片描述


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

完整效果图示:

1.作为第一焦点时

这里写图片描述

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

这里写图片描述

3.按下,第二焦点切换

这里写图片描述

/** * ━━━━━━神兽出没━━━━━━ *    ┏┓   ┏┓ *   ┏┛┻━━━┛┻┓ *   ┃       ┃ *   ┃   ━   ┃ *   ┃ ┳┛ ┗┳ ┃ *   ┃       ┃ *   ┃   ┻   ┃ *   ┗━┓   ┏━┛  看不懂,没关系.. *     ┃   ┃     *     ┃   ┗━━━┓ *     ┃       ┣┓ *     ┃       ┏┛ *     ┗┓┓┏━┳┓┏┛ *      ┃┫┫ ┃┫┫ *      ┗┻┛ ┗┻┛ * * ━━━━━━神兽保佑,代码无bug━━━━━━ */
0 0
原创粉丝点击