Android ListView那些事

Android ListView那些事ListView是我们在开发Android程序时用得比较多的一种widget,通常用来展示多条数据,这里,我对ListView的一些功能点作一个简单介绍。1. Cachecolorhint默认情况下,Android中的View的背景都是透明的,这是一个合理的设计,但是,当渲染到屏幕上时,这会引入许多的计算,因为所有的child的背景是透明的,这就意味着当ListView绘制它的chil

大家好,又见面了,我是你们的朋友全栈君。

ListView是我们在开发Android程序时用得比较多的一种widget,通常用来展示多条数据,这里,我对ListView的一些功能点作一个简单介绍。

1. Cache color hint

默认情况下,Android中的View的背景都是透明的,这是一个合理的设计,但是,当渲染到屏幕上时,这会引入许多的计算,因为所有的child的背景是透明的,这就意味着当ListView绘制它的child时,会导致child与window的背景色相混合,当ListView上下滑动或Fling时,性能就会下降。当ListView上下滑动或者是Fling时,为了避免这种情况发生或提高渲染速度,ListView引入了”scrolling cache”机制。这个机制简单地说来就是ListView把可见的child绘制在一个bitmap上面(系统将每一个child拷贝到由cache color hint填充的bitmap上面),然后再直接把这个bitmap绘制到屏幕上,由于这个bitmap是不透明的,所以就不会有混合计算,这样就提高了绘制的效率。

但是,由于系统默认的cache color hint的颜色是#191919,当你滑动ListView时,你就会看到一个黑色的背景。

出现这种情况肯定是不正确的,那么怎么解决呢?

最简单的方法是将cache color hint设置为透明。

android:cacheColorHint=”#00000000″  或 setCacheColorHint(Color.TRANSPARENT)

以下是官方文档的原文:
As mentioned before, ListView has a transparent/translucent background by default, and so all default widgets in the Android UI toolkit. This implies that when ListView redraws its children, it has to blend the children with the window’s background. Once again, this requires costly readbacks from memory that are particularly painful during a scroll or a fling when drawing happens dozen of times per second.

To improve drawing performance during scrolling operations, the Android framework reuses the cache color hint. When this hint is set, the framework copies each child of the list in a Bitmap filled with the hint value (assuming that another optimization, called scrolling cache, is not turned off). ListView then blits these bitmaps directly on screen and because these bitmaps are known to be opaque, no blending is required. Also, since the default cache color hint is #191919, you get a dark background behind each item during a scroll.

To fix this issue, all you have to do is either disable the cache color hint optimization, if you use a non-solid color background, or set the hint to the appropriate solid color value. You can do this from code (see setCacheColorHint(int)) or preferably from XML, by using the android:cacheColorHint attribute. To disable the optimization, simply use the transparent color #00000000. The following screenshot shows a list with android:cacheColorHint=”#00000000″ set in the XML layout file.

2. Divider

通过android:divider XML属性来指定。
Divider可以颜色或者Drawable,当绘制内容时,ListView会自动地计算出divider的位置。由于divider接收一个drawable,它可以是ColorDrawable,也可以是BitmapDrawable,但是,由于ColorDrawable,它是没有高度的,所以Drawable#getIntrinsicHeight()方法返回-1,因此,为了避免这个问题, 我们可以通过android:dividerHeight属性来设计其高度。

3. ListView绘制顺序

对于ListView的绘制顺序,我们很有必要了解一下。先看一下下面的图片。

Android ListView那些事


从上面的图片可以看出,Android首先绘制背景和Dividers,然后再绘制其selector,最后,绘制所有的item在最上面。

由于通过情况下,listview的item的背景是透明的,所以,当用户按下一个item时,黄色的selector就会透出来。假如你的item是一个TextView,你将其背景设置为白色,那么当按钮一个item是时,selector就不会显示出来了,因为它是绘制在所有item的下面。

所以,对于ListView来说,其绘制顺序是:
Background -> Dividers -> List selector -> Itemviews 

4. OnItemClickListener不触发

有时候,当ListView中的每一个item是自定义的View时,有可能会导致ListView的OnItemClickListener的listener无法调用,请看如下情况:
如果你的自定义ListViewItem中有Button或者Checkable的子类控件的话,那么默认focus是交给了子控件,而 ListView的Item能被选中的基础是它能获取Focus,也就是说我们可以通过将ListView中Item中包含的所有控件的 focusable属性设置为false,这样的话ListView的Item自动获得了Focus的权限,也就可以被选中了。

我们可以通过对Item Layout的根控件设置其
android:descendantFocusability=”blocksDescendants”即可,这样Item Layout就屏蔽了所有子控件获取Focus的权限,不需要针对Item Layout中的每一个控件重新设置focusable属性了,如此就可以顺利的响应onItemClickListener中的onItemClick()方法了。

我看一下ListView处理touch事件的方法,AbsListView#onTouchEvent()方法中,代码如下:
...

