【问题标题】:How to add divider lines in between preferences (settings menu)?如何在首选项(设置菜单)之间添加分隔线?
【发布时间】:2017-03-18 03:44:40
【问题描述】:

在我的设置中 我有多个偏好,它们之间没有线条,从而产生了丑陋的外观。我该如何解决这个问题?

【问题讨论】:

  • 此链接可能已满,请查看javatpoint.com/android-preferences-example
  • 这是 Material Design 的正确外观。我同意它看起来很奇怪,但如果你不关注它,你的应用就会显得格格不入。
  • @Tenfour04 你能把它具体说的地方链接起来吗?
  • @PikeD。好吧,我查了一下,发现我错了。规范没有提到它。我做了一个假设,因为它是 Marshmallow+ 和 AppCompat 中的默认样式。但是,当结果是您的 UI 与系统的其他部分没有凝聚力时,为什么还要努力让自己的应用看起来与 Google 自己的应用不同?

标签: android preferences


【解决方案1】:

AndroidX

如果使用 AndroidX,要显示分隔符,您只需在 Preference XML 中添加以下属性:

<Preference
    ...
    app:allowDividerAbove="true"
    app:allowDividerBelow="true"
    ... />

这里有更详细的答案:https://stackoverflow.com/a/55981453/2836371

【讨论】:

    【解决方案2】:

    以下内容适用于 AndroidX:

    在 AndroidX 中,getListView() 返回一个 RecyclerView。

    可以使用 .addItemDecoration() 将分隔线添加到 RecyclerViews

    这应该在 RecyclerView 在 onActivityCreated() 中被充气后完成。

    @Override
    public void onActivityCreated(@Nullable Bundle savedInstanceState) {
        super.onActivityCreated(savedInstanceState);
        RecyclerView recyclerView = getListView();
        DividerItemDecoration itemDecoration = new DividerItemDecoration(context, RecyclerView.VERTICAL);
        recyclerView.addItemDecoration(itemDecoration);
    }
    

    【讨论】:

      【解决方案3】:

      我发现最合适的解决方案是在 XML 中为类别和首选项设置布局。例如

      pref_screen.xml:

      <PreferenceScreen xmlns:android="http://schemas.android.com/apk/res/android"
          xmlns:app="http://schemas.android.com/apk/res-auto">
      
          <Preference
              android:key="@string/pref_org_code_key"
              android:title="@string/pref_org_code_title"
              android:defaultValue="@string/pref_org_code_default"
              app:iconSpaceReserved="false"
              android:layout="@layout/single_preference" />
          <PreferenceCategory android:title="Invitation - Auto accept">
              <CheckBoxPreference
                  android:defaultValue="@bool/friend_invite_accept_default"
                  android:key="@string/pref_friend_invite_auto_accept_key"
                  android:summaryOff="@string/pref_disabled"
                  android:summaryOn="@string/pref_enabled"
                  android:title="@string/pref_invites_friend_title"
                  app:iconSpaceReserved="false"
                  android:layout="@layout/single_preference"
                  android:widgetLayout="@layout/single_pref_checkbox" />
              <CheckBoxPreference
                  android:defaultValue="@bool/group_invite_accept_default"
                  android:key="@string/pref_group_invite_auto_accept_key"
                  android:summaryOff="@string/pref_disabled"
                  android:summaryOn="@string/pref_enabled"
                  android:title="@string/pref_invites_group_title"
                  app:iconSpaceReserved="false"
                  android:layout="@layout/single_preference"
                  android:widgetLayout="@layout/single_pref_checkbox" />
          </PreferenceCategory>
      </PreferenceScreen>
      

      single_preference.xml

      <?xml version="1.0" encoding="utf-8"?>
      <!--
        ~ Copyright (C) 2015 The Android Open Source Project
        ~
        ~ Licensed under the Apache License, Version 2.0 (the "License");
        ~ you may not use this file except in compliance with the License.
        ~ You may obtain a copy of the License at
        ~
        ~      http://www.apache.org/licenses/LICENSE-2.0
        ~
        ~ Unless required by applicable law or agreed to in writing, software
        ~ distributed under the License is distributed on an "AS IS" BASIS,
        ~ WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
        ~ See the License for the specific language governing permissions and
        ~ limitations under the License
        -->
      <LinearLayout xmlns:android="http://schemas.android.com/apk/res/android"
          xmlns:app="http://schemas.android.com/apk/res-auto"
          android:orientation="vertical"
          android:layout_width="match_parent"
          android:layout_height="wrap_content"
          android:minHeight="?android:attr/listPreferredItemHeightSmall">
      
      <LinearLayout
          android:layout_width="match_parent"
          android:layout_height="wrap_content"
          android:gravity="center_vertical"
          android:paddingLeft="?android:attr/listPreferredItemPaddingLeft"
          android:paddingRight="?android:attr/listPreferredItemPaddingRight"
          android:background="?android:attr/selectableItemBackground"
          android:clipToPadding="false"
          android:focusable="true" >
      
          <LinearLayout
              android:id="@+id/icon_frame"
              android:layout_width="wrap_content"
              android:layout_height="wrap_content"
              android:layout_marginLeft="-4dp"
              android:minWidth="60dp"
              android:gravity="start|center_vertical"
              android:orientation="horizontal"
              android:paddingRight="12dp"
              android:paddingTop="4dp"
              android:paddingBottom="4dp">
              <android.support.v7.internal.widget.PreferenceImageView
                  android:id="@android:id/icon"
                  android:layout_width="wrap_content"
                  android:layout_height="wrap_content"
                  app:maxWidth="48dp"
                  app:maxHeight="48dp" />
          </LinearLayout>
      
          <RelativeLayout
              android:layout_width="wrap_content"
              android:layout_height="wrap_content"
              android:layout_weight="1"
              android:paddingTop="16dp"
              android:paddingBottom="16dp">
      
              <TextView android:id="@android:id/title"
                  android:layout_width="wrap_content"
                  android:layout_height="wrap_content"
                  android:singleLine="true"
                  android:textAppearance="@style/Preference_TextAppearanceMaterialSubhead"
                  android:ellipsize="marquee" />
      
              <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="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:gravity="end|center_vertical"
              android:paddingLeft="16dp"
              android:orientation="vertical" >
          </LinearLayout>
      
      </LinearLayout>
      
          <View
              android:layout_width="match_parent"
              android:layout_height="1dp"
              android:layout_marginStart="8dp"
              android:layout_marginEnd="8dp"
              android:background="@color/cool_grey"/>
      </LinearLayout>
      

      single_pref_checkbox.xml

      <?xml version="1.0" encoding="utf-8"?>
      <CheckBox xmlns:android="http://schemas.android.com/apk/res/android"
          android:id="@+android:id/checkbox"
          android:layout_width="wrap_content"
          android:layout_height="wrap_content"
          android:focusable="false"
          android:clickable="false"
          android:background="@null" />
      

      single_pref_category.xml

      <?xml version="1.0" encoding="utf-8"?>
      <!--
        ~ Copyright (C) 2015 The Android Open Source Project
        ~
        ~ Licensed under the Apache License, Version 2.0 (the "License");
        ~ you may not use this file except in compliance with the License.
        ~ You may obtain a copy of the License at
        ~
        ~      http://www.apache.org/licenses/LICENSE-2.0
        ~
        ~ Unless required by applicable law or agreed to in writing, software
        ~ distributed under the License is distributed on an "AS IS" BASIS,
        ~ WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
        ~ See the License for the specific language governing permissions and
        ~ limitations under the License
        -->
      <LinearLayout
          xmlns:android="http://schemas.android.com/apk/res/android"
          xmlns:app="http://schemas.android.com/apk/res-auto"
          android:layout_marginBottom="0dp"
          android:layout_marginTop="0dp"
          android:orientation="vertical"
          android:layout_width="match_parent"
          android:layout_height="wrap_content">
          <View
              android:layout_width="match_parent"
              android:layout_height="8dp"
              android:layout_marginStart="8dp"
              android:layout_marginEnd="8dp"
              android:background="@color/grey300"/>
      
      <FrameLayout
          android:layout_width="match_parent"
          android:layout_height="wrap_content"
          android:layout_marginLeft="?android:attr/listPreferredItemPaddingLeft">
      
          <LinearLayout
              android:id="@+id/icon_frame"
              android:layout_width="wrap_content"
              android:layout_height="wrap_content"
              android:gravity="start|center_vertical"
              android:orientation="horizontal">
              <android.support.v7.internal.widget.PreferenceImageView
                  android:id="@android:id/icon"
                  android:layout_width="wrap_content"
                  android:layout_height="wrap_content"
                  app:maxHeight="18dp"
                  app:maxWidth="18dp"/>
          </LinearLayout>
      
          <LinearLayout
              android:layout_width="match_parent"
              android:layout_height="wrap_content"
              android:orientation="vertical"
              android:paddingLeft="@dimen/preference_category_padding_start">
      
              <TextView
                  android:id="@android:id/title"
                  android:layout_width="match_parent"
                  android:layout_height="wrap_content"
                  android:layout_marginTop="16dp"
                  android:paddingRight="?android:attr/listPreferredItemPaddingRight"
                  android:textAlignment="viewStart"
                  android:textColor="@color/preference_fallback_accent_color"
                  android:textStyle="bold" />
              <TextView
                  android:id="@android:id/summary"
                  android:layout_width="wrap_content"
                  android:layout_height="wrap_content"
                  android:ellipsize="end"
                  android:singleLine="true"
                  android:textColor="?android:attr/textColorSecondary"/>
          </LinearLayout>
      
      </FrameLayout>
      </LinearLayout>
      

      可能还需要修改样式并使用此样式而不是默认样式:

      <style name="SpecialPreferenceTheme">
              <item name="android:scrollbars">vertical</item>
              <item name="checkBoxPreferenceStyle">@style/Preference.CheckBoxPreference.Material</item>
              <item name="dialogPreferenceStyle">@style/Preference.DialogPreference.Material</item>
              <item name="dropdownPreferenceStyle">@style/Preference.DropDown.Material</item>
              <item name="editTextPreferenceStyle">@style/Preference.DialogPreference.EditTextPreference.Material</item>
              <item name="preferenceCategoryStyle">@style/CategoryPreference</item>
              <item name="preferenceFragmentCompatStyle">@style/PreferenceFragment.Material</item>
              <item name="preferenceFragmentListStyle">@style/PreferenceFragmentList.Material</item>
              <item name="preferenceFragmentStyle">@style/PreferenceFragment.Material</item>
              <item name="preferenceScreenStyle">@style/Preference.PreferenceScreen.Material</item>
              <item name="preferenceStyle">@style/SinglePreference</item>
              <item name="seekBarPreferenceStyle">@style/Preference.SeekBarPreference.Material</item>
              <item name="switchPreferenceCompatStyle">@style/Preference.SwitchPreferenceCompat.Material</item>
              <item name="switchPreferenceStyle">@style/Preference.SwitchPreference.Material</item>
          </style>
          <style name="SinglePreference">
              <item name="android:layout">@layout/single_preference</item>
              <item name="allowDividerAbove">false</item>
              <item name="allowDividerBelow">true</item>
              <item name="singleLineTitle">false</item>
              <item name="iconSpaceReserved">false</item>
          </style>
          <style name="CategoryPreference">
              <item name="android:layout">@layout/single_pref_category</item>
              <item name="allowDividerAbove">false</item>
              <item name="allowDividerBelow">false</item>
              <item name="iconSpaceReserved">false</item>
          </style>
          <style name="CheckboxPreferece">
              <item name="android:layout">@layout/single_preference</item>
              <item name="allowDividerAbove">false</item>
              <item name="allowDividerBelow">true</item>
              <item name="iconSpaceReserved">false</item>
          </style>
      

      【讨论】:

      • 我一直在寻找 app:iconSpaceReserved="false" 的 waaaaaayyyyy 太久了。我从您帖子中的代码 sn-ps 中学到的东西比我在 100 篇文章和有关偏好项目的官方文档中学到的更多。谢谢!
      • 问题出在 app:iconSpaceReserved 适用于 API 26 及以上版本:(
      【解决方案4】:

      我认为您正在尝试在自定义 preference.xml 中添加分隔符。

      如果您同时使用 PreferenceActivity 或 Preference Fragment,这应该很容易。

      只需转到 onCreate 方法并调用它

      ListView list = getListView();
      list.setDivider(); // pass null for no dividers or a valid drawable for dividers.
      

      【讨论】:

        【解决方案5】:

        感谢Matthew Smith的回答。

        正确的方法是覆盖PreferenceFragmentCompat类的onCreateRecyclerView方法

            @Override
            public RecyclerView onCreateRecyclerView(LayoutInflater inflater, ViewGroup parent, Bundle savedInstanceState) {
                RecyclerView recyclerView = super.onCreateRecyclerView(inflater, parent, savedInstanceState);
                DividerItemDecoration itemDecoration = new DividerItemDecoration(getContext(), RecyclerView.VERTICAL);
                recyclerView.addItemDecoration(itemDecoration);
                return recyclerView;
            }
        

        这适用于com.android.support:preference-v7:28.0.0

        【讨论】:

          【解决方案6】:

          在 androidx(基于this post)的整个设置屏幕中创建分隔线的好方法是创建 Preference 的子类并覆盖 onBindViewHolder,然后在 xml 中使用它。它适用于

          implementation 'androidx.preference:preference:1.1.1'
          

          但不幸的是,对于具有多个 Preference 类型的屏幕(可能会为 EditTextPreference 等创建子类),这不是一个好的解决方案

          public class CustomPreference extends Preference {
            public CustomPreference(Context context, AttributeSet attrs) {
              super(context, attrs);
            }
          
            @Override
            public void onBindViewHolder(PreferenceViewHolder holder) {
              super.onBindViewHolder(holder);
              holder.setDividerAllowedAbove(true);
            }
          

          }

          【讨论】:

            猜你喜欢
            • 1970-01-01
            • 1970-01-01
            • 2016-01-21
            • 2016-11-24
            • 1970-01-01
            • 1970-01-01
            • 1970-01-01
            • 1970-01-01
            • 1970-01-01
            相关资源
            最近更新 更多