Как добавить разделительные линии между настройками (меню настроек)?

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


person Pike D.    schedule 18.03.2017    source источник
comment
эта ссылка может быть использована полностью, чтобы вы могли проверить ее javatpoint.com/android-preferences-example   -  person sunita    schedule 18.03.2017
comment
Это правильный взгляд на Material Design. Я согласен, что это выглядит странно, но ваше приложение будет выглядеть неуместно, если вы ему не будете следовать.   -  person Tenfour04    schedule 10.07.2017
comment
@ Tenfour04, не могли бы вы дать ссылку, где это конкретно сказано?   -  person Pike D.    schedule 10.07.2017
comment
@PikeD. Ну, я посмотрел и понял, что ошибался. Спецификация не упоминает об этом. Я сделал предположение, потому что это стиль по умолчанию в Marshmallow+ и AppCompat. Но зачем тратить усилия, пытаясь выглядеть иначе, чем собственные приложения Google, если в результате ваш пользовательский интерфейс не связан с остальной частью системы?   -  person Tenfour04    schedule 10.07.2017


Ответы (6)


Я думаю, вы пытаетесь добавить разделители в пользовательский файл preference.xml.

Это должно быть легко, если вы используете PreferenceActivity или Preference Fragment.

Просто перейдите к методу onCreate и вызовите это

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

AndroidX

Если вы используете AndroidX, чтобы показать разделители, вы можете просто добавить следующие атрибуты в XML-файл предпочтений:

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

Более подробный ответ здесь: https://stackoverflow.com/a/55981453/2836371

person Maksim Ivanov    schedule 04.05.2019

Для AndroidX следующее:

В AndroidX getListView() возвращает RecyclerView.

Разделительные линии можно добавить в RecyclerViews с помощью .addItemDecoration().

Это должно быть сделано после того, как 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);
}
person Matthew Smith    schedule 14.02.2019

Наиболее подходящим решением, которое я нашел, является настройка макетов для категорий и предпочтений в 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>
person Valentina Konyukhova    schedule 06.03.2019
comment
Я искал app:iconSpaceReserved=false слишком долго. Из фрагментов кода в вашем посте я узнал больше, чем из 100 статей и официальных документов об элементах предпочтений. Спасибо! ‹3 - person jungledev; 28.06.2019
comment
проблема в том, что app:iconSpaceReserved предназначен для API 26 и выше :( - person Pulkit; 12.03.2021

Благодаря ответу Matthew Smith.

Правильный способ - перезаписать метод onCreateRecyclerView класса thePreferenceFragmentCompat.

    @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

person crazygit    schedule 27.10.2019

Хороший способ создать разделители на всем экране настроек в androidx (на основе этот пост) — создать подкласс предпочтений и переопределите onBindViewHolder, а затем используйте его в xml. Он работает в

implementation 'androidx.preference:preference:1.1.1'

но, к сожалению, это не очень хорошее решение для экранов с более чем одним типом предпочтений (можно создать подкласс для 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);
  }

}

person Vít Kapitola    schedule 17.06.2020