case MotionEvent.ACTION_UP: {
    switch (mTouchMode) {
    case TOUCH_MODE_DOWN:
    case TOUCH_MODE_TAP:
    case TOUCH_MODE_DONE_WAITING:
        final int motionPosition = mMotionPosition;
        final View child = getChildAt(motionPosition - mFirstPosition);


        final float x = ev.getX();
        final boolean inList = x > mListPadding.left 
             && x < getWidth() - mListPadding.right;


        if (child != null && !child.hasFocusable() && inList) {
            if (mTouchMode != TOUCH_MODE_DOWN) {
                child.setPressed(false);
            }


            if (mPerformClick == null) {
                mPerformClick = new PerformClick();
            }


...

总结如下:
原因:
ListView中的Item内部的View获得了焦点,如Button, Checkbox等。 

解决办法:
不要让ListView中的Item内部的View获得焦点就OK了,这样做:
android:descendantFocusability=”blocksDescendants”

public static final int descendantFocusability
Defines the relationship between the ViewGroup and its descendants when looking for a View to take focus.

Constant Value Description
beforeDescendants  0 The ViewGroup will get focus before any of its descendants. 
afterDescendants 1 The ViewGroup will get focus only if none of its descendants want it.
blocksDescendants 2 The ViewGroup will block its descendants from receiving focus.

注意:

还有一种情况也会导致OnItemClickListener或OnItemLongClickListener回调不会执行,那就是ListView的child设置了onClickListener或onLongClickListener。我们可以通过源代码看出,在你调用setOnClickListener()方法后,它会调用setClickable(true),在onTouchEvent里面的实现如下:

if (((viewFlags & CLICKABLE) == CLICKABLE ||                (viewFlags & LONG_CLICKABLE) == LONG_CLICKABLE)) {     // ....    return true;}

当一个View在onTouchEvent里面返回true后,ListView就不会正常接收到事件。

5. ListView不要做的事

1)android:layout_height=”warp_content”?

有时候我们很容易让ListView的高度是wrap_content,这样做,很容易导致性能问题,wrap_content意味着as big as my children,这会导致1)测量大量的children;2)当添加child时,容易引起ListView重新发生layout,这又可能引发child的layout。我曾经遇到过一个问题,就是在维护别的写的代码时,ListView上下滑动速度特别慢,我把adapter等地方都优化完后,仍然一样,最终才发现ListView的高度是wrap_content,我把其改为match_parent之后,性能一下就正常了。


2)ListView套在ScrollView中,这种用法实在蛋痛,不解释。

版权声明:本文内容由互联网用户自发贡献,该文观点仅代表作者本人。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如发现本站有涉嫌侵权/违法违规的内容, 请发送邮件至 举报,一经查实,本站将立刻删除。

发布者:全栈程序员-用户IM,转载请注明出处:https://javaforall.cn/163262.html原文链接:https://javaforall.cn

【正版授权,激活自己账号】: Jetbrains全家桶Ide使用,1年售后保障,每天仅需1毛

【官方授权 正版激活】: 官方授权 正版激活 支持Jetbrains家族下所有IDE 使用个人JB账号...

(0)
blank

相关推荐

  • Android 应用程序窗口显示状态操作(requestWindowFeature()的应用)

    Android 应用程序窗口显示状态操作(requestWindowFeature()的应用)

  • webpack基础打包命令_webpack打包现有项目

    webpack基础打包命令_webpack打包现有项目没有配置文件的打包如果我们没有使用配置文件webpack.config.js,那么我们就需要通过命令来打包案例我们首先创建一个webpackTest文件夹,然后在文件夹中再创建2个子文件夹dis

  • pyyaml使用_pam模块

    pyyaml使用_pam模块pyyaml模块

  • vb中如何连接mysql_vb怎么连接数据库「建议收藏」

    vb怎么连接数据库[编辑]概述我们对数据库进行操作时,一方面要使用户可以在程序界面上对需要的数据进行访问;另一方面可以对数据库中的数据进行各种操作,最终的操作结果还要反馈给用户。一、Data控件1.设置数据控件的属性2.将Data控件连到一个特定的数据库和其中的一个表上3.在VB中建立一个标准的工程4.在窗体中添加控件(Data1就是一个Data控件)5.改变控件的一些属性6.对Data控件进行设…

  • java c socket通信 中文乱码解决「建议收藏」

    java c socket通信 中文乱码解决「建议收藏」前言(扯淡)作为一个一直从事Java的人来说,突然做C++很多地方都是乱撞墙,就发送的这个乱码就让人感到十分头秃,昨天跟老板对话,老板说不行咱就花钱找别人做。。。能力别质疑的感觉真是让人糟心啊–不扯太多,程序员节快乐,大家一起头秃吧。。虽然我并不想秃。问题言归正传,c++接收信息是gb2312,Java发数据是UTF-8,我Java接收数据没有问题,但是发给C++就遇到乱码问题…

  • JVM之内存结构详解

    JVM之内存结构详解对于开发人员来说,如果不了解Java的JVM,那真的是很难写得一手好代码,很难查得一手好bug。同时,JVM也是面试环节的中重灾区。今天开始,《JVM详解》系列开启,带大家深入了解JVM相关知识。我们不能为了面试而面试,但是学习会这些核心知识你必定会成为面试与工作中“最亮的一颗星”。本系列首发于微信公众号“程序新视界”。下面,开启我们的第一篇文章《JVM之内存结构详解》。学习也是要讲究方式方法…

发表回复

您的电子邮箱地址不会被公开。

关注全栈程序员社区公众号