J'ai signalé ce problème aquí (vous pouvez également consulter mon projet de contournement), mais pour l'instant, j'ai trouvé un moyen un peu bricolé, mais facile, de surmonter ce problème :
-
Pour PreferenceCategory
j'ai réglé le padding de début/gauche de ses mises en page sur 0.
-
Pour les autres types de préférences, je choisis de masquer le icon_frame
au cas où ils n'auraient pas d'icône.
Voici le code. Il suffit d'étendre cette classe et le reste est automatique :
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());
}
}
}
Et le résultat (échantillon XML) peut être trouvé aquí de cet échantillon Google que j'ai créé aquí à vérifier) :
Ce code est un peu dangereux, aussi assurez-vous qu'à chaque mise à jour de la bibliothèque, vous vérifiez qu'il fonctionne bien.
En outre, elle peut ne pas fonctionner correctement dans certains cas particuliers, par exemple lorsque vous définissez android:layout
de votre propre préférence, vous devrez donc le modifier pour cette question.
J'ai une meilleure solution, plus officielle :
Pour chaque préférence, utilisez app:iconSpaceReserved="false"
. Cela devrait fonctionner correctement, mais pour une raison quelconque, il y a un bogue (connu) qui fait que cela ne fonctionne pas pour PreferenceCategory. Il a été signalé aquí et devrait être corrigé dans un avenir proche.
Pour l'instant, vous pouvez donc utiliser une version mixte de la solution de contournement que j'ai écrite et de ce drapeau.
EDIT : J'ai trouvé une autre solution. Celle-ci permet de passer outre toutes les préférences, et de définir isIconSpaceReserved
pour chacun. Malheureusement, comme je l'ai écrit ci-dessus, si vous utilisez PreferenceCategory, cela gâche tout, mais cela devrait fonctionner correctement si vous ne l'utilisez pas :
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);
}
}
}
EDIT : après que Google ait finalement corrigé la bibliothèque (lien aquí ), vous pouvez définir le drapeau pour chaque préférence, ou utiliser cette solution qui le fait pour tous, pour vous :
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)
}
}
}
Il suffit de s'en éloigner, et vous n'aurez pas de rembourrage inutile pour vos préférences. Exemple de projet aquí Je demande également qu'il existe un moyen officiel de l'éviter, au lieu de ces astuces. S'il vous plaît envisager de l'étoiler.