programacion - Android: Cómo obtener eliminar margen/relleno en la pantalla de preferencias
manual de programacion android pdf (15)
Actualizando esto para androidx.
Después de mucha experimentación, resolví este problema agregando esto a cada preferencia que tenía una sangría excesiva:
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"
Estoy enfrentando un problema muy extraño en el diseño de la pantalla de preferencias. Aunque no estoy dando ningún margen en el diseño, queda algo de espacio a la izquierda.
Como se puede ver en la imagen de abajo:
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 la casilla de verificación en la pantalla?
Agregue android:defaultValue="false"
a su etiqueta <PreferenceScreen [...]
:
<PreferenceScreen xmlns:android="http://schemas.android.com/apk/res/android" android:defaultValue="false">
Aparentemente, 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.
Cambia el tema de preferencias como este. Asegúrese de usar 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>
Desafortunadamente, nada de arriba funcionó para mí.
Respuesta corta :
Resolví esto utilizando márgenes negativos en el contenedor superior del diseño de preferencias personalizado.
Pasos:
- Cree un diseño personalizado para la preferencia (p. Ej. Preferences_category.xml)
- especifique que su preferencia usa el diseño personalizado agregando android: layout param a una etiqueta de preferencia en XML
- Aplicar márgenes negativos.
Respuesta detallada:
La preferencia 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>
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 preferencia 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" />
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 podría resolver esto. Sin embargo, no es muy sencillo.
El relleno es causado por el ListView
principal en la ListView
de PreferenceScreen
contiene sus ajustes. Si está utilizando un PreferenceFragment
para crear sus preferencias, solo vaya a la función onActivityCreated
del PreferenceFragement
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);
}
He informado sobre este problema here (también puede consultar mi proyecto de solución), pero por ahora, he encontrado un poco de piratería, pero una forma fácil de superar esto:
Para
PreferenceCategory
, establezco el inicio / relleno izquierdo de sus diseños en 0.Para otros tipos de preferencias, elijo ocultar el
icon_frame
en caso de que no tengan un icono.
Aquí está el código. Solo amplíe desde 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 here de esta muestra de Google , que he creado here para verla):
Este código es un poco peligroso, así que asegúrese de que con cada actualización de la biblioteca, verifique que funcione bien.
Además, es posible que no funcione bien en algunos casos especiales, como cuando define android:layout
propio para la preferencia, por lo que tendrá que modificarlo para este asunto.
Tengo una solución mejor, más oficial:
Para cada preferencia, use la app:iconSpaceReserved="false"
. Esto debería funcionar bien, pero por alguna razón hay un error (conocido) que no funciona para PreferenceCategory. Se informó here , y se debe arreglar en un futuro próximo.
Así que por ahora puedes usar una versión mixta de la solución que escribí y esta bandera.
EDIT: Encontró otra solución. Éste superará todas las preferencias y establecerá isIconSpaceReserved
para cada una. Lamentablemente, como he escrito anteriormente, si usas la Categoría de Preferencia, la arruina, pero debería funcionar bien si no la usas:
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 arregle la biblioteca (enlace here ), puede establecer la marca 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ás el relleno inútil para tus preferencias. Ejemplo de proyecto here , donde también solicito tener una forma oficial de evitarlo, en lugar de esos trucos. Por favor considere protagonizarlo.
Ninguna de las respuestas anteriores funcionó, tuve que copiar el diseño de preference , 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, establezca el diseño de 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>
No sé si es demasiado tarde para una respuesta, pero hoy tuve el mismo problema y ninguna de estas respuestas me ayudó.
Así que utilicé esta solución:
En mi DisclaimerPreference
que extends Preference
, dejo de lado el onBindView(View view)
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 configurar el RelativeLayout
dentro de la Vista principal como GONE
. Por favor, hágamelo saber si algo está mal :)
Pregunté hace bastante tiempo, pero lo que me ayudó a resolver esto fue márgenes negativos, sin necesidad de archivos personalizados.
Cuando crea su clase SettingsActivity (que contiene PreferenceFragment), 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>
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;
}
Puedes configurar el relleno usando: setPadding();
Si está utilizando la biblioteca com.android.support:preference-v7
, asegúrese de que el tema para la actividad que aloja sus preferencias tenga un tema de preferencia en la superposición del tema de preferencia de Material v14:
<item name="preferenceTheme">@style/PreferenceThemeOverlay.v14.Material</item>
Trato de usar
android:icon="@null"
con CheckBoxPreference
en Android 4.4 pero no se puede rellenar desde la izquierda. Utilicé un pequeño icono transparente y lo agregué
android:icon="@drawable/transparent_icon"
Y parece que funciona para mí. Espero que pueda ayudar. Gracias.
compile ''com.android.support:preference-v7:24.2.1''
Use PreferenceFragmentCompat puede hacer esto:
1. Definir un adaptador de grupo de preferencia:
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. Anular el método onCreateAdapter de PreferenceFragmentCompat:
@Override
protected Adapter onCreateAdapter(PreferenceScreen preferenceScreen) {
return new CustomAdapter(preferenceScreen);
}
Use style.xml puede hacer esto:
1.values / 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.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>