Mark一个今天被坑了很久的小问题
需求
实现脸萌的创作界面(如下)
而工作重点是实现底下的格子页面,有选中效果,格子间有间隔线。
方法
由于顶部的滑动条和底部的格子界面需要同步滑动,决定采用第三库 ViewPagerIndicator,底部自然是用 ViewPager 嵌套 Fragment,Fragment 的主要内容是格子页面。格子页面用 GridView 实现(不想用最新的 RecyclerView,因为对 Item 点击事件的支持不好)。
难点
仔细观察 GridView 的 Item ,发现其由一张图片、间隔线以及选中时的提示框组成。因此我用如下的布局文件实现(注意 GridView 的 Item 中最好不要放 Button 之类的,否则 GridView 的 Item 点击事件拿不到):
1 | <?xml version="1.0" encoding="utf-8"?> |
ImageView
主要放图片( ImageResource )和边框间隔线( BackgroundResource ),选中效果我一开始是用 GridView
的 listSelector 属性来做,然而此处遇到第一个坑,见下图:
[屏幕快照 2016-06-29 下午6.56.28](/images/2016-6-29/屏幕快照 2016-06-29 下午6.56.28.png)
[屏幕快照 2016-06-29 下午6.56.52](/images/2016-6-29/屏幕快照 2016-06-29 下午6.56.52.png)
在快速滚动 GridView 的时候,选中框出现滚动 bug,找了好多资料,貌似没人遇到这种问题,只能作罢(另外,我在写 selector 文件的时候发现,当我把 state_selected
设为 false 时,GridView 的表现反而是选中状态,不明所以)。我又上网查了其他方案,结果都是些怎么改变 listSelector 样式啊之类的。还有一些是建议在 Item 最外层的 LinearLayout
上加 selector,然后在 GridView 的 ItemClickListener 中设置监听手动更换背景。我想,如果 listSelector 的思路不行的话,这个方法应该是唯一的解决方案了。于是,我将 LinearLayout
的 background 设为 selector,然后在 OnItemClickListener 中手动设置,大致代码如下:
1 | gridView.setOnItemClickListener(new AdapterView.OnItemClickListener() { |
然而这样做,虽然点击的时候会出现选中框,但滑动 GridView,再滑回去时,选中框消失了。后来又试了在 Adapter 的 getView 方法中设置,都没什么效果。之后,我突然想起以前用 ListView 的时候,曾经踩过 CheckBox 的选中状态因为滚动而重置的情况,于是我猜测选中框的消失可能和适配器中 View 的重用有关。所以,干脆另辟蹊径,用一个 boolean 数组记录每个 Item 的选中状态,然后每次调用 getView 函数时,根据数组刷新 Item,也就是放弃 GridView 中的 setSelection 方法,手动更换背景。于是得到最终的代码:
1 | gridView.setOnItemClickListener(new AdapterView.OnItemClickListener() { |
以下是 Adapter 的部分代码:
1 | class GridAdapter extends BaseAdapter { |
在 OnItemClickListener 中修改 Adapter 的数据并刷新 View,在 getView 中根据 boolean 数组手动设置背景,结果证明有效。