ListView is one of Android's most widely used widgets. It is rather easy to use, very flexible and incredibly powerful. ListView
can also be difficult to understand at times.
One of the most common issues with ListView
happens when you try to use a custom background. By default, like many Android widgets, ListView
has a transparent background which means yo can see through the default window's background, a very dark gray (#FF191919
with the current dark theme.) Additionally, ListView
enables the fading edges by default, as you can see at the top of the following screenshot; the first text item gradually fades to black. This technique is used throughout the system to indicate that the container can be scrolled.
The fade effect is implemented using a combination of Canvas.saveLayerAlpha() and the Porter-Duff Destination Out blending mode. This technique is similar to the one explained in Filthy Rich Clients and various presentations. Unfortunately, things start to get ugly when you try to use a custom background on the ListView
or when you change the window's background. The following two screenshots show what happens in an application when you change the window's background. The left image shows what the list looks like by default and the right image shows what the list looks like during a scroll initiated with a touch gesture:
This rendering issue is caused by an optimization of the Android framework enabled by default on all instances of ListView
(for some reason, I forgot to enable it by default on GridView
.) I mentioned earlier that the fade effect is implemented using a Porter-Duff blending mode. This implementation works really well but is unfortunately very costly and can bring down drawing performance by quite a bit as it requires to capture a portion of the rendering in an offscreen bitmap and then requires extra blending (which implies readbacks from memory.)
Since ListView
is most of the time displayed on a solid background, there is no reason to go down that expensive route. That's why we introduced an optimization called the "cache color hint." The cache color hint is an RGB color set by default to the window's background color, that is #191919 in Android's dark theme. When this hint is set, ListView
(actually, its base class View
) knows it will draw on a solid background and therefore replaces th expensive saveLayerAlpha()/Porter-Duff
rendering with a simple gradient. This gradient goes from fully transparent to the cache color hint value and this is exactly what you see on the image above, with the dark gradient at the bottom of the list. However, this still does not explain why the entire list turns black during a scroll.
As I said before, ListView
has a transparent/translucent background by default, and so all default Android widgets. 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 (this assumes 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. And 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. This can be dome from code 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:
As you can see, the fade works perfectly against the custom wooden background. I find the cache color hint feature interesting because it shows how optimizations can make developers' life more difficult in some situations. In this particular case, however, the benefit of the default behavior outweighs the added complexity for the developer.
相关推荐
另一种方法是在`ListView`的XML布局文件中设置`android:drawSelectorOnTop="true"`,并将`android:listSelector`的值设为透明(`"#00000000"`),这可以确保选择器的绘制不会覆盖背景色,同时避免黑色背景的出现。...
在用户拖动ListView的过程中,为了提高交互的视觉反馈,默认会有一个黑色的背景颜色显示出来。有时候这种效果并不符合应用的设计风格,需要被移除。 可以通过设置`android:cacheColorHint`属性来实现这一需求。将该...
将`android:cacheColorHint`设置为`#00000000`(透明色)可以消除滚动时的背景颜色,从而去除了顶部和底部的阴影效果。 2. `android:fadingEdge`:此属性用于控制ListView边缘的渐变效果,即滚动时边缘的阴影。将其...
我们可以为ListView设置一个带有透明度的背景颜色,或者使用Alpha动画来改变其背景的透明度。例如,当开始刷新时,增加ListView背景的透明度: ```java swipeRefreshLayout.setColorSchemeResources(android.R....
有时候,简单的改变ListView的背景颜色并不足够,可能会遇到以下问题:当用户滑动ListView或者点击空白区域时,所有未被选中的项目都会变为默认的黑色或其他颜色,从而破坏整体的设计效果。这是因为Android系统默认...
如果使用图片作为背景,可以通过设置`cacheColorHint`为透明色来避免点击或滑动时出现黑色背景。 ```xml <ListView android:id="@+id/my_list_view" android:cacheColorHint="#00000000" /> ``` **2.4 divider ...
布局文件应设定适当的透明度,如设置背景颜色为`#CC000000`(即60%的黑色,透明度从0到255,值越小越透明)。 2. **手势检测**:使用Android的` GestureDetector`或者`SwipeRefreshLayout`来监听用户的滑动动作。你...
PopupWindow在Android开发中是一种非常常用的组件,它用于创建弹出式窗口,通常用作对话框、下拉菜单或者快捷操作按钮。这个组件允许开发者在应用程序的任何位置显示一个浮动的视图,提供了灵活的布局和交互方式。...
2. **设置透明背景**:为Action Bar设置一个带有透明度的颜色值,例如`#AA000000`(75%透明的黑色)。这样,即使Action Bar本身不完全透明,也能显示出下方的内容。 3. **监听滚动事件**:添加一个滚动监听器到...