Как обрабатывать длинный текст в настройках на Android?

Фон

Я создаю приложение с некоторыми настройками, и я хочу использовать встроенную функцию PreferenceActivity или PreferenceFragment для задания

Проблема

Некоторые из предпочтений имеют длинное название, которое я не могу сократить, плюс я думаю, что если бы я когда-либо локализовал приложение (перевести на несколько языков), я столкнулся бы с той же проблемой (например, на немецком языке, который имеет довольно длинные слова, иногда).

То, что вы получаете в этой ситуации, - это только начало текста, а затем "..." (или меньше точек, что не имеет особого смысла в конце).

Пример:

enter image description here

Что я пробовал

Я знаю, что PreferenceActivity распространяется из ListActivity, поэтому я могу изменить его адаптер на все, что пожелаю, но это удалит его работу.

Я также знаю, что я могу распространяться на каждый из типов классов предпочтений, использовать метод onCreateView, чтобы иметь ссылку на созданный вид, а затем обращаться к его дочерним элементам, но это странно, нет? Я имею в виду, это почти похоже на то, что он никогда не изменит способ, которым он выглядит.

EDIT: Здесь пример кода, который я пробовал:

Расширьте из каждого из классов предпочтений и в каждом из них используйте:

...
@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);
  }

Это работает, но я не думаю, что это рекомендуется, так как Google может изменить способ просмотра предпочтений.

Вопрос

Как обрабатывать длинные тексты в заголовках настроек на Android?

Возможно ли, что у него есть эллипсис/шатер (чтобы у него была анимация, чтобы показать все)? Или, может быть, авто подходит размер шрифта? Или установить, что у вас есть перенос слов? Или горизонтальное scrollView, которое позволит пользователю прокручивать, чтобы прочитать остальную часть текста?

Есть ли соглашение о том, как обращаться с такими случаями? Может быть, длинный щелчок, чтобы показать тост/диалог для просмотра всего текста?

Ответ 1

Кажется, новая версия библиотеки поддержки (Android-X) для предпочтений исправляет это.

Все, что мне нужно сделать, это расширить PreferenceFragmentCompat. Пример:

файл Gradle:

implementation 'androidx.preference:preference:1.0.0'

MainActivity.kt

class MainActivity : AppCompatActivity() {

    override fun onCreate(savedInstanceState: Bundle?) {
        super.onCreate(savedInstanceState)
        if (savedInstanceState == null)
            supportFragmentManager.beginTransaction().replace(android.R.id.content, PrefsFragment()).commit()
    }

    class PrefsFragment : PreferenceFragmentCompat() {
        override fun onCreatePreferences(savedInstanceState: Bundle?, rootKey: String?) {
            setPreferencesFromResource(R.xml.settings, rootKey)
        }
    }
}

settings.xml

<androidx.preference.PreferenceScreen xmlns:android="http://schemas.android.com/apk/res/android"
                                      xmlns:tools="http://schemas.android.com/tools">
    <androidx.preference.PreferenceCategory android:title="general">
        <androidx.preference.Preference android:summary="someSummary"
                                        android:key="pref" android:title="someTitle" tools:title="donation"/>
    </androidx.preference.PreferenceCategory>
</androidx.preference.PreferenceScreen>

Ответ 2

Это мое решение проблемы для конкретного случая SwitchPreference и для предпочтения в целом.

Прежде всего, я должен отметить, что для уровней API до 14 он выглядит так, как по умолчанию заголовки предпочтений были многострочными - по крайней мере, я не видел проблем с длинными заголовками в Android 2.3.3. В новых версиях Android это поведение изменилось на принудительное однострочное название.

Обходной путь - немного подправить SwitchPreference или любой другой тип макета предпочтений.

В файле экрана предпочтений добавьте атрибут android:layout для требуемых предпочтений, например:

<?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"
        />
        ...

Затем поставьте preference_multiline.xml альтернативный макет. Я использовал модифицированную версию стандарта 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>

Здесь я намеренно изменил значение android:singleLine в заголовке TextView от true до false. Это делает работу.

Ответ 3

Я не хотел копировать и вставлять макет, поэтому я выбрал подклассы настроек:

import android.content.Context;
import android.support.v7.preference.CheckBoxPreference;
import android.support.v7.preference.PreferenceViewHolder;
import android.util.AttributeSet;
import android.widget.TextView;

public class CustomCheckboxPreference extends CheckBoxPreference {

  public CustomCheckboxPreference(Context context) {
    super(context);
  }

  public CustomCheckboxPreference(Context context, AttributeSet attrs) {
    super(context, attrs);
  }

  public CustomCheckboxPreference(Context context, AttributeSet attrs, int defStyleAttr) {
    super(context, attrs, defStyleAttr);
  }

  public CustomCheckboxPreference(Context context, AttributeSet attrs, int defStyleAttr, int defStyleRes) {
    super(context, attrs, defStyleAttr, defStyleRes);
  }

  @Override
  public void onBindViewHolder(PreferenceViewHolder holder) {
    super.onBindViewHolder(holder);
    TextView title = (TextView) holder.findViewById(android.R.id.title);
    if (title != null) {
      title.setSingleLine(false);
    }
  }

}

Затем просто используйте его в своем prefs.xml:

<android.support.v7.preference.PreferenceScreen ...>
  <android.support.v7.preference.PreferenceCategory ...>
    <com.example.CustomCheckboxPreference
      ...
      />