解决2.3.x某些系统中listview超出item高度部分灰色背景问题
正如在博文中提到的,Motorola设备升级到Android 2.3.x Gingerbread版本后,该版本增加了新的 Android 样式(style)和主题(theme)。你可能发现了你的应用中的某些视图在升级后的设备上看上去发生了变化。
作为Android开发者,你已经知道 样式 是一个或多个的属性/值对,来定义视图 (View) 的外观。主题也类似,只是它对一个activity或应用起作用。样式和主题都是从Android平台中的内置主题继承而来,所以本文的主题都从 android:Theme 继承而来:
<style name="MyTheme" parent="android:Theme">
<item name="android:windowBackground">@null</item>
</style>
所有我们没有显式定义的样式都从平台主题定义的样式向下合并而来。
然而在升级到 Android 2.3 的 Motorola 设备上,内置主题定义的某些属性值已经发生改变,如Theme, Theme.Black, Theme.Light 和其它你可能继承的内置主题。 要查看某个 Android 版本中的内置主题,你可以在 MOTODEV Studio(或带ADT的Eclipse)中打开一个XML layout文件,并检查 GraphicalLayout 视图。
这对你的应用有何影响呢?默认地,有些视图如 ListView, AlertDialog 等使用设备上的可用主题来显示。所以如果你不做任何事,你的应用将从 android:Theme 继承 --- 但 android:Theme 在这种情况下的显示会与默认的 Android 版本不同。
当然你可以为你的应用定义传统的风格或主题。它需要付出更多的工作,但能提供你需要的外观,并使你的应用能更灵活地运行在各种设备中。
定义ListView
ListView 是Android视图中最常用的,所以本文将重点讨论它。你可以在 XML 中定义一个ListView,如下例:
<ListView
xmlns:android="http://schemas.android.com/apk/res/android"
android:id="@android:id/list"
android:layout_width="match_parent"
android:layout_height="match_parent"
android:background="@drawable/bluegradientbackground"
android:cacheColorHint="#00000000"
android:divider="#fff"
android:dividerHeight="0sp"
android:descendantFocusability="afterDescendants"
/>
这是一个很直观的 ListView。layout_width和 layout_height 的值都设置成 match_parent(在更早的Android版本中使用的是 fill_parent),我们期望 ListView 填充整个屏幕。它有一个背景图片,cacheColorHint 设置成透明色#00000000(参见 Why is my list black? An Android optimization 以更好地理解 ListView 中如何使用cacheColorHint)
但当你在Android2.3版本的设备上显示这个列表时,并且这个列表的行数不能填充屏幕时,会出现如下图的效果。
列表下方的灰色背景是从设备的主题继承而来的。它的目的是提示用户列表内容结束了。
对比一下,在运行Android 3.1 的 Motorola XOOM 平板上(在一个没有碎片的简单屏幕)显示同一个ListView 的效果:
如果你希望在 Motorola Android 2.3.x 设备上显示列表下方为灰色,并希望你的应用与设备融于一体,而不是在不同的设备上显示一样,那么你可以不用做任何事情。
简单的解决方案
但如果你(或你的客户或用户)希望 ListView 的背景全屏显示,或你的应用在不同设备上看起来一样,可以采用一个简单的方案:在 ListView中使用Android2.3 Gingrebread 中新增加的overScrollFooter属性。如果你设置 overScrollFooter 为 @null, 列表下方的背景变为透明,你的背景图片就能显示出来。
<ListView
xmlns:android="http://schemas.android.com/apk/res/android"
android:id="@android:id/list"
android:layout_width="match_parent"
android:layout_height="match_parent"
android:background="@drawable/bluegradientbackground"
android:cacheColorHint="#00000000"
android:divider="#fff"
android:dividerHeight="0sp"
android:descendantFocusability="afterDescendants"
android:overScrollFooter="@null" />
这一次,列表填充了整个屏幕。
如果你希望列表下方显示不同颜色,你可以设置 overScrollFooter 为某个颜色,如下例:
android:overScrollFooter="#aa000000"
android:overScrollFooter="@drawable/my_drawable"
保持代码简洁
因为 overScrollFooter 是在Android2.3 引入的,如果你想让你的应用支持不同的Android版本,你应当在支持Gingerbread及更高版本的主题中定义它。
接下来在res/values-v10/styles.xml文件中,为你的 ListView 创建一个样式, 它从内置的Widget.ListView 继承,并设置overScrollFooter 为 @null:
<style name="MyListView" parent="@android:style/Widget.ListView">
<item name="android:listSelector">@drawable/list_selector</item>
<item name="android:overScrollFooter">@null</item>
</style>
完整的样式要素 (element )列表参见 R.styleable。
然后在应用的主题中设置传统的样式:
<style name="MyTheme" parent="android:Theme">
<item name="android:windowBackground">@null</item>
<item name="android:listViewStyle">@style/MyListView</item>
</style>
最后在你的 AndroidManifest 中使用你的传统主题:
<activity android:name="com.listtest.MainActivity"
android:label="@string/app_name"
android:theme="@style/MyTheme">
你还需要用Android2.3 编译应用,并在 res/values 中创建一个相应的 styles.xml 文件,它不使用 verScrollFooter,这样能在低于API 级别10 的设备上使用。
使用样式和主题使你的代码简洁(DRY) --- 即Do Not Repeat Yourself --- 因为你可以定义样式,然后复用它们。本文的方法能使你的代码简洁,并解决列表下方背景颜色问题。