在Android上如何处理偏好设置中的长文本?

13

背景

我正在开发一个应用程序,其中有一些设置,我希望使用内置的PreferenceActivity或PreferenceFragment完成这项工作。

问题

一些偏好设置具有过长的标题,我无法缩短它们,而且我认为如果我将应用程序本地化(翻译成多种语言),我将面临相同的问题(例如在德语中,有相当长的单词,有时候)。

在这种情况下,您只能看到文本的开头,然后是“...”(或更少的点,这并没有太多意义)。

示例:

enter image description here

我尝试过的方法

我知道PreferenceActivity从ListActivity继承,因此我可以更改其适配器为任何我想要的,但这将删除它的工作方式。

我还知道我可以从每个喜好类别扩展,使用“onCreateView”方法引用创建的视图,然后访问其子元素,但这很奇怪,对吧?我的意思是,这几乎就像假设它永远不会改变外观。

编辑:以下是我尝试过的示例代码:

从每个喜好类别扩展,然后在每个类别中使用:

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

它确实起作用,但我认为不建议使用,因为谷歌可能会更改偏好设置视图的工作方式。

问题

如何处理Android中偏好设置标题中的长文本?

是否可以使其具有省略号/跑马灯(这样它将具有动画来显示所有内容)?或者自动调整字体大小?或者将其设置为自动换行?或者水平滚动视图,允许用户滚动以阅读其余文本?

也许有惯例可以处理这种情况吗?也许长按以显示弹出窗口/对话框以查看整个文本?


2
@WilliamKinaan 不,我不是在谈论sharedPreferences。我在谈论UI。preferenceActivity中的所有文本视图都有标题限制。目前,在这种情况下对我有效的唯一解决方案是从每个偏好类中进行扩展,并找到id为“R.id.title”的TextView并更改其属性为我想要的任何内容,但这是一个奇怪的解决方案。 - android developer
1
@el_bhm 但是也有一些屏幕空间很小,甚至无法显示英文单词。此外,在 switchPreference 的情况下,通常会减少约50%的空间(因为开关视图和填充)。 - android developer
我认为对于小屏幕来说,这个问题非常烦人且频繁。您介绍的解决方法是否可以作为扩展答案发布? - Stan
@Stan 究竟是哪种情况?您需要帮助使用哪种UI组件?对于大多数组件,我已经自己解决了(希望在所有设备上都能很好地运行)。 如果您愿意,可以查看我的应用程序,了解我在那里做了什么:https://play.google.com/store/apps/details?id=com.lb.app_manager - android developer
对于问题中所示的情况(开关标题被截断,而复选框标题则没有),我将尝试使用自定义首选项布局进行调整,如果您的方法似乎过于复杂。那么您在问题中提到的“编辑” - 是您最终采用的解决方法吗? - Stan
显示剩余7条评论
4个回答

6
这是我针对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>

我故意将标题中TextViewandroid:singleLine值从true更改为false。这样就可以完成任务了。


这是一种更安全的解决方案,但另一方面,它不尊重设备操作系统的默认外观,因为它强制其看起来像您选择的样子。我想每种解决方案都有其优点和缺点... - android developer
你说得对。是的,Android 在新版本中可能会发生变化,从而引入不必要的副作用(正如编辑答案中关于首选项标题“多行性”的提到的那样),因此拥有自定义布局可以完全控制应用程序。毕竟,许多开发人员使用自定义首选项。 - Stan
太好了!这个运行得非常完美。但是有一个警告:android:singleLine已经过时:False是默认值,所以只需删除该属性。我应该删除它吗? - Hammad Nasir
@HammadNasir,你可以试试。这可能是版本特定的。 - Stan
AOSP 中的原始布局链接:https://github.com/aosp-mirror/platform_frameworks_base/blob/master/core/res/res/layout/preference.xml - Albert Vila Calvo

2

2021: 当使用androidx.preference(很可能是每个人都在使用的)

您可以简单地使用app:singleLineTitle="false"

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

也适用于交换机等


1
似乎运行良好。谢谢。但是有没有一种方法可以设置为全部? - android developer
好的,我已经更新了我的答案(似乎一开始是错误的,但也许最初是正确的),现在它有一个适用于所有偏好的解决方案。 - android developer

2

根据这里这里的解决方案,如果任何人希望将其设置为所有内容,则可以采用以下方法:

原始答案:Original Answer

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)
    }

}

1
很想知道这个程序是“如何”解决问题(以及提出的六个子问题)。 - CaptainCrunch
@CaptainCrunch 抱歉我不记得了。至于这些问题,你或许可以从中拓展并自行处理 Views。 - android developer
@CaptainCrunch 您说得对。这并没有帮助。我不知道为什么写了它。也许以前它能处理,但现在不行了。不知道发生了什么。 - android developer
@CaptainCrunch 无论如何,现在已经更新了更好的方法来完成它。 - android developer

0

我不想复制粘贴布局,所以最终我选择了子类化首选项:

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

这是我在问题中编写的完全相同的代码。同样也存在于我制作的库中,链接在此处:https://github.com/AndroidDeveloperLB/MaterialPreferenceLibrary - android developer
是的,它是一样的(除了我使用支持首选项)... 我甚至没有读问题,哈哈。 - Albert Vila Calvo

网页内容由stack overflow 提供, 点击上面的
可以查看英文原文,
原文链接