Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

How to handle long text in preferences on Android?

Background

I'm making an app that has some settings, and I want to use the built in PreferenceActivity or PreferenceFragment for the job

The problem

Some of the preferences have a long title which I cannot shorten, plus I think that if I ever localize the app (translate to multiple languages) I would face the same problem (for example in German, which has quite long words, sometimes).

What you get in this situation is just the beginning of the text and then "..." (or less dots, which doesn't make much sense btw) in the end of it.

Example:

enter image description here

What I've tried

I know that the PreferenceActivity extends from ListActivity, so I can change its adapter to whatever I wish, but that would remove the way it works.

I also know that I can extend from each of the types of the preferences classes, use the "onCreateView" method to have a reference to the created view and then access its children, but this is weird, no? I mean, it's almost like assuming that it will never change the way it looks.

EDIT: Here's a sample code of what I've tried:

Extend from each of the preferences classes, and in each of them , use:

...
@Override
protected View onCreateView(final ViewGroup parent)
  {
  final View view=super.onCreateView(parent);
  ViewUtil.handlePreferenceTitleTextView(view);
  return view;
  }
...

//ViewUtil.java :

private void handlePreferenceTitleTextView(final View v)
  {
  final TextView titleTextView=(TextView)v.findViewById(android.R.id.title);
  if(titleTextView!=null)
    titleTextView.setSingleLine(false);
  }

It works, but I don't think it's recommended as Google might change the way preferences views work.

The question

How to handle long text in preferences' titles on Android ?

Is it possible to make it have an ellipsize / marquee (so that it will have an animation to show everything) ? Or maybe auto fit the font size? Or set it to have word wrap ? Or a horizontal scrollView that will allow the user to scroll to read the rest of the text?

Is there maybe a convention of how to handle such cases? Maybe long clicking to show a toast/dialog for seeing the whole text?

like image 779
android developer Avatar asked Apr 06 '13 17:04

android developer


3 Answers

2021: When using androidx.preference (likely what everyone has)

You can simply use app:singleLineTitle="false"

<Preference
        app:key="your_key"
        app:singleLineTitle="false"
        app:title="LONG TITLEEEEEEE EEEEEEEEE EEEEEEEEEEEEEEE" />

Works for Switches etc too

like image 169
Merthan Erdem Avatar answered Sep 22 '22 09:09

Merthan Erdem


This is my solution of the problem for specific case of the SwitchPreference and for a preference in general.

First of all, I should note that for API levels before 14 it looks like preference titles were multiline by default - at least I did not see any problems with long titles in Android 2.3.3. In newer versions of Android this behaviour has changed to forced single line title.

The workaround is to tweek the SwitchPreference or any other type of preference's layout a bit.

In the preference screen file add the android:layout attribute for required preference, for example:

<?xml version="1.0" encoding="utf-8"?>
<PreferenceScreen xmlns:android="http://schemas.android.com/apk/res/android">
  <PreferenceCategory android:title="@string/prefs_category">
    <SwitchPreference
        android:key="keyOfThePreference"
        android:title="@string/pref_title"
        android:switchTextOn="@string/pref_on"
        android:switchTextOff="@string/pref_off"
        android:summaryOn="@string/pref_enabled"
        android:summaryOff="@string/pref_disabled"
        android:layout="@layout/preference_multiline"
        />
        ...

Next, provide the preference_multiline.xml with alternative layout. I used a modified version of the standard preference.xml:

<?xml version="1.0" encoding="utf-8"?>
<!-- Layout for a Preference in a PreferenceActivity. The
     Preference is able to place a specific widget for its particular
     type in the "widget_frame" layout. -->
<LinearLayout xmlns:android="http://schemas.android.com/apk/res/android" 
    android:layout_width="match_parent"
    android:layout_height="wrap_content"
    android:minHeight="?android:attr/listPreferredItemHeight"
    android:gravity="center_vertical"
    android:paddingRight="?android:attr/scrollbarSize"
    android:background="?android:attr/selectableItemBackground" >

    <ImageView
        android:id="@+android:id/icon"
        android:layout_width="wrap_content"
        android:layout_height="wrap_content"
        android:layout_gravity="center"
        />

    <RelativeLayout
        android:layout_width="wrap_content"
        android:layout_height="wrap_content"
        android:layout_marginLeft="15dip"
        android:layout_marginRight="6dip"
        android:layout_marginTop="6dip"
        android:layout_marginBottom="6dip"
        android:layout_weight="1">

        <TextView android:id="@+android:id/title"
            android:layout_width="wrap_content"
            android:layout_height="wrap_content"
            android:singleLine="false"
            android:textAppearance="?android:attr/textAppearanceLarge"
            android:ellipsize="marquee"
            android:fadingEdge="horizontal" />

        <TextView android:id="@+android:id/summary"
            android:layout_width="wrap_content"
            android:layout_height="wrap_content"
            android:layout_below="@android:id/title"
            android:layout_alignLeft="@android:id/title"
            android:textAppearance="?android:attr/textAppearanceSmall"
            android:textColor="?android:attr/textColorSecondary"
            android:maxLines="4" />

    </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:gravity="center_vertical"
        android:orientation="vertical" />

</LinearLayout>

Here I deliberately changed android:singleLine value in the title's TextView from true to false. This does the job.

like image 6
Stan Avatar answered Oct 14 '22 18:10

Stan


Based on solution from here and here , this is a way to set it for all, if anyone wishes:

abstract class BasePreferenceFragment : PreferenceFragmentCompat() {

    private fun applyOperationsForAllPreferences(preference: Preference) {
        // preference.isIconSpaceReserved = false //you can add this too, if you don't want icons space
        preference.isSingleLineTitle = false
        if (preference is PreferenceGroup)
            for (i in 0 until preference.preferenceCount)
                applyOperationsForAllPreferences(preference.getPreference(i))
    }

    override fun setPreferenceScreen(preferenceScreen: PreferenceScreen?) {
        preferenceScreen?.let { applyOperationsForAllPreferences(it) }
        super.setPreferenceScreen(preferenceScreen)
    }

}
like image 2
android developer Avatar answered Oct 14 '22 18:10

android developer