Android: как убрать поля / отступы на экране настроек
Я сталкиваюсь с очень странной проблемой при проектировании экрана предпочтений. Хотя я не даю никакого запаса в макете, он оставляет некоторое пространство слева.
Как вы можете видеть на изображении ниже:
XML:
<PreferenceScreen android:title="demo" >
<CheckBoxPreference
android:defaultValue="false"
android:key="prefSync"`
android:title="Auto Sync" />
</PreferenceScreen>
Я делаю что-то не так, добавляя флажок на экране?
18 ответов
Обновление это для Android.
После долгих экспериментов я решил эту проблему, добавив ее к каждому предпочтению, имеющему лишний отступ:
app:iconSpaceReserved="false"
Конечно, вам также нужно добавить это в само объявление PreferenceScreen вверху вашего xml:
xmlns:app="http://schemas.android.com/apk/res-auto"
Я сообщил об этой проблеме здесь (вы также можете проверить мой обходной проект там), но на данный момент я нашел немного хакерский, но простой способ преодолеть это:
За
PreferenceCategory
Я установил начальное / левое заполнение его макетов на 0.Для других типов предпочтений я хочу скрыть
icon_frame
в случае, если у них нет значка.
Вот код Просто простирайтесь от этого класса, а остальное - автоматически:
Котлин
abstract class BasePreferenceFragment : PreferenceFragmentCompat() {
override fun onCreateAdapter(preferenceScreen: PreferenceScreen?): RecyclerView.Adapter<*> {
return object : PreferenceGroupAdapter(preferenceScreen) {
override fun onBindViewHolder(holder: PreferenceViewHolder, position: Int) {
super.onBindViewHolder(holder, position)
val preference = getItem(position)
if (preference is PreferenceCategory)
setZeroPaddingToLayoutChildren(holder.itemView)
else
holder.itemView.findViewById<View?>(R.id.icon_frame)?.visibility = if (preference.icon == null) View.GONE else View.VISIBLE
}
}
}
private fun setZeroPaddingToLayoutChildren(view: View) {
if (view !is ViewGroup)
return
val childCount = view.childCount
for (i in 0 until childCount) {
setZeroPaddingToLayoutChildren(view.getChildAt(i))
if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.JELLY_BEAN_MR1)
view.setPaddingRelative(0, view.paddingTop, view.paddingEnd, view.paddingBottom)
else
view.setPadding(0, view.paddingTop, view.paddingRight, view.paddingBottom)
}
}
}
Джава
public abstract class BasePreferenceFragmentCompat extends PreferenceFragmentCompat {
@Override
protected RecyclerView.Adapter onCreateAdapter(PreferenceScreen preferenceScreen) {
return new PreferenceGroupAdapter(preferenceScreen) {
@SuppressLint("RestrictedApi")
@Override
public void onBindViewHolder(PreferenceViewHolder holder, int position) {
super.onBindViewHolder(holder, position);
Preference preference = getItem(position);
if (preference instanceof PreferenceCategory)
setZeroPaddingToLayoutChildren(holder.itemView);
else {
View iconFrame = holder.itemView.findViewById(R.id.icon_frame);
if (iconFrame != null) {
iconFrame.setVisibility(preference.getIcon() == null ? View.GONE : View.VISIBLE);
}
}
}
};
}
private void setZeroPaddingToLayoutChildren(View view) {
if (!(view instanceof ViewGroup))
return;
ViewGroup viewGroup = (ViewGroup) view;
int childCount = viewGroup.getChildCount();
for (int i = 0; i < childCount; i++) {
setZeroPaddingToLayoutChildren(viewGroup.getChildAt(i));
if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.JELLY_BEAN_MR1)
viewGroup.setPaddingRelative(0, viewGroup.getPaddingTop(), viewGroup.getPaddingEnd(), viewGroup.getPaddingBottom());
else
viewGroup.setPadding(0, viewGroup.getPaddingTop(), viewGroup.getPaddingRight(), viewGroup.getPaddingBottom());
}
}
}
И результат (образец XML можно найти здесь из этого примера Google, который я создал здесь, чтобы проверить):
Этот код немного опасен, поэтому убедитесь, что при каждом обновлении библиотеки вы проверяете, что он работает нормально.
Кроме того, это может не сработать в некоторых особых случаях, например, когда вы определяете android:layout
по своему усмотрению, так что вам придется изменить его по этому вопросу.
Получил лучшее, более официальное решение:
Для каждого предпочтения используйте app:iconSpaceReserved="false"
, Это должно работать нормально, но по какой-то причине есть (известная) ошибка, которая не работает для PreferenceCategory. Об этом сообщалось здесь, и должно быть исправлено в ближайшее время.
Так что сейчас вы можете использовать смешанную версию обходного пути, который я написал, и этот флаг.
РЕДАКТИРОВАТЬ: нашел еще одно решение. Этот изменит все настройки и установит isIconSpaceReserved
для каждого. К сожалению, как я уже писал выше, если вы используете PreferenceCategory, он разрушает его, но он должен работать нормально, если вы его не используете:
Котлин
abstract class BasePreferenceFragment : PreferenceFragmentCompat() {
override fun setPreferenceScreen(preferenceScreen: PreferenceScreen?) {
super.setPreferenceScreen(preferenceScreen)
if (preferenceScreen != null) {
val count = preferenceScreen.preferenceCount
for (i in 0 until count)
preferenceScreen.getPreference(i)!!.isIconSpaceReserved = false
}
}
Джава
public class BasePreferenceFragment extends PreferenceFragmentCompat {
@Override
public void setPreferenceScreen(PreferenceScreen preferenceScreen) {
super.setPreferenceScreen(preferenceScreen);
if (preferenceScreen != null) {
int count = preferenceScreen.getPreferenceCount();
for (int i = 0; i < count; i++)
preferenceScreen.getPreference(i).setIconSpaceReserved(false);
}
}
}
РЕДАКТИРОВАТЬ: после того, как Google, наконец, исправил библиотеку (ссылка здесь), я получил другое работающее решение:
abstract class BasePreferenceFragment : PreferenceFragmentCompat() {
private fun setAllPreferencesToAvoidHavingExtraSpace(preference: Preference) {
preference.isIconSpaceReserved = false
if (preference is PreferenceGroup)
for (i in 0 until preference.preferenceCount)
setAllPreferencesToAvoidHavingExtraSpace(preference.getPreference(i))
}
override fun setPreferenceScreen(preferenceScreen: PreferenceScreen?) {
if (preferenceScreen != null)
setAllPreferencesToAvoidHavingExtraSpace(preferenceScreen)
super.setPreferenceScreen(preferenceScreen)
}
override fun onCreateAdapter(preferenceScreen: PreferenceScreen?): RecyclerView.Adapter<*> =
object : PreferenceGroupAdapter(preferenceScreen) {
@SuppressLint("RestrictedApi")
override fun onPreferenceHierarchyChange(preference: Preference?) {
if (preference != null)
setAllPreferencesToAvoidHavingExtraSpace(preference)
super.onPreferenceHierarchyChange(preference)
}
}
}
Просто продолжайте, и у вас не будет бесполезного отступа для ваших предпочтений. Пример проекта здесь, где я также прошу иметь официальный способ избежать этого, вместо этих уловок. Пожалуйста, подумайте об этом.
Простое рабочее решение здесь:
Создайте res/values-sw360dp-v13/values-preference.xml
:
<resources xmlns:tools="http://schemas.android.com/tools">
<bool name="config_materialPreferenceIconSpaceReserved" tools:ignore="MissingDefaultResource,PrivateResource">false</bool>
<dimen name="preference_category_padding_start" tools:ignore="MissingDefaultResource,PrivateResource">0dp</dimen>
</resources>
<bool>
исправляет значение по умолчанию iconSpacePreserved
для всех Preference
; <dimen>
исправляет PreferenceCategory.
Попробуй это:
@Override
public View onCreateView(LayoutInflater inflater, ViewGroup container,
Bundle savedInstanceState) {
View v = super.onCreateView(inflater, container, savedInstanceState);
if(v != null) {
ListView lv = (ListView) v.findViewById(android.R.id.list);
lv.setPadding(10, 10, 10, 10);
}
return v;
}
Вы можете установить отступ, используя: setPadding();
К сожалению, у меня ничего не сработало.
Краткий ответ:
Я решил это, используя отрицательные поля в верхнем контейнере макета пользовательских настроек.
шаги:
- Создайте пользовательский макет для предпочтения (например, preference_category.xml)
- укажите, что ваши предпочтения используют пользовательский макет, добавив параметр android: layout в тег предпочтения в XML
- Применить отрицательные поля
Подробный ответ:
Предпочтительный XML:
<android.support.v7.preference.PreferenceScreen
xmlns:android="http://schemas.android.com/apk/res/android"
android:title="@string/settings_title" >
<android.support.v7.preference.PreferenceCategory
android:layout="@layout/preference_category"
android:key="settings_list"
android:title="@string/pref_category_settings" />
<android.support.v7.preference.SwitchPreferenceCompat
android:layout="@layout/preference_row"
android:icon="@drawable/ic_nav_switch"
android:key="pref_switch"
android:title="@string/pref_switch_title" />
</android.support.v7.preference.PreferenceScreen>
Пользовательский макет для строки предпочтений, который удаляет ненужные левый и правый поля:
<LinearLayout xmlns:android="http://schemas.android.com/apk/res/android"
android:layout_width="match_parent"
android:layout_height="wrap_content"
android:layout_marginStart="-12dp"
android:layout_marginEnd="-8dp"
android:minHeight="?android:attr/listPreferredItemHeight"
android:gravity="center_vertical">
<RelativeLayout
android:layout_width="wrap_content"
android:layout_height="wrap_content">
<ImageView
android:id="@android:id/icon"
android:layout_width="58dp"
android:layout_height="58dp"
android:padding="8dp"
android:layout_gravity="center"
android:visibility="visible" />
</RelativeLayout>
<RelativeLayout
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:layout_marginStart="15dp"
android:layout_marginEnd="6dp"
android:layout_marginTop="6dp"
android:layout_marginBottom="6dp"
android:layout_weight="1">
<TextView
android:id="@android:id/title"
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:singleLine="true"
android:textAppearance="?android:attr/textAppearanceListItem"
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_alignStart="@android:id/title"
android:textAppearance="?android:attr/textAppearanceListItemSecondary"
android:textColor="?android:attr/textColorSecondary"
android:maxLines="2"/>
</RelativeLayout>
<LinearLayout
android:id="@android:id/widget_frame"
android:layout_width="wrap_content"
android:layout_height="match_parent"
android:gravity="end|center_vertical"
android:orientation="vertical">
</LinearLayout>
</LinearLayout>
Пользовательский макет для категории предпочтений, который удаляет ненужные левый и правый поля:
<TextView xmlns:android="http://schemas.android.com/apk/res/android"
android:layout_width="match_parent"
android:layout_height="wrap_content"
android:textColor="@color/colorAccent"
android:textStyle="bold"
android:textSize="12sp"
android:gravity="center_vertical"
android:textAllCaps="true"
android:layout_marginStart="-4dp"
android:layout_marginEnd="-8dp"
android:id="@+android:id/title" />
Если вы используете com.android.support:preference-v7
библиотека, убедитесь, что тема для действия, в котором размещены ваши предпочтения, имеет preferenceTheme
установить наложение темы предпочтения материала v14:
<item name="preferenceTheme">@style/PreferenceThemeOverlay.v14.Material</item>
Измените тему предпочтений следующим образом. Убедитесь, что вы используете последнюю версию библиотеки настроек androidx.preference 1.1.0-alpha01
<style name="AppTheme" parent="Theme.AppCompat.Light.NoActionBar">
<!-- Customize your theme here. -->
<item name="preferenceTheme">@style/CustomPreferenceTheme</item>
</style>
<style name="CustomPreferenceTheme" parent="@style/PreferenceThemeOverlay">
<item name="preferenceFragmentCompatStyle">@style/CustomPreferenceFragmentCompatStyle</item>
<item name="preferenceCategoryStyle">@style/CustomPreferenceCategory</item>
<item name="preferenceStyle">@style/CustomPreference</item>
<item name="checkBoxPreferenceStyle">@style/CustomCheckBoxPreference</item>
<item name="dialogPreferenceStyle">@style/CustomDialogPreference</item>
<item name="switchPreferenceCompatStyle">@style/CustomSwitchPreferenceCompat</item> <!-- for pre lollipop(v21) -->
<item name="switchPreferenceStyle">@style/CustomSwitchPreference</item>
</style>
<style name="CustomPreferenceFragmentCompatStyle" parent="@style/PreferenceFragment.Material">
<item name="android:layout">@layout/fragment_settings</item>
</style>
<style name="CustomPreferenceCategory" parent="Preference.Category.Material">
<item name="iconSpaceReserved">false</item>
</style>
<style name="CustomPreference" parent="Preference.Material">
<item name="iconSpaceReserved">false</item>
</style>
<style name="CustomCheckBoxPreference" parent="Preference.CheckBoxPreference.Material">
<item name="iconSpaceReserved">false</item>
</style>
<style name="CustomDialogPreference" parent="Preference.DialogPreference.Material">
<item name="iconSpaceReserved">false</item>
</style>
<style name="CustomSwitchPreferenceCompat" parent="Preference.SwitchPreferenceCompat.Material">
<item name="iconSpaceReserved">false</item>
</style>
<style name="CustomSwitchPreference" parent="Preference.SwitchPreference.Material">
<item name="iconSpaceReserved">false</item>
</style>
Заполнение вызвано родителем ListView
в PreferenceScreen
содержащий ваши настройки. Если вы используете PreferenceFragment
чтобы создать свои предпочтения, просто перейдите на onActivityCreated
функция PreferenceFragement
и выполните следующие действия, чтобы удалить отступы:
public void onActivityCreated(Bundle savedInstanceState) {
super.onActivityCreated(savedInstanceState);
View lv = getView().findViewById(android.R.id.list);
if (lv != null) lv.setPadding(0, 0, 0, 0);
}
Скомпилируйте 'com.android.support:preference-v7:24.2.1'
Использование PreferenceFragmentCompat может сделать это:
1. Определите PreferenceGroupAdapter:
static class CustomAdapter extends PreferenceGroupAdapter {
public CustomAdapter(PreferenceGroup preferenceGroup) {
super(preferenceGroup);
}
@Override
public PreferenceViewHolder onCreateViewHolder(ViewGroup parent, int viewType) {
PreferenceViewHolder preferenceViewHolder = super.onCreateViewHolder(parent, viewType);
parent.setPadding(0, 0, 0, 0);
preferenceViewHolder.itemView.setPadding(20, 5, 20, 5);
return preferenceViewHolder;
}
}
2. Метод onCreateAdapter метода PreferenceFragmentCompat:
@Override
protected Adapter onCreateAdapter(PreferenceScreen preferenceScreen) {
return new CustomAdapter(preferenceScreen);
}
Использование style.xml может сделать это:
1.values / styles.xml:
<style name="customPreferenceThemeOverlay" parent="@style/PreferenceThemeOverlay">
<item name="preferenceFragmentListStyle">@style/customPreferenceFragmentList</item>
</style>
<style name="customPreferenceFragmentList">
<item name="android:paddingLeft">0dp</item>
<item name="android:paddingRight">0dp</item>
</style>
2.values-v17 / styles.xml:
<style name="customPreferenceFragmentList">
<item name="android:paddingLeft">0dp</item>
<item name="android:paddingRight">0dp</item>
<item name="android:paddingStart">0dp</item>
<item name="android:paddingEnd">0dp</item>
</style>
3.value / styles.xml:
<style name="AppTheme" parent="Theme.AppCompat.Light.NoActionBar">
<!-- Customize your theme here. -->
... ...
<item name="preferenceTheme">@style/customPreferenceThemeOverlay</item>
</style>
Просто добавьте этот атрибут в тег предпочтений
app:iconSpaceReserved="false"
Ни один из приведенных выше ответов не сработал, мне пришлось скопировать макет настроек, создать новый файл макета, такой как custom_preference.xml, переопределить содержимое макета, установив видимость рамки значка на GONE. А затем в pref.xml установите макет для предпочтения использовать этот пользовательский макет.
<?xml version="1.0" encoding="utf-8"?>
<PreferenceScreen xmlns:android="http://schemas.android.com/apk/res/android"
android:layout_width="match_parent"
android:layout_height="match_parent"
>
<android.support.v7.preference.EditTextPreference
android:title="@string/pref_label"
android:hint="@string/pref_hint"
android:key="@string/pref_key"
android:inputType="text"
android:singleLine="true"
android:layout="@layout/custom_preference_layout"
/>
</PreferenceScreen>
Если вы используете AndroidX, вы можете добавить/удалить дополнительные отступы, просто добавив следующий атрибут.
<Preference
...
app:iconSpaceReserved="false/true"
.../>
Видимо, добавляя android:layout="@null"
чтобы ваши предпочтения в XML сделали свое дело. Но, следовательно, это также увеличит размер заголовка.
Я пытаюсь использовать
android:icon="@null"
с CheckBoxPreference
в Android 4.4, но не может заполнять слева. Я обманул использование маленького прозрачного значка и добавил
android:icon="@drawable/transparent_icon"
и это похоже на работу для меня. Я надеюсь, что это может помочь. Благодарю.
Я не знаю, уже слишком поздно для ответа, но сегодня у меня была та же проблема, и ничто из этих ответов не помогло мне.
Поэтому я использовал это решение:
В моем DisclaimerPreference
тот extends Preference
Я овериду onBindView(View view)
метод таким образом:
@Override protected void onBindView(View view) {
super.onBindView(view);
if(view instanceof ViewGroup){
ViewGroup vg = (ViewGroup)view;
View currView;
for(int i=0; i<vg.getChildCount(); i++){
currView = vg.getChildAt(i);
if (currView instanceof RelativeLayout)
currView.setVisibility(View.GONE);
}
}
}
Ключ должен установить RelativeLayout
внутри основной вид как GONE
, Пожалуйста, дайте мне знать, если что-то не так:)
Спросил довольно давно, но то, что помогло мне решить эту проблему, было отрицательные поля, нет необходимости в пользовательских файлах.
Когда вы создаете свой класс SettingsActivity (в котором есть PreferenceFragment внутри), вы просто устанавливаете его макет как фрагмент и добавляете отрицательное поле.
settings_activity:
<?xml version="1.0" encoding="utf-8"?>
<fragment
android:layout_marginLeft="-40dp"
android:name="com.example.USER.APPNAME.SettingsActivity$PrefsFragment"
xmlns:android="http://schemas.android.com/apk/res/android"
xmlns:tools="http://schemas.android.com/tools"
android:layout_width="match_parent"
android:layout_height="match_parent"
tools:context="com.example.USER.APPNAME.SettingsActivity">
</fragment>
"Заполнение" начинается в PreferenceFrameLayout.java
:
public PreferenceFrameLayout(Context context, AttributeSet attrs, int defStyle) {
super(context, attrs, defStyle);
TypedArray a = context.obtainStyledAttributes(attrs,
com.android.internal.R.styleable.PreferenceFrameLayout, defStyle, 0);
float density = context.getResources().getDisplayMetrics().density;
int defaultBorderTop = (int) (density * DEFAULT_BORDER_TOP + 0.5f);
int defaultBottomPadding = (int) (density * DEFAULT_BORDER_BOTTOM + 0.5f);
int defaultLeftPadding = (int) (density * DEFAULT_BORDER_LEFT + 0.5f);
int defaultRightPadding = (int) (density * DEFAULT_BORDER_RIGHT + 0.5f);
mBorderTop = a.getDimensionPixelSize(
com.android.internal.R.styleable.PreferenceFrameLayout_borderTop,
defaultBorderTop);
mBorderBottom = a.getDimensionPixelSize(
com.android.internal.R.styleable.PreferenceFrameLayout_borderBottom,
defaultBottomPadding);
mBorderLeft = a.getDimensionPixelSize(
com.android.internal.R.styleable.PreferenceFrameLayout_borderLeft,
defaultLeftPadding);
mBorderRight = a.getDimensionPixelSize(
com.android.internal.R.styleable.PreferenceFrameLayout_borderRight,
defaultRightPadding);
a.recycle();
}
Если вы знаете, как переопределить стили, определенные в Android, вы можете решить эту проблему. Это не очень прямо вперед, однако.
Добавлять android:defaultValue="false"
на ваш <PreferenceScreen [...]
Тег:
<PreferenceScreen xmlns:android="http://schemas.android.com/apk/res/android" android:defaultValue="false">