我用 SimpleAdapter 作为 ListView 的适配器,自定义了一个布局,里面有一个 ImageView 和一个 TextView ,我想要实现 ListView 的每一项都是文字加图片的效果。布局文件如下: <ImageView
android:id="@+id/ItemImage"
android:layout_alignParentRight="true"
android:layout_marginRight="20sp"
android:layout_width="30sp"
android:layout_height="30sp"
android:visibility="gone"
/>
<TextView
android:id="@+id/ItemText"
android:layout_width="match_parent"
android:layout_height="wrap_content"
android:layout_marginLeft="20sp"
android:textSize="20sp" />
我设置了 android:visibility="gone",是想开始的时候让图片不显示,在需要显示的地方再显示。然后我点击某个按钮后,想让此图片显示。所以我先遍历 ListView ,然后得到这个 ImageView 对象,再设置它的可见性,代码如下( set 是一个按钮):
set.setOnClickListener (new OnClickListener () {
@Override
public void onClick (View v ) {
//全选遍历 ListView 的选项,每个选项就相当于布局配置文件中的 RelativeLayout
for (int i = 0; i < cityListView.getCount (); i++){
RelativeLayout layout =
(RelativeLayout ) cityListView.getAdapter ().getView (i, null, null );
ImageView image = (ImageView ) layout.getChildAt (0 );
image.setImageResource (R.drawable.delete );
image.setVisibility (View.VISIBLE );
}
}
});
可是都设置完成后,先前隐藏的图片还是都没显示,不知道什么愿因,
ps :我的目的是让 ListView 里面被隐藏的图片显示出来,不知道是不是应该这样做
1
jimmy 2015-08-25 18:16:00 +08:00
执行了 adapter.notifyOnDataChange 了吗?
|
2
xhuuanniqege 2015-08-25 18:24:43 +08:00 via Android
正常的做法是在 adapter 里面设置一个辅助数组保存 imageview 的状态,在 getview 方法中根据这个数组设定 imageview 的可见性。当当按下按钮后,改变状态数组的内容然后 notifydatachange 。你遍历每个 view 没用的,因为当 view 看不见时会被回收。
|
3
ljbha007 2015-08-25 18:35:26 +08:00
首先你这么写代码的习惯很不好 耦合性太高 万一布局一变 imageview 不是在第 0 个了 代码就失效了 应该像楼上说的这么写
其次 千万不要手动调用 getView 方法 如果你 getView 方法里根据 xml 渲染了一个 listView 里的一行的话 你再次调用还会再渲染一次 而且还会触发 listView 的 view 循环利用机制 非常浪费 |
4
kx5d62Jn1J9MjoXP 2015-08-25 19:13:39 +08:00 via Android
难道是因为 textview android:layout_width="match_parent"覆盖了?
不过不管是什么原因,你这写法都很不常规 |
5
Bown 2015-08-25 19:17:48 +08:00
cityListView.getAdapter ().getView (i, null, null ) 改成 cityListView.getChildAt (i )
|
6
JayFang1993 2015-08-25 19:19:14 +08:00
一看就是新手,问问题的问法以及代码一看就像是来自百度知道的那种,拉低了 v 站的逼格~
|
7
Bown 2015-08-25 19:20:59 +08:00
没仔细看题。。 都有 view 重用,正确做法是 adapter 里面一个 list 记录每个 item 的状态是否 visible , getView 里面根据对应 index 的状态设置 visibility ,然后点击事件里面修改这个状态记录再 notifyDataSetChange
|
8
allan1st 2015-08-25 19:55:46 +08:00 via Android
你这样写 ListView 还有什么意义,建议把 ListView 原理好好看几遍。另外,请尽量转用 RecyclerView 。
|
9
creatorYC OP @JayFang1993 按您的说法,新手应该去哪呢?
|
13
anthonyeef 2015-08-25 20:48:43 +08:00 via Android
@xhuuanniqege 回答的很好啊也很耐心
|
14
kx5d62Jn1J9MjoXP 2015-08-25 20:50:01 +08:00 via Android
@creatorYC 我不知道你是哪里学的,反正随便搜索 listview 的用法都不是这样的。
因为 listview 里面的子 view 对象是会被回收重复利用的,所以就算这个写法一开始能正常工作,只要滑动几下,一个 view 滑出屏幕就会被回收,用到别的 position 去。 入门推荐 udacity 的免费课程 |
15
creatorYC OP @xhuuanniqege 我刚学没多久,请问您有没有什么好的学习建议,或者能不能推荐一些书以及博客之类的,不胜感激
|
16
gengrui 2015-08-25 21:56:38 +08:00
看了下代码,说下个人看法。
从 layout 上看,应该是一个 RelativeLayout ,在 adapter 里面应该是左边有一个 TextView, 右边有一个 ImageView ,左右两边分别有 20sp 的 padding 。我的看法其实和 @ssynhtn 一样,看起来是 TextView 覆盖了 ImageView ,因为 TextView 的 android:layout_width 属性是 match_parent ,建议你: 1 改成"wrap_content",或者; 2 在 TextView 里面加上 android:layout_toLeftOf="@+id/ImageView", 或者; 3 把 TextView 和 ImageView 在 XML 文件里面换个位置,先定义 TextView ,再定义 ImageView 。 我没有在代码里尝试,但是凭经验来说,上述任何一个方法应该都能起码把 ImageView 给显示出来。 下面说说在 setOnClickListener 里面的 code 。一般来说不建议直接调用 getView 这个方法,因为这里面的逻辑是得到一个重绘的 View 。如果放在 for 循环从 0 到 list.getCount 的话,则相当于重绘这个 ListView 里面所有的 Item ,这是相当耗费资源的。建议你按照 @xhuuanniqege 提供的办法,在 Object 里面增加一个辅助的 flag 来定义这个 ImageView 的 visibility 。之后的 code 则类似于: // 假设你的 model 是 TextObject.class List<TextObject> mTextObjects = new ArrayList<TextObject> (); ListView mListView = (ListView ) findViewById (...); CustomAdapter<TextObject> mAdapter = new CustomAdapter (this, R.layout.xxx, mTextObjects ); set.setOnClickListener (new OnClickListener () { @Override public void onClick (View v ) { //全选遍历 ListView 的选项,每个选项就相当于布局配置文件中的 RelativeLayout for (int i = 0; i < cityListView.getCount (); i++){ mTextObjects.get (i ).setImageViewVisibility (true ); } mAdapter.notifyDatasetChanged (); } }); 希望对你有帮助。 |
17
kx5d62Jn1J9MjoXP 2015-08-25 22:01:40 +08:00
好吧,反正不是 textview 遮挡的问题,因为 textview 的背景色默认是透明的
|
19
creatorYC OP @gengrui 我刚接触 android 不久,我应该去详细了解一下 ListView 的机制和原理,您的意思是说我应该设置标记去更新相应的 item 的可见性,而不应该每次都是去重绘 item ,的确我没有考虑到这些,没有考虑到代码的优化,多谢您的指点,我会尝试着改变这个写法,谢谢您详细的解答
|
22
xhuuanniqege 2015-08-25 22:19:41 +08:00 via Android 1
@creatorYC 新手用这个方法也说明挺动脑筋的了,多写多练,多谷歌,能力很快会提高的
|
24
kx5d62Jn1J9MjoXP 2015-08-25 22:27:28 +08:00
我知道问题了,原因是你主动调用了 getView ,下面是 SimpleAdapter 的 getView 方法,因为传入的 convertView 是 null ,所以会新建一个 view ,这个 view 不会被 ListView 使用,因为只有 ListView 调用 getView 返回的那个 view 会被 ListView 使用,所以你对这个 view 进行任何操作都是没有任何用的
/** * @see android.widget.Adapter#getView (int, View, ViewGroup ) */ public View getView (int position, View convertView, ViewGroup parent ) { return createViewFromResource (position, convertView, parent, mResource ); } private View createViewFromResource (int position, View convertView, ViewGroup parent, int resource ) { View v; if (convertView == null ) { v = mInflater.inflate (resource, parent, false ); } else { v = convertView; } bindView (position, v ); return v; } |
25
kx5d62Jn1J9MjoXP 2015-08-25 22:28:15 +08:00
我之前说 textview 覆盖 imageview 的那个解释是错误的,以为 textview 的 background 默认是透明的
|
27
creatorYC OP |
28
kx5d62Jn1J9MjoXP 2015-08-25 22:51:34 +08:00
@creatorYC 继承 BaseAdapter 或者 ArrayAdapter ,建一个 model 类{text, image, visible}作为一行, Adapter 中保持一个 List<Model>,当需要对某一行的图片进行隐藏的时候对那一行的 model 的 visible 设为 false ,接着调用 Adapter.notifyDatasetChanged
如果听不懂的话,善用 Google ,而且我真的很推荐 udacity 的免费 Android 课程 |
30
kaient 2015-08-26 11:53:48 +08:00
我觉得吧,如果你把 imageView 的的 GONE 变成 INVISIBLE 应该就对了
|
31
creatorYC OP @xhuuanniqege 请问你们都是怎么谷歌的,翻墙了还是用什么 vpn 啊
|
32
xhuuanniqege 2015-08-26 18:41:35 +08:00 via Android
@creatorYC 翻墙了
|
33
wzg1015 2015-08-27 11:41:32 +08:00
1.看见你的宽度啥都用 sp 就蛋疼
2.贴代码就贴全, ImageView 的父布局都不贴,你怎么知道一定是这个 imageView 的问题? 或许就是你 item 的布局就错误了呢,导致 imageView 无处显示呢 3.上面是布局,下面是代码,一个字乱,何况代码就光一个监听,你就知道其他地方都正确?或许我们累死累活的找 bug ,结果发现就因为你这句语句没调用呢 4.ImageView image = (ImageView ) layout.getChildAt (0 ); 很少见到这种写法,哪天你把图片放后面了,然后就报错了 5.RelativeLayout layout =(RelativeLayout ) cityListView.getAdapter ().getView (i, null, null ); 如同 @ssynhtn 所说,你这根本就是创建了一个新的 view ,你显示它的图片,并没有卵用。 6.如果让我写这个,我会将需要显示的数据放在一个 List 集合中,其元素就是每一行需要显示的图片( id ),文字,其中有个属性为是否显示图片,默认为不显示。 将 List 集合传给 adapter 。当点击按钮的时候,修改 list 内部数据,调用 adapter 的 notifyOnDataChange 。 这样逻辑在 activiy 里实现,显示在 adpter 实现。 |
34
creatorYC OP |
35
quiz 2015-08-28 12:43:47 +08:00
|
36
quiz 2015-08-28 12:44:36 +08:00
cha ,回错贴了~
|