如下图所示: XML:
<PreferenceScreen android:title="demo" >
<CheckBoxPreference
android:defaultValue="false"
android:key="prefSync"`
android:title="Auto Sync" />
</PreferenceScreen>
在屏幕中添加复选框偏好设置的操作是否有误?
<PreferenceScreen android:title="demo" >
<CheckBoxPreference
android:defaultValue="false"
android:key="prefSync"`
android:title="Auto Sync" />
</PreferenceScreen>
在屏幕中添加复选框偏好设置的操作是否有误?
更新此内容以适应AndroidX。
经过大量试验,我通过将这个添加到每个具有多余缩进的偏好设置来解决了这个问题:
app:iconSpaceReserved="false"
当然,您还需要将此添加到您的xml顶部的PreferenceScreen声明本身中。xmlns:app="http://schemas.android.com/apk/res-auto"
关于自定义偏好的后续处理
我注意到在自定义偏好的情况下,特别是在旧设备上,这个解决方案并不总是有效。例如,像这样的偏好仍然可能会出现缩进:
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"
问题出在自定义首选项类中使用的第三个构造函数参数。如果传递该第三个参数,则列表项将缩进。如果省略它,则列表将正确对齐:
问题源于自定义偏好类中第三个构造参数的使用。如果传入该第三个参数,列表项将缩进。如果省略该参数,则列表将正确对齐:
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
}
}
使用这个而不是那个:
class SomeCustomPreference
@JvmOverloads constructor(
context: Context,
attrs: AttributeSet? = null
) : DialogPreference(context, attrs) {
override fun getDialogLayoutResource(): Int {
return R.layout.my_layout
}
}
这归功于@CommonsWare在这篇非常古老的帖子中。
28.0.0
的PreferenceFragmentCompat
。太好了! - jayeffkay对于PreferenceCategory
,我将其布局的开始/左填充设置为0。
对于其他类型的首选项,如果它们没有图标,我选择隐藏icon_frame
。
这是代码。只需从这个类扩展,其余部分就是自动的:
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());
}
}
}
以下是结果(XML示例可以在这里找到,我在这里创建了此Google示例以进行检查):
这段代码有些危险,因此在每次更新库时,请确保检查它是否正常工作。
同时,它可能在某些特殊情况下无法正常工作,例如当您为首选项定义自己的android:layout
时,您需要对其进行修改。
有一个更好、更官方的解决方案:
对于每个偏好设置,使用app:iconSpaceReserved="false"
。这应该可以正常工作,但由于某种原因,存在一个(已知的)错误,它不能用于PreferenceCategory。已在此处报告,应在不久的将来修复。
所以现在你可以使用我写的解决方法和这个标志的混合版本。
编辑:发现另一个解决方案。这个解决方案将覆盖所有偏好设置,并为每个偏好设置设置isIconSpaceReserved
。不幸的是,如上所述,如果您使用PreferenceCategory,它会破坏它,但如果您不使用它,它应该可以正常工作:
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);
}
}
}
编辑:在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)
}
}
}
只需从中扩展,您就不必为首选项设置无用的填充。示例项目在这里,我还要求有一种官方方法来避免它,而不是使用那些技巧。请考虑加星标。
onPreferenceHierarchyChange
方法 - Emmanuel Mtali这里提供一个简单的工作解决方案,来自这里。
它可以适用于所有偏好设置,无需编写所有偏好设置的app:iconSpaceReserved="false"
创建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>
<bool>
元素为所有Preference
类型的iconSpacePreserved
属性设置了默认值;<dimen>
元素为PreferenceCategory
类型设置了默认间距。
编辑:如果您正在使用androidx.preference:preference:1.1.1
,则不需要使用preference_category_padding_start
尺寸。测试可用于Android 6-10。
试试这个:
@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();
来设置内边距。PreferenceFragmentCompat
时,这不再是原因。现在,填充(或仅图标框架)是首选项视图的一部分。 - android developercom.android.support:preference-v7
库,请确保托管偏好设置的活动主题具有设置为v14材料偏好设置主题覆盖的preferenceTheme
:
<item name="preferenceTheme">@style/PreferenceThemeOverlay.v14.Material</item>
PreferenceFragmentCompat
类时是否有类似的解决方案? - android developerPreferenceFragmentCompat
,但是我已经重新设计了我的设置屏幕,并且它包括图标,这使得这种填充对我很有用(它有助于保持左对齐的一致性)。 - mtrewartha <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" />
按照以下方式更改偏好主题。确保使用最新版本的偏好库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>
androidx.preference:preference:1.1.0-alpha01
的关键性错误。在应用程序中任何第二个片段堆栈上的设备旋转都会导致崩溃。希望它能在以后的版本中得到修复。我回退到androidx.preference:preference:1.0.0
。 - Joonsoo这个内边距是由包含你的设置的 PreferenceScreen
中的父 ListView
引起的。如果你正在使用 PreferenceFragment
创建你的偏好设置,只需要进入 PreferenceFragement
的 onActivityCreated
函数,并进行以下操作来移除内边距:
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);
}
PreferenceFragmentCompat
时,这不再是原因。现在填充(或仅图标框架)是首选项视图的一部分。 - android developer编译 '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.重写PreferenceFragmentCompat的onCreateAdapter方法:
@Override
protected Adapter onCreateAdapter(PreferenceScreen preferenceScreen) {
return new CustomAdapter(preferenceScreen);
}
<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"