Search code examples
androidandroid-preferences

How to wrap a preference title? (Really)


Please don't point me to How to wrap preference title? as it doesn't work for the case where (as I commented) you use a @strings/ reference to a strings.xml file.

If you use

android:title="@string/some_string"

and put

<string name="some_string">the string I want \n to wrap</string>

into strings.xml, the \n is ignored.


Solution

  • For most Android versions, there is no exposed API to allow line wrapping on Preference titles. This leads to the unfortunate common bug of truncated/faded text on medium-to-long titles, especially on small screen devices in portrait orientation:

    <PreferenceScreen
        android:key="my_pref_key"
        android:title="A Long Preference Title that should wrap to multiple lines" />
    

    Before - Single-line preference titles, in Holo and Material Theme

    But there are 2 ways to workaround it:

    1. The easy way - But this only works on Android 8 (API 26) and above:

    Use android:singleLineTitle="false" like this:

    <PreferenceScreen
        android:key="my_pref_key"
        android:title="A Long Preference Title that should wrap to multiple lines"
        android:singleLineTitle="false" />
    

    2. The hard way - Custom Preference Child layouts - This works on all Android versions:

    For Preferences that have long titles, use a custom layout on them (like this), where the TextView has explicitly turned off single-line text. But you have to set the layouts programmatically, because the themes are different between Android 4 (Holo theme) and Android 5 and above (Material theme).

    SettingsFragment.java or SettingsActivity.java:

    PreferenceScreen myPreferenceItem = (PreferenceScreen)
        getPreferenceScreen().findPreference("my_pref_key");
    
    if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.LOLLIPOP) {
        myPreferenceItem.
            setLayoutResource(R.layout.preference_child_material_customized);
    } else {
        myPreferenceItem.
            setLayoutResource(R.layout.preference_child_holo_customized);
    }
    

    After - Multi-line preference titles, in Holo and Material Theme

    Example for res/layout/preference_child_material_customized.xml:

    Copy this file from your Android SDK/platforms/android-22/data/res/layout/ preference_child_material.xml (like this one) and customize it:

    <LinearLayout xmlns:android="http://schemas.android.com/apk/res/android"
        android:layout_width="match_parent"
        android:layout_height="wrap_content"
        android:layout_marginStart="?android:attr/listPreferredItemPaddingStart"
        android:minHeight="?android:attr/listPreferredItemHeight"
        android:gravity="center_vertical"
        android:paddingStart="?android:attr/listPreferredItemPaddingStart"
        android:paddingEnd="?android:attr/listPreferredItemPaddingEnd">
    
        <LinearLayout
            android:id="@+android:id/icon_frame"
            android:layout_width="wrap_content"
            android:layout_height="match_parent"
            android:minWidth="40dip"
            android:gravity="start|center_vertical"
            android:orientation="horizontal">
            <ImageView
                android:id="@+android:id/icon"
                android:layout_width="wrap_content"
                android:layout_height="wrap_content"
                android:layout_marginEnd="8dip" />
        </LinearLayout>
    
        <RelativeLayout
            android:layout_width="wrap_content"
            android:layout_height="wrap_content"
            android:layout_weight="1"
            android:paddingTop="16dip"
            android:paddingBottom="16dip">
    
            <TextView android:id="@+android:id/title"
                android:layout_width="wrap_content"
                android:layout_height="wrap_content"
                android:singleLine="false"
                android:textAppearance="?android:attr/textAppearanceListItem" />
    
            <TextView android:id="@+android:id/summary"
                android:layout_width="wrap_content"
                android:layout_height="wrap_content"
                android:layout_below="@android:id/title"
                android:layout_alignStart="@android:id/title"
                android:textAppearance="?android:attr/textAppearanceListItemSecondary"
                android:textColor="?android:attr/textColorSecondary"
                android:maxLines="10" />
    
        </RelativeLayout>
    
        <!-- Preference should place its actual preference widget here. -->
        <LinearLayout android:id="@+android:id/widget_frame"
            android:layout_width="wrap_content"
            android:layout_height="match_parent"
            android:minWidth="58dip"
            android:gravity="end|center_vertical"
            android:orientation="vertical" />
    
    </LinearLayout>
    

    Notice the line android:singleLine="false" on the TextView.

    For res/layout/preference_child_holo_customized.xml, you should copy it from your Android SDK/platforms/android-19/data/res/layout/ preference_child.xml or preference_child_holo.xml (like this one) and customize it in a similar way.