Ich habe ein sehr seltsames Problem beim Entwerfen des Einstellungsbildschirms. Obwohl ich im Layout keinen Spielraum gebe, lässt es links etwas Platz.
Wie Sie im Bild unten sehen können:
XML:
<PreferenceScreen android:title="demo" >
<CheckBoxPreference
android:defaultValue="false"
android:key="prefSync"`
android:title="Auto Sync" />
</PreferenceScreen>
Mache ich etwas falsch, wenn ich die Kontrollkästcheneinstellungen auf dem Bildschirm hinzufüge?
Antworten:
Aktualisierung für AndroidX.
Nach vielen Experimenten habe ich dieses Problem behoben, indem ich dies zu jeder Präferenz hinzugefügt habe , die die überschüssige Einrückung hatte:
app:iconSpaceReserved="false"
Natürlich müssen Sie dies auch zur PreferenceScreen-Deklaration oben in Ihrer XML-Datei hinzufügen:
xmlns:app="http://schemas.android.com/apk/res-auto"
Follow-up für benutzerdefinierte Einstellungen
Ich habe festgestellt, dass bei benutzerdefinierten Einstellungen, insbesondere bei älteren Geräten, diese Lösung nicht immer funktioniert. Eine solche Präferenz könnte beispielsweise immer noch eingerückt sein:
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"
Das Problem ist auf die Verwendung des dritten Konstruktorparameters in der benutzerdefinierten Voreinstellungsklasse zurückzuführen. Wenn Sie diesen dritten Parameter übergeben, wird das Listenelement eingerückt. Wenn Sie es weglassen, wird die Liste korrekt ausgerichtet:
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 } }
Verwenden Sie stattdessen Folgendes:
class SomeCustomPreference @JvmOverloads constructor( context: Context, attrs: AttributeSet? = null ) : DialogPreference(context, attrs) { override fun getDialogLayoutResource(): Int { return R.layout.my_layout } }
Die Gutschrift dafür geht an @CommonsWare in diesem sehr alten Beitrag .
quelle
PreferenceFragmentCompat
Support-Bibliothek28.0.0
. Toll!Ich habe über dieses Thema berichtet hier (Sie können auch dort meine Abhilfe Projekt überprüfen), aber für jetzt, ich habe ein bisschen Hack-y, aber einfache Weise zu überwinden diese gefunden:
Für
PreferenceCategory
setze ich den Start / Links-Abstand seiner Layouts auf 0.Für andere Arten von Einstellungen habe ich mich entschieden, diese auszublenden,
icon_frame
falls sie kein Symbol haben.Hier ist der Code. Verlängern Sie einfach diese Klasse und der Rest erfolgt automatisch:
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()); } } }
Und das Ergebnis (XML-Beispiel finden Sie hier in diesem Google-Beispiel , das ich hier zum Auschecken erstellt habe ):
Dieser Code ist etwas gefährlich. Stellen Sie daher sicher, dass Sie bei jedem Update der Bibliothek überprüfen, ob er ordnungsgemäß funktioniert.
Außerdem funktioniert es in einigen Sonderfällen möglicherweise nicht gut, z. B. wenn Sie
android:layout
für die Präferenz eine eigene Definition festlegen. Daher müssen Sie diese für diese Angelegenheit ändern.Ich habe eine bessere, offiziellere Lösung:
Verwenden Sie für jede Präferenz
app:iconSpaceReserved="false"
. Dies sollte gut funktionieren, aber aus irgendeinem Grund gibt es einen (bekannten) Fehler, der für PreferenceCategory nicht funktioniert. Es wurde hier berichtet und sollte in naher Zukunft behoben werden.Im Moment können Sie also eine Mix-Version der von mir geschriebenen Problemumgehung und dieses Flag verwenden.
EDIT: Noch eine andere Lösung gefunden. Dieser wird alle Einstellungen überwinden und
isIconSpaceReserved
für jede festlegen . Wie ich oben geschrieben habe, ruiniert es leider, wenn Sie PreferenceCategory verwenden, aber es sollte gut funktionieren, wenn Sie es nicht verwenden: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); } } }
BEARBEITEN: Nachdem Google die Bibliothek endgültig repariert hat (Link hier ), können Sie das Flag für jede Voreinstellung setzen oder diese Lösung verwenden, die dies für alle erledigt:
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) } } }
Erweitern Sie es einfach, und Sie werden nicht die nutzlose Polsterung für Ihre Vorlieben haben. Beispielprojekt hier , bei dem ich anstelle dieser Tricks auch einen offiziellen Weg fordere, dies zu vermeiden. Bitte erwägen Sie, es zu markieren.
quelle
Einfache Arbeitslösung von hier .
Es funktioniert über alle Einstellungen hinweg, ohne dass in alle Einstellungen geschrieben werden muss
app:iconSpaceReserved="false"
Erstellen
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>
Das
<bool>
behebt den Standardwert voniconSpacePreserved
für allePreference
; Das<dimen>
behebt die PreferenceCategory.BEARBEITEN: Wenn Sie verwenden
androidx.preference:preference:1.1.1
, benötigen Sie das Maß nichtpreference_category_padding_start
. Getestet auf Android 6-10.quelle
Versuche dies:
@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; }
Sie können die Polsterung wie folgt einstellen:
setPadding();
quelle
PreferenceFragmentCompat
nicht mehr der Grund. Das Auffüllen (oder nur ein Symbolrahmen) ist jetzt Teil der Ansichten der Einstellungen.Wenn Sie die
com.android.support:preference-v7
Bibliothek verwenden, stellen Sie sicher, dass für das Thema für die Aktivität, in der IhrepreferenceTheme
Einstellungen gehostet werden, die Überlagerung des Themas für Materialeinstellungen v14 festgelegt ist:<item name="preferenceTheme">@style/PreferenceThemeOverlay.v14.Material</item>
quelle
PreferenceFragmentCompat
Klasse?PreferenceFragmentCompat
jetzt auch, aber seitdem habe ich meinen Einstellungsbildschirm neu gestaltet und es enthält Symbole, die dieses Auffüllen für mich jetzt wünschenswert machen (es hilft, die linke Ausrichtung konsistent zu halten).Leider hat bei mir nichts von oben funktioniert.
Kurze Antwort :
Ich habe dies gelöst, indem ich einen negativen Rand für den obersten Container des benutzerdefinierten Einstellungslayouts verwendet habe.
Schritte:
Detaillierte Antwort:
Die Präferenz 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>
Das benutzerdefinierte Layout für die Voreinstellungszeile, mit dem unnötige linke und rechte Ränder entfernt werden:
<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>
Das benutzerdefinierte Layout für die Einstellungskategorie, mit dem unnötige linke und rechte Ränder entfernt werden:
<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" />
quelle
Die Polsterung wird von den Eltern verursacht
ListView
in denPreferenceScreen
Einstellungen enthält. Wenn SiePreferenceFragment
zum Erstellen Ihrer Einstellungen ein verwenden, gehen Sie einfach zuronActivityCreated
Funktion vonPreferenceFragement
und gehen Sie wie folgt vor, um die Polsterung zu entfernen: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); }
quelle
PreferenceFragmentCompat
ist dies nicht mehr der Grund. Das Auffüllen (oder nur ein Symbolrahmen) ist jetzt Teil der Ansichten der Einstellungen.Ändern Sie das Präferenzthema wie folgt. Stellen Sie sicher, dass Sie die neueste Version der Einstellungsbibliothek verwenden
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>
quelle
androidx.preference:preference:1.1.0-alpha01
. Die Gerätedrehung auf einem zweiten Fragmentstapel in der App führt zu einem Absturz. Ich hoffe, dass es in späteren Versionen behoben wird. Ich gehe zurück zuandroidx.preference:preference:1.0.0
.kompiliere 'com.android.support:preference-v7:24.2.1'
Verwenden Sie PreferenceFragmentCompat, um dies zu tun:
1.Definieren Sie einen 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.Überschreiben Sie die onCreateAdapter-Methode von PreferenceFragmentCompat:
@Override protected Adapter onCreateAdapter(PreferenceScreen preferenceScreen) { return new CustomAdapter(preferenceScreen); }
Verwenden Sie style.xml, um dies zu tun:
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>
quelle
Keines der oben genannten Antwort gearbeitet, ich hatte das kopieren Präferenz Layout eine neue Layout - Datei wie custom_preference.xml erstellen, überschreibe das Layout Inhalt durch die Einstellung Sichtbarkeit des Symbol Rahmen GONE . Legen Sie dann in der Datei pref.xml das Layout fest, damit dieses benutzerdefinierte Layout bevorzugt verwendet wird.
<?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>
quelle
Das 'Auffüllen' wird eingeleitet in
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(); }
Wenn Sie wissen, wie Sie von Android definierte Stile überschreiben, können Sie dies wahrscheinlich lösen. Es ist jedoch nicht sehr einfach.
quelle
Ich versuche es mit
android:icon="@null"
mit
CheckBoxPreference
in Android 4.4, kann aber nicht von links auffüllen. Ich habe versucht, ein kleines transparentes Symbol zu verwenden und hinzuzufügenandroid:icon="@drawable/transparent_icon"
und es scheint Arbeit für mich. Ich hoffe es kann helfen. Vielen Dank.
quelle
Ich weiß nicht, ob es für eine Antwort zu spät ist, aber heute hatte ich das gleiche Problem und nichts von diesen Antworten hilft mir.
Also habe ich diese Lösung verwendet:
In meinem
DisclaimerPreference
dassextends Preference
, ovveride ich dasonBindView(View view)
Verfahren auf diese Weise:@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); } } }
Der Schlüssel ist, die
RelativeLayout
Innenansicht als festzulegenGONE
. Bitte lassen Sie mich wissen, wenn etwas nicht stimmt :)quelle
onBindView
ist im neuen nicht mehr verfügbarPreferenceFragmentCompat
. Stattdessen können Sie verwendenonCreateAdapter
undonBindViewHolder
, wie ich hier schrieb: stackoverflow.com/a/51568782/878126Anscheinend
android:layout="@null"
würde das Hinzufügen zu Ihrer Präferenz in XML den Trick tun. Infolgedessen wird der Titel jedoch auch größer.quelle
Fügen Sie diese Einstellung einfach in das Präferenz-Tag ein
app:iconSpaceReserved="false"
quelle
Vor einiger Zeit gefragt, aber was mir bei der Lösung dieses Problems geholfen hat, waren negative Ränder, keine benutzerdefinierten Dateien erforderlich.
Wenn Sie Ihre SettingsActivity-Klasse erstellen (in der sich das PreferenceFragment befindet), legen Sie das Layout einfach als Fragment fest und fügen einen negativen Rand hinzu.
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>
quelle
In
android:defaultValue="false"
zu Ihrem<PreferenceScreen [...]
Tag:<PreferenceScreen xmlns:android="http://schemas.android.com/apk/res/android" android:defaultValue="false">
quelle