android 中 imageview 设置可见性的问题 - V2EX
V2EX = way to explore
V2EX 是一个关于分享和探索的地方
现在注册
已注册用户请  登录
creatorYC
V2EX    Android

android 中 imageview 设置可见性的问题

  •  
  •   creatorYC 2015-08-25 17:38:51 +08:00 15961 次点击
    这是一个创建于 3713 天前的主题,其中的信息可能已经有所发展或是发生改变。

    我用 SimpleAdapter 作为 ListView 的适配器,自定义了一个布局,里面有一个 ImageView 和一个 TextView ,我想要实现 ListView 的每一项都是文字加图片的效果。布局文件如下: <ImageView
    android:id="@+id/IteImage"
    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 里面被隐藏的图片显示出来,不知道是不是应该这样做 
    36 条回复    2015-08-28 12:44:36 +08:00
    jimmy
        1
    jimmy  
       2015-08-25 18:16:00 +08:00
    执行了 adapter.notifyOnDataChange 了吗?
    xhuuanniqege
        2
    xhuuanniqege  
       2015-08-25 18:24:43 +08:00 via Android
    正常的做法是在 adapter 里面设置一个辅助数组保存 imageview 的状态,在 getview 方法中根据这个数组设定 imageview 的可见性。当当按下按钮后,改变状态数组的内容然后 notifydatachange 。你遍历每个 view 没用的,因为当 view 看不见时会被回收。
    ljbha007
        3
    ljbha007  
       2015-08-25 18:35:26 +08:00
    首先你这么写代码的习惯很不好 耦合性太高 万一布局一变 imageview 不是在第 0 个了 代码就失效了 应该像楼上说的这么写

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

    希望对你有帮助。
    kx5d62Jn1J9MjoXP
        17
    kx5d62Jn1J9MjoXP  
       2015-08-25 22:01:40 +08:00
    好吧,反正不是 textview 遮挡的问题,因为 textview 的背景色默认是透明的
    gengrui
        18
    gengrui  
       2015-08-25 22:07:13 +08:00
    @ssynhtn 有道理,这点确实忽略了
    creatorYC
        19
    creatorYC  
    OP
       2015-08-25 22:12:44 +08:00
    @gengrui 我刚接触 android 不久,我应该去详细了解一下 ListView 的机制和原理,您的意思是说我应该设置标记去更新相应的 item 的可见性,而不应该每次都是去重绘 item ,的确我没有考虑到这些,没有考虑到代码的优化,多谢您的指点,我会尝试着改变这个写法,谢谢您详细的解答
    veiz
        20
    veiz  
       2015-08-25 22:16:00 +08:00
    @creatorYC StackOverflow 或者 SegmentFault
    creatorYC
        21
    creatorYC  
    OP
       2015-08-25 22:16:17 +08:00
    @ssynhtn 那我就更困惑了,暂且不说代码优化,用这种拙劣的不优化的代码能不能实现我想要的效果呢?
    xhuuanniqege
        22
    xhuuanniqege  
       2015-08-25 22:19:41 +08:00 via Android   1
    @creatorYC 新手用这个方法也说明挺动脑筋的了,多写多练,多谷歌,能力很快会提高的
    gengrui
        23
    gengrui  
       2015-08-25 22:26:10 +08:00
    @creatorYC 不客气 :)
    kx5d62Jn1J9MjoXP
        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;
    }
    kx5d62Jn1J9MjoXP
        25
    kx5d62Jn1J9MjoXP  
       2015-08-25 22:28:15 +08:00
    我之前说 textview 覆盖 imageview 的那个解释是错误的,以为 textview 的 background 默认是透明的
    creatorYC
        26
    creatorYC  
    OP
       2015-08-25 22:36:50 +08:00
    @ssynhtn 好像挺深奥的。。。恕我愚昧,我想知道我应该怎么写呢。。
    creatorYC
        27
    creatorYC  
    OP
       2015-08-25 22:48:50 +08:00
    @Bown 按您的方法,我实现了想要的效果,您能帮忙讲一下这两个的区别吗,就是因为像 @ssynhtn 说的那样,主动调用 getView 方法导致重新创建了一个 view ?
    kx5d62Jn1J9MjoXP
        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 课程
    creatorYC
        29
    creatorYC  
    OP
       2015-08-25 22:55:20 +08:00
    @ssynhtn 谢谢您,我会认真看的,多谢
    kaient
        30
    kaient  
       2015-08-26 11:53:48 +08:00
    我觉得吧,如果你把 imageView 的的 GONE 变成 INVISIBLE 应该就对了
    creatorYC
        31
    creatorYC  
    OP
       2015-08-26 13:31:40 +08:00
    @xhuuanniqege 请问你们都是怎么谷歌的,翻墙了还是用什么 vpn 啊
    xhuuanniqege
        32
    xhuuanniqege  
       2015-08-26 18:41:35 +08:00 via Android
    @creatorYC 翻墙了
    wzg1015
        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 实现。
    creatorYC
        34
    creatorYC  
    OP
       2015-08-27 12:34:37 +08:00
    @wzg1015 我按 @Bown 说的那样,已经解决了,正如您说的那样,我用这个 RelativeLayout layout =(RelativeLayout ) cityListView.getAdapter ().getView (i, null, null ); 其实就是创建了一个新的 view ,我贴这些代码是因为我敢肯定是这里面的问题,因为我的功能都是一个个加的,都是一个个测试的,关于代码的质量,我的确需要提高很多,因为我才刚学不久,所以现在要求自己先把功能做出来,代码优化的确做的很差。不管怎样,都谢谢您的耐心解答,我会提高自己问问题的水平,抱歉
    quiz
        35
    quiz  
       2015-08-28 12:43:47 +08:00
    Golang 效率高了,但是应该算是一种退步吧:)
    https://www.dartlang.org/mobile/
    看看 google 想怎么玩儿
    quiz
        36
    quiz  
       2015-08-28 12:44:36 +08:00
    cha ,回错贴了~
    关于     帮助文档     自助推广系统     博客     API     FAQ     Solana     2675 人在线   最高记录 6679       Select Language
    创意工作者们的社区
    World is powered by solitude
    VERSION: 3.9.8.5 26ms UTC 08:41 PVG 16:41 LAX 01:41 JFK 04:41
    Do have faith in what you're doing.
    ubao msn snddm index pchome yahoo rakuten mypaper meadowduck bidyahoo youbao zxmzxm asda bnvcg cvbfg dfscv mmhjk xxddc yybgb zznbn ccubao uaitu acv GXCV ET GDG YH FG BCVB FJFH CBRE CBC GDG ET54 WRWR RWER WREW WRWER RWER SDG EW SF DSFSF fbbs ubao fhd dfg ewr dg df ewwr ewwr et ruyut utut dfg fgd gdfgt etg dfgt dfgd ert4 gd fgg wr 235 wer3 we vsdf sdf gdf ert xcv sdf rwer hfd dfg cvb rwf afb dfh jgh bmn lgh rty gfds cxv xcv xcs vdas fdf fgd cv sdf tert sdf sdf sdf sdf sdf sdf sdf sdf sdf sdf sdf sdf sdf sdf sdf sdf sdf sdf sdf sdf sdf sdf sdf sdf sdf sdf sdf sdf sdf sdf sdf sdf sdf sdf sdf sdf sdf sdf sdf sdf shasha9178 shasha9178 shasha9178 shasha9178 shasha9178 liflif2 liflif2 liflif2 liflif2 liflif2 liblib3 liblib3 liblib3 liblib3 liblib3 zhazha444 zhazha444 zhazha444 zhazha444 zhazha444 dende5 dende denden denden2 denden21 fenfen9 fenf619 fen619 fenfe9 fe619 sdf sdf sdf sdf sdf zhazh90 zhazh0 zhaa50 zha90 zh590 zho zhoz zhozh zhozho zhozho2 lislis lls95 lili95 lils5 liss9 sdf0ty987 sdft876 sdft9876 sdf09876 sd0t9876 sdf0ty98 sdf0976 sdf0ty986 sdf0ty96 sdf0t76 sdf0876 df0ty98 sf0t876 sd0ty76 sdy76 sdf76 sdf0t76 sdf0ty9 sdf0ty98 sdf0ty987 sdf0ty98 sdf6676 sdf876 sd876 sd876 sdf6 sdf6 sdf9876 sdf0t sdf06 sdf0ty9776 sdf0ty9776 sdf0ty76 sdf8876 sdf0t sd6 sdf06 s688876 sd688 sdf86