背景
我正在尝试模仿 Lollipop 的联系人应用程序显示联系人首字母的固定标题的方式,正如我在这里所写的那样。
问题
由于原始代码(可在此处找到,在“PinnedHeaderListViewSample”文件夹中)不显示除英文以外的字母,因此我不得不稍微更改代码,但这还不够。标题本身也是如此,它现在必须在左侧,而不是在行上方。
一切正常,直到我在 RTL 语言(在我的情况下是希伯来语)上对其进行了测试,而设备的语言环境也更改为 RTL 语言(在我的情况下是希伯来语)。
出于某种原因,滚动和标题本身都变得非常奇怪,奇怪的是它发生在某些设备/版本的 Android 上。
例如,在带有 Kitkat 的 Galaxy S3 上,滚动和滚动条完全错误(我滚动到顶部,但滚动条的位置在中间)。
在装有 Android 4.2.2 的 LG G2 上,它也有这个问题,但它也没有显示标题(固定标题除外),尤其是希伯来语中的标题。
在 Galaxy S4 和 Huwawei Ascend P7(都运行 Kitkat)上,无论我做什么,一切正常。
简而言之,特殊情况是:
- 使用 pinnedHeaderListView
- 让设备使用 RTL 语言环境,或通过开发人员设置进行
- 有英语和希伯来语的列表视图项目
- 设置 listView 以显示快速滚动条。
- 使用快速滚动器滚动 listView 或像没有它一样滚动。
编码
代码量非常大,加上我做了 2 个 POC,其中一个与我开始使用的代码有很大不同(使其看起来像在 Lollipop 上)。所以我会尽量显示最小的数量。
编辑:大 POC 代码在 Github 上可用,这里。
“PinnedHeaderActivity.java”
我在“名称”字段的顶部添加了 2 个希伯来语项目:
"אאא",
"בבב",
在“setupListView”方法中,我使快速滚动条可见:
listView.setFastScrollEnabled(true);
在“NamesAdapter”CTOR 中,我让它支持的不仅仅是英文字母:
public NamesAdapter(Context context, int resourceId, int textViewResourceId, String[] objects) {
super(context, resourceId, textViewResourceId, objects);
final SortedSet<Character> set = new TreeSet<Character>();
for (final String string : objects) {
final String trimmed = string == null ? "" : string.trim();
if (!TextUtils.isEmpty(trimmed))
set.add(Character.toUpperCase(trimmed.charAt(0)));
else
set.add(' ');
}
final StringBuilder sb = new StringBuilder();
for (final Character character : set)
sb.append(character);
this.mIndexer = new StringArrayAlphabetIndexer(objects, sb.toString());
}
“StringArrayAlphabetIndexer.java”
在“getSectionForPosition”方法中,我将其更改为:
public int getSectionForPosition(int position) {
try {
if (mArray == null || mArray.length == 0)
return 0;
final String curName = mArray[position];
// Linear search, as there are only a few items in the section index
// Could speed this up later if it actually gets used.
// TODO use binary search
for (int i = 0; i < mAlphabetLength; ++i) {
final char letter = mAlphabet.charAt(i);
if (TextUtils.isEmpty(curName) && letter == ' ')
return i;
final String targetLetter = Character.toString(letter);
if (compare(curName, targetLetter) == 0)
return i;
}
return 0; // Don't recognize the letter - falls under zero'th section
} catch (final Exception ex) {
return 0;
}
}
list_item.xml
<LinearLayout xmlns:android="http://schemas.android.com/apk/res/android"
android:id="@+id/list_item"
android:layout_width="match_parent"
android:layout_height="wrap_content"
android:orientation="vertical">
<FrameLayout
android:layout_width="match_parent"
android:layout_height="wrap_content">
<include layout="@layout/list_item_header" />
<include
layout="@android:layout/simple_list_item_1"
android:layout_width="match_parent"
android:layout_height="wrap_content"
android:layout_marginLeft="50dp" />
</FrameLayout>
<View
android:id="@+id/list_divider"
android:layout_width="match_parent"
android:layout_height="1px"
android:background="@android:drawable/divider_horizontal_dark" />
</LinearLayout>
list_item_header.xml
<TextView xmlns:android="http://schemas.android.com/apk/res/android"
android:id="@+id/header_text"
android:layout_width="25dip"
android:layout_height="25dip"
android:textStyle="bold"
android:background="@color/pinned_header_background"
android:textColor="@color/pinned_header_text"
android:textSize="14sp"
android:paddingLeft="6dip"
android:gravity="center" />
这是两张截图,一张看起来不太好,另一张看起来还不错:
Galaxy S3 kitkat 和 LG G2 4.2.2 - 不显示希伯来语标题,并且在底部附近有奇怪的滚动(与其余滚动相比,滚动到底部非常快):
Galaxy S4 kitkat - 显示标题很好,但底部的滚动很奇怪:
出于某种原因,尽管我在开发人员选项中选择了 Galaxy S4,但它并没有像应有的那样镜像 UI,所以这也可能是它显示标题正常的原因。
我试过的
除了尝试我制作的 2 个 POC(一个更类似于材料设计风格且更复杂的 POC),我尝试了各种使用布局的方法,还尝试使用 LayoutDirection 来强制要显示的标题。
更难的问题是解决快速滚动条,它在更复杂的 POC 上非常奇怪,在简单的 POC 上有点奇怪(在底部附近快速滚动)。
问题
解决这些问题的正确方法是什么?
为什么 RTL 对这种类型的 UI 有问题?
编辑:似乎即使是 Google 的示例也不能在简单的 ListView 上很好地处理 RTL 项目:
http://developer.android.com/training/contacts-provider/retrieve-names.html
当它有希伯来语联系人时,滚动条会“发疯”。