Background
I'm trying to mimic the way that the contacts app of Lollipop shows the pinned headers for the contacts' first letter, as i've written about here.
The problem
Since the original code (which is found here, in the "PinnedHeaderListViewSample" folder) doesn't show letters other than the English ones, I had to change the code a bit, but that wasn't enough. Same goes for the header itself, which had to be on the left now other than being above the rows.
Everything worked fine, till I've tested it on RTL languages (Hebrew in my case), while the device's locale was also changed to an RTL language (Hebrew in my case) .
For some reason, things get really weird in both the scrolling and the header itself, and the weird part is that it occurs on some devices/versions of Android.
For example, on Galaxy S3 with Kitkat, the scrolling and the scrollbar is completely wrong (I scroll to the top, yet the scrollbar's location is on the middle).
On LG G2 with Android 4.2.2, it also has this problem, but it also doesn't show the headers (except for the pinned header), especially not those in Hebrew.
On Galaxy S4 and on Huwawei Ascend P7 (both running Kitkat), everything worked fine no matter what I did.
In short, the special scenario is:
- Use a pinnedHeaderListView
- have the device using an RTL locale, or do it via the developers settings
- have listview items in both English and Hebrew
- set the listView to show the fast-scroller.
- scroll listView using either the fast-scroller or like you do without it.
The code
The code amount is very large, plus I've made 2 POCs, while one of them is quite different from the code that I've started with (to make it look like on Lollipop). so I'll try to show the minimal amount.
EDIT: the big POC code is available on Github, here .
"PinnedHeaderActivity.java"
I've added 2 Hebrew items to the top, into the "names" field:
"אאא",
"בבב",
in "setupListView" method, I've made the fast scrollbar visible:
listView.setFastScrollEnabled(true);
in "NamesAdapter" CTOR, I've made it support more than the English Alphabet:
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"
In "getSectionForPosition" method, I've changed it to:
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" />
Here are 2 screenshots, one that doesn't look good, and another that looks ok:
Galaxy S3 kitkat and also LG G2 4.2.2 - don't show Hebrew headers, and have weird scrolling near the bottom (goes very fast to the bottom compared to the rest of the scrolling):
Galaxy S4 kitkat - shows the headers fine, but the scrolling is weird at the bottom:
For some reason, the Galaxy S4 didn't mirror the UI as it should, even though I've chosen it on the developer options, so it might also be the reason for why it showed the headers fine.
What I've tried
Besides trying out 2 POCs that I've made (one that is much more similar to the material design style and it's more complex), I've tried various ways to use the layouts, and also tried to use LayoutDirection in order to force the headers to show.
The even harder problem is to solve the fast-scrollbar, which works really weird on the more complex POC and a bit weird on the simple one (which scrolls fast near the bottom).
The question
What is the correct way to solve those issues?
Why does RTL have issues with this type of UI ?
EDIT: It seems that even Google's example doesn't handle RTL items well on a simple ListView:
http://developer.android.com/training/contacts-provider/retrieve-names.html
When it has Hebrew contacts, the scroller goes "crazy".