android 中 imageview 设置可见性的问题

2015-08-25 17:38:51 +08:00
 creatorYC

我用 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 里面被隐藏的图片显示出来,不知道是不是应该这样做
9785 次点击
所在节点    Android
36 条回复
jimmy
2015-08-25 18:16:00 +08:00
执行了 adapter.notifyOnDataChange 了吗?
xhuuanniqege
2015-08-25 18:24:43 +08:00
正常的做法是在 adapter 里面设置一个辅助数组保存 imageview 的状态,在 getview 方法中根据这个数组设定 imageview 的可见性。当当按下按钮后,改变状态数组的内容然后 notifydatachange 。你遍历每个 view 没用的,因为当 view 看不见时会被回收。
ljbha007
2015-08-25 18:35:26 +08:00
首先你这么写代码的习惯很不好 耦合性太高 万一布局一变 imageview 不是在第 0 个了 代码就失效了 应该像楼上说的这么写

其次 千万不要手动调用 getView 方法
如果你 getView 方法里根据 xml 渲染了一个 listView 里的一行的话 你再次调用还会再渲染一次 而且还会触发 listView 的 view 循环利用机制 非常浪费
ssynhtn
2015-08-25 19:13:39 +08:00
难道是因为 textview android:layout_width="match_parent"覆盖了?
不过不管是什么原因,你这写法都很不常规
Bown
2015-08-25 19:17:48 +08:00
cityListView.getAdapter ().getView (i, null, null ) 改成 cityListView.getChildAt (i )
JayFang1993
2015-08-25 19:19:14 +08:00
一看就是新手,问问题的问法以及代码一看就像是来自百度知道的那种,拉低了 v 站的逼格~
Bown
2015-08-25 19:20:59 +08:00
没仔细看题。。 都有 view 重用,正确做法是 adapter 里面一个 list 记录每个 item 的状态是否 visible , getView 里面根据对应 index 的状态设置 visibility ,然后点击事件里面修改这个状态记录再 notifyDataSetChange
allan1st
2015-08-25 19:55:46 +08:00
你这样写 ListView 还有什么意义,建议把 ListView 原理好好看几遍。另外,请尽量转用 RecyclerView 。
creatorYC
2015-08-25 20:34:19 +08:00
@JayFang1993 按您的说法,新手应该去哪呢?
creatorYC
2015-08-25 20:36:16 +08:00
@ssynhtn 我是新手,请原谅,这样写为什么不常规呢
creatorYC
2015-08-25 20:40:32 +08:00
@allan1st 抱歉,我是新手,我还不太懂代码的优化之类的,能不能详细说点
creatorYC
2015-08-25 20:42:36 +08:00
@ljbha007 多谢指导,我会好好看的,谢谢您
anthonyeef
2015-08-25 20:48:43 +08:00
@xhuuanniqege 回答的很好啊也很耐心
ssynhtn
2015-08-25 20:50:01 +08:00
@creatorYC 我不知道你是哪里学的,反正随便搜索 listview 的用法都不是这样的。
因为 listview 里面的子 view 对象是会被回收重复利用的,所以就算这个写法一开始能正常工作,只要滑动几下,一个 view 滑出屏幕就会被回收,用到别的 position 去。
入门推荐 udacity 的免费课程
creatorYC
2015-08-25 20:53:33 +08:00
@xhuuanniqege 我刚学没多久,请问您有没有什么好的学习建议,或者能不能推荐一些书以及博客之类的,不胜感激
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 ();
}
});

希望对你有帮助。
ssynhtn
2015-08-25 22:01:40 +08:00
好吧,反正不是 textview 遮挡的问题,因为 textview 的背景色默认是透明的
gengrui
2015-08-25 22:07:13 +08:00
@ssynhtn 有道理,这点确实忽略了
creatorYC
2015-08-25 22:12:44 +08:00
@gengrui 我刚接触 android 不久,我应该去详细了解一下 ListView 的机制和原理,您的意思是说我应该设置标记去更新相应的 item 的可见性,而不应该每次都是去重绘 item ,的确我没有考虑到这些,没有考虑到代码的优化,多谢您的指点,我会尝试着改变这个写法,谢谢您详细的解答
veiz
2015-08-25 22:16:00 +08:00
@creatorYC StackOverflow 或者 SegmentFault

这是一个专为移动设备优化的页面(即为了让你能够在 Google 搜索结果里秒开这个页面),如果你希望参与 V2EX 社区的讨论,你可以继续到 V2EX 上打开本讨论主题的完整版本。

https://www.v2ex.com/t/215907

V2EX 是创意工作者们的社区,是一个分享自己正在做的有趣事物、交流想法,可以遇见新朋友甚至新机会的地方。

V2EX is a community of developers, designers and creative people.

© 2021 V2EX