Estoy enfrentando un problema muy extraño al diseñar la pantalla de preferencias. Aunque no estoy dando ningún margen en el diseño, deja algo de espacio a la izquierda.
Como puede ver en la imagen a continuación:
XML:
<PreferenceScreen android:title="demo" >
<CheckBoxPreference
android:defaultValue="false"
android:key="prefSync"`
android:title="Auto Sync" />
</PreferenceScreen>
¿Estoy haciendo algo mal al agregar la preferencia de casilla de verificación en la pantalla?
Respuestas:
Actualizando esto para androidx.
Después de mucha experimentación, resolví este problema agregando esto a cada preferencia que tenía el exceso de sangría:
app:iconSpaceReserved="false"
Por supuesto, también deberá agregar esto a la declaración PreferenceScreen en la parte superior de su xml:
xmlns:app="http://schemas.android.com/apk/res-auto"
Seguimiento de preferencias personalizadas
Noté que en el caso de las preferencias personalizadas, particularmente en dispositivos más antiguos, esta solución no siempre funcionaba. Por ejemplo, una preferencia como esta aún podría tener sangría:
com.example.preference.SomeCustomPreference android:id="@+id/some_custom_preference" android:name="Custom Preference" android:key="@string/custom_pref_key" android:summary="@string/custom_pref_summary" android:title="@string/preference_custom_title" app:iconSpaceReserved="false"
El problema se debe al uso del tercer parámetro de constructor en la clase de preferencia personalizada. Si pasa ese tercer parámetro, el elemento de la lista se sangrará. Si lo omite, la lista se alineará correctamente:
class SomeCustomPreference @JvmOverloads constructor( context: Context, attrs: AttributeSet? = null, defStyle: Int = android.R.attr.someCustomPreferenceStyle ) : DialogPreference(context, attrs, defStyle) { override fun getDialogLayoutResource(): Int { return R.layout.my_layout } }
En lugar de eso, usa esto:
class SomeCustomPreference @JvmOverloads constructor( context: Context, attrs: AttributeSet? = null ) : DialogPreference(context, attrs) { override fun getDialogLayoutResource(): Int { return R.layout.my_layout } }
El crédito por esto es para @CommonsWare en esta publicación muy antigua .
fuente
PreferenceFragmentCompat
soporte lib28.0.0
. ¡Excelente!He informado sobre este problema aquí (también puede consultar mi proyecto de solución allí), pero por ahora, he encontrado una manera un poco hack-y, pero fácil de superar esto:
Para
PreferenceCategory
, configuré el relleno inicial / izquierdo de sus diseños en 0.Para otros tipos de preferencias, elijo ocultar las
icon_frame
en caso de que no tengan un icono.Aquí está el código. Simplemente extiéndase de esta clase y el resto es automático:
Kotlin
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) } } }
Java
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()); } } }
Y el resultado (la muestra XML se puede encontrar aquí de esta muestra de Google , que he creado aquí para consultar):
Este código es un poco peligroso, así que asegúrese de que en cada actualización de la biblioteca, verifique que funciona bien.
Además, es posible que no funcione bien en algunos casos especiales, como cuando define
android:layout
su propia preferencia, por lo que tendrá que modificarlo para este asunto.Obtuve una solución mejor y más oficial:
Para cada preferencia, use
app:iconSpaceReserved="false"
. Esto debería funcionar bien, pero por alguna razón hay un error (conocido) que no funciona para PreferenceCategory. Se informó aquí y debería corregirse en un futuro próximo.Entonces, por ahora, puede usar una versión mixta de la solución alternativa que escribí y esta bandera.
EDITAR: Encontré otra solución. Este superará todas las preferencias y se establecerá
isIconSpaceReserved
para cada una. Lamentablemente, como escribí anteriormente, si usa PreferenceCategory, lo arruina, pero debería funcionar bien si no lo usa:Kotlin
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 } }
Java
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); } } }
EDITAR: después de que Google finalmente arregló la biblioteca (enlace aquí ), puede establecer la bandera para cada preferencia, o usar esta solución que lo hace para todos, para usted:
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) } } }
Simplemente extiéndalo y no tendrá el relleno inútil para sus preferencias. Proyecto de muestra aquí , donde también solicito tener una forma oficial de evitarlo, en lugar de esos trucos. Considere protagonizarlo.
fuente
Solución de trabajo simple desde aquí .
Funciona en todas las preferencias sin necesidad de escribir en todas las preferencias.
app:iconSpaceReserved="false"
Crear
res/values-sw360dp/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>
Las
<bool>
correcciones del valor por defecto deiconSpacePreserved
para todosPreference
; La<dimen>
fija el PreferenceCategory.EDITAR: Si está usando
androidx.preference:preference:1.1.1
, no necesitará la dimensiónpreference_category_padding_start
. Probado en Android 6-10.fuente
Prueba esto:
@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; }
Puede configurar el relleno usando:
setPadding();
fuente
PreferenceFragmentCompat
, esta ya no es la razón. El relleno (o simplemente un marco de icono) ahora es parte de las vistas de las preferencias.Si está utilizando la
com.android.support:preference-v7
biblioteca, asegúrese de que el tema de la actividad que aloja sus preferencias tenga unpreferenceTheme
conjunto para la superposición de tema de preferencia de material v14:<item name="preferenceTheme">@style/PreferenceThemeOverlay.v14.Material</item>
fuente
PreferenceFragmentCompat
clase?PreferenceFragmentCompat
ahora, pero desde entonces he rediseñado mi pantalla de configuración e incluye íconos, lo que hace que este relleno sea deseable para mí ahora (ayuda a mantener la alineación izquierda consistente).Desafortunadamente, nada de lo anterior funcionó para mí.
Respuesta corta :
Resolví esto usando márgenes negativos en el contenedor superior del diseño de preferencias personalizado.
Pasos:
Respuesta detallada:
El XML de preferencia:
<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>
El diseño personalizado para la fila de preferencias que elimina los márgenes izquierdo y derecho innecesarios:
<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>
El diseño personalizado para la categoría de preferencias que elimina los márgenes izquierdo y derecho innecesarios:
<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" />
fuente
El relleno es causado por el padre
ListView
en el quePreferenceScreen
contiene su configuración. Si está utilizando aPreferenceFragment
para crear sus Preferencias, simplemente vaya a laonActivityCreated
función dePreferenceFragement
y haga lo siguiente para eliminar el relleno: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); }
fuente
PreferenceFragmentCompat
, esta ya no es la razón. El relleno (o simplemente un marco de icono) ahora es parte de las vistas de las preferencias.Cambie el tema de preferencias de esta manera. Asegúrese de utilizar la última versión de la biblioteca de preferencias
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>
fuente
androidx.preference:preference:1.1.0-alpha01
. La rotación del dispositivo en cualquier segunda pila de fragmentos de la aplicación provocará un bloqueo. Espero que se solucione en versiones posteriores. Vuelvo aandroidx.preference:preference:1.0.0
.compilar 'com.android.support:preference-v7:24.2.1'
Use PreferenceFragmentCompat puede hacer esto:
1.Defina un 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.Override el método onCreateAdapter de PreferenceFragmentCompat:
@Override protected Adapter onCreateAdapter(PreferenceScreen preferenceScreen) { return new CustomAdapter(preferenceScreen); }
Use style.xml puede hacer esto:
1.valores / estilos.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.valores-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.valor / styles.xml:
<style name="AppTheme" parent="Theme.AppCompat.Light.NoActionBar"> <!-- Customize your theme here. --> ... ... <item name="preferenceTheme">@style/customPreferenceThemeOverlay</item> </style>
fuente
Ninguna de las respuestas anteriores funcionó, tuve que copiar el diseño de preferencias , crear un nuevo archivo de diseño como custom_preference.xml, anular el contenido del diseño configurando la visibilidad del marco del icono en GONE . Y luego, en pref.xml, configure el diseño para la preferencia para usar este diseño personalizado.
<?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>
fuente
El 'relleno' se inicia en
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(); }
Si sabe cómo anular los estilos definidos por Android, probablemente pueda resolver esto. Sin embargo, no es muy sencillo.
fuente
Intento usar
android:icon="@null"
con
CheckBoxPreference
en Android 4.4 pero no puede rellenar desde la izquierda. Engañé usar un pequeño ícono transparente y agregarandroid:icon="@drawable/transparent_icon"
y me parece que funciona. Espero que pueda ayudar. Gracias.
fuente
No sé si es demasiado tarde para una respuesta, pero hoy tuve el mismo problema y ninguna de estas respuestas me ayuda.
Entonces usé esta solución:
En mi
DisclaimerPreference
esoextends Preference
, anulo elonBindView(View view)
método de esta manera:@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); } } }
La clave es establecer el
RelativeLayout
interior de la Vista principal comoGONE
. Por favor avíseme si algo anda mal :)fuente
onBindView
ya no está disponible en el nuevoPreferenceFragmentCompat
. En su lugar, puede usaronCreateAdapter
yonBindViewHolder
, como escribí aquí: stackoverflow.com/a/51568782/878126Aparentemente, agregar
android:layout="@null"
a su preferencia en xml haría el truco. Pero en consecuencia, también aumentará el tamaño del título.fuente
Simplemente agregue este attirubte en la etiqueta de preferencia
app:iconSpaceReserved="false"
fuente
Pregunté hace bastante tiempo, pero lo que me ayudó a resolver esto fueron los márgenes negativos, sin necesidad de archivos personalizados.
Cuando crea su clase SettingsActivity (que tiene el PreferenceFragment adentro), simplemente configura su diseño para que sea un fragmento y agregue un margen negativo.
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>
fuente
Agregar
android:defaultValue="false"
a su<PreferenceScreen [...]
etiqueta:<PreferenceScreen xmlns:android="http://schemas.android.com/apk/res/android" android:defaultValue="false">
fuente