我在设计首选项屏幕时遇到了非常奇怪的问题。虽然我没有在布局上给出任何空白,但它在左边留下了一些空间。
如下图所示:
XML:
<PreferenceScreen android:title="demo" >
<CheckBoxPreference
android:defaultValue="false"
android:key="prefSync"`
android:title="Auto Sync" />
</PreferenceScreen>
在屏幕中添加复选框首选项是不是做错了什么?
发布于 2018-11-21 05:52:50
更新androidx的这个。
经过大量的实验,我解决了这个问题,我将这个添加到每个具有多余缩进的首选项中:
app:iconSpaceReserved="false"
当然,您还需要将此代码添加到PreferenceScreen声明本身的xml顶部:
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"
该问题可追溯到自定义preference类中第三个构造函数参数的使用。如果传递第三个参数,则列表项将缩进。如果省略它,列表将正确对齐:
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
}
}
这归功于这个非常老的post中的@CommonsWare。
发布于 2018-07-28 14:40:31
我已经报告了这个问题 (你也可以在那里查看我的变通项目),但现在,我已经找到了一些老生常谈的,但很容易克服这个问题的方法:
对于
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示例,我已经创建了来检查它):
这段代码有点危险,所以请确保每次更新库时,都要检查它是否工作正常。
此外,在某些特殊情况下,它可能不能很好地工作,例如,当您为首选项定义自己的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);
}
}
}
编辑:在谷歌最终修改库(链接)后,你可以为每个首选项设置标志,或者使用这个解决方案为你做所有的事情:
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)
}
}
}
只要从它扩展,你就不会有无用的填充你的喜好。示例项目,在那里我也要求有一个官方的方法来避免它,而不是那些技巧。请考虑出演它。
发布于 2018-12-29 19:15:14
来自here的简单的工作解决方案。
无需写入所有首选项,即可在所有首选项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
,你就不需要dimen preference_category_padding_start
了。在Android 6-10上进行了测试。
https://stackoverflow.com/questions/18509369
复制相似问题