在Android中调整“PreferenceScreen”中的边距/填充。

5
我希望调整Android中“PreferenceScreen”的默认边距/填充值,我知道不能仅在XML代码(布局文件)中设置它,但Android肯定从某处获取这些值,而且很可能(我希望)我可以设置一些“样式属性”来实现它。
我想要调整的值是:

enter image description here

我在网上找到了这个答案: Android:如何最大化PreferenceFragment的宽度(或去除边距)? 但是我认为它使用了一个非常糟糕的解决方法,我想尝试操纵一些官方参数。
有人知道我如何通过调整样式或其他字段来实现吗?

你是否正在使用偏好设置支持包 - Cheticamp
实现 'com.android.support:preference-v7:27.1.1' - Rafael Lima
更新了我的回答。 - Cheticamp
1个回答

4

很不幸,我认为你不可能找到比你已经在Android: How to maximize PreferenceFragment width (or get rid of margin)?中发现的答案更好了。我会解释原因,并给你提供一个备选方案,尽管你可能会认为这个方案比你参考答案中提出的更糟糕。

我们将识别每个项目下面的布局,这些是我们将使用的首选项库依赖项:

implementation 'com.android.support:preference-v7:27.1.1'
implementation 'com.android.support:preference-v14:27.1.1'

主题的preferenceTheme属性定义了首选项的外观。
<style name="AppTheme" parent="Theme.AppCompat.Light.DarkActionBar">
    ...
    <!-- Theme for the preferences -->
    <item name="preferenceTheme">@style/PreferenceThemeOverlay.v14.Material</item>
</style>

PreferenceThemeOverlay.v14.Material向上遍历父级链(ctrl-B),我们可以看到
<style name="PreferenceThemeOverlay.v14.Material">
...
<item name="preferenceStyle">@style/Preference.Material</item>
...
</style>    

Preference.Material的定义如下:

<style name="Preference.Material">
    <item name="android:layout">@layout/preference_material</item>
</style>    

偏好设置的布局是 preference_material.xml。以下是源代码
该布局的以下部分引起了我们的兴趣:
...
<RelativeLayout
    android:layout_width="wrap_content"
    android:layout_height="wrap_content"
    android:layout_weight="1"
    android:paddingTop="16dp"
    android:paddingBottom="16dp">
    <TextView android:id="@+id/title"
        android:layout_width="wrap_content"
        android:layout_height="wrap_content"
        android:singleLine="true"
        android:textAppearance="?attr/textAppearanceListItem"
        android:ellipsize="marquee" />
    <TextView android:id="@+id/summary"
        android:layout_width="wrap_content"
        android:layout_height="wrap_content"
        android:layout_below="@id/title"
        android:layout_alignStart="@id/title"
        android:textAppearance="?attr/textAppearanceListItemSecondary"
        android:textColor="?attr/textColorSecondary"
        android:maxLines="10"
        android:ellipsize="end" />
</RelativeLayout>
...

如您所见,RelativeLayout 的顶部和底部填充是硬编码的。由于没有使用样式属性,因此无法覆盖填充。由于这种硬编码,您有两个选择:
  1. 使用您找到的答案中概述的"真正糟糕的解决方法",它涉及使用Java代码修改填充,或者

  2. 通过在首选项的XML中定义 android:layout="@layout/custom_preference" 来使用自己的布局。您可以复制 Android 布局并进行修改。

每种方法都有缺点,请选择您认为最能处理的方法。
以下是演示替换首选项布局的小应用程序的关键组件。 MainActivity.java
这个活动为方便起见滚动首选项片段。
public class MainActivity extends AppCompatActivity {

    @Override
    protected void onCreate(Bundle savedInstanceState) {
        super.onCreate(savedInstanceState);
        setContentView(R.layout.activity_main);

        if (savedInstanceState == null) {
            Fragment preferenceFragment = new PrefsFragment();
            FragmentTransaction ft = getSupportFragmentManager().beginTransaction();
            ft.add(R.id.prefContainer, preferenceFragment);
            ft.commit();
        }
    }

    public static class PrefsFragment extends PreferenceFragmentCompat {

        @Override
        public void onCreatePreferences(Bundle bundle, String s) {
            addPreferencesFromResource(R.xml.app_preferences);
        }
    }
}

app_preference.xml

<?xml version="1.0" encoding="utf-8"?>
<android.support.v7.preference.PreferenceScreen xmlns:android="http://schemas.android.com/apk/res/android">
    <android.support.v7.preference.Preference
        android:key="preference"
        android:layout="@layout/custom_pref_layout"
        android:summary="Doesn't really do anything."
        android:title="Preference Title" />

    <android.support.v7.preference.EditTextPreference
        android:defaultValue="Default EditTextPreference value"
        android:dialogMessage="EditTextPreference Dialog Message"
        android:inputType="number"
        android:key="editTextPreference"
        android:layout="@layout/custom_pref_layout"
        android:summary="EditTextPreference Summary"
        android:title="EditTextPreference Title" />

    <android.support.v7.preference.SwitchPreferenceCompat
        android:defaultValue="true"
        android:key="switchPreference"
        android:layout="@layout/custom_pref_layout"
        android:summary="SwitchPreference Summary"
        android:title="SwitchPreference Title" />

    <android.support.v7.preference.CheckBoxPreference
        android:defaultValue="true"
        android:key="checkBoxPreference"
        android:layout="@layout/custom_pref_layout"
        android:summary="CheckBoxPreference Summary"
        android:title="CheckBoxPreference Title" />

    <android.support.v7.preference.ListPreference
        android:defaultValue="180"
        android:entries="@array/pref_sync_frequency_titles"
        android:entryValues="@array/pref_sync_frequency_values"
        android:key="list_preference"
        android:layout="@layout/custom_pref_layout"
        android:negativeButtonText="@null"
        android:positiveButtonText="@null"
        android:title="List Preference Title" />

</android.support.v7.preference.PreferenceScreen>

activity_main.xml
简单定义了首选项片段的主页面。

<?xml version="1.0" encoding="utf-8"?>
<FrameLayout xmlns:android="http://schemas.android.com/apk/res/android"
    xmlns:tools="http://schemas.android.com/tools"
    android:id="@+id/prefContainer"
    android:layout_width="match_parent"
    android:layout_height="match_parent"
    tools:context="com.example.preferencecustomlayout.MainActivity" />

custom_pref_layout.xml
已进行一些修改以适应该文件的使用,主要更新了?attr/somthing?android:attr/something

<?xml version="1.0" encoding="utf-8"?>
<!-- Copyright (C) 2014 The Android Open Source Project
     Licensed under the Apache License, Version 2.0 (the "License");
     you may not use this file except in compliance with the License.
     You may obtain a copy of the License at
          http://www.apache.org/licenses/LICENSE-2.0
     Unless required by applicable law or agreed to in writing, software
     distributed under the License is distributed on an "AS IS" BASIS,
     WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
     See the License for the specific language governing permissions and
     limitations under the License.
-->
<!-- Layout for a Preference in a PreferenceActivity. The
     Preference is able to place a specific widget for its particular
     type in the "widget_frame" layout. -->

<!-- Modified from the original to accommodate usage as a local layout file. -->
<LinearLayout xmlns:android="http://schemas.android.com/apk/res/android"
    android:layout_width="match_parent"
    android:layout_height="wrap_content"
    android:background="?android:attr/activatedBackgroundIndicator"
    android:clipToPadding="false"
    android:gravity="center_vertical"
    android:minHeight="?attr/listPreferredItemHeightSmall"
    android:paddingEnd="?android:attr/listPreferredItemPaddingEnd"
    android:paddingStart="?android:attr/listPreferredItemPaddingStart">

    <LinearLayout
        android:id="@+id/icon_frame"
        android:layout_width="wrap_content"
        android:layout_height="wrap_content"
        android:layout_marginStart="-4dp"
        android:gravity="start|center_vertical"
        android:minWidth="60dp"
        android:orientation="horizontal"
        android:paddingBottom="4dp"
        android:paddingEnd="12dp"
        android:paddingTop="4dp">

        <com.android.internal.widget.PreferenceImageView
            android:id="@+id/icon"
            android:layout_width="wrap_content"
            android:layout_height="wrap_content"
            android:maxHeight="48dp"
            android:maxWidth="48dp" />
    </LinearLayout>

    <RelativeLayout
        android:layout_width="wrap_content"
        android:layout_height="wrap_content"
        android:layout_weight="1"
        android:paddingBottom="16dp"
        android:paddingTop="16dp">

        <TextView
            android:id="@android:id/title"
            android:layout_width="wrap_content"
            android:layout_height="wrap_content"
            android:ellipsize="marquee"
            android:singleLine="true"
            android:textAppearance="?attr/textAppearanceListItem" />

        <TextView
            android:id="@android:id/summary"
            android:layout_width="wrap_content"
            android:layout_height="wrap_content"
            android:layout_alignStart="@android:id/title"
            android:layout_below="@android:id/title"
            android:ellipsize="end"
            android:maxLines="10"
            android:textAppearance="?attr/textAppearanceListItemSecondary"
            android:textColor="?android:attr/textColorSecondary" />
    </RelativeLayout>
    <!-- Preference should place its actual preference widget here. -->
    <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"
        android:paddingStart="16dp" />
</LinearLayout>

Gradle文件
apply plugin: 'com.android.application'

android {
    compileSdkVersion 27
    buildToolsVersion '27.0.3'

    defaultConfig {
        applicationId "com.example.preferencecustomlayout"
        minSdkVersion 18
        targetSdkVersion 27
        versionCode 1
        versionName "1.0"
    }
    buildTypes {
        release {
            minifyEnabled false
            proguardFiles getDefaultProguardFile('proguard-android.txt'), 'proguard-rules.pro'
        }
    }
}

dependencies {
    implementation fileTree(dir: 'libs', include: ['*.jar'])
    testImplementation 'junit:junit:4.12'
    implementation 'com.android.support:appcompat-v7:27.1.1'
    implementation 'com.android.support:preference-v7:27.1.1'
    implementation 'com.android.support:preference-v14:27.1.1'
}

我尝试了第二个选项:从那个链接复制文件,然后在我的 settings.xml 文件中编辑 <PreferenceScreen xmlns:android="http://schemas.android.com/apk/res/android" android:layout="@layout/preferenes_layout">... 但是在 preferences_layout 上的更改在运行时不会反映在首选项屏幕上。 - Rafael Lima
@RafaelLima 你改变了preference_layout中的padding值吗?如果是的话,但没有看到更改,请在此处发布您的settings.xml - Cheticamp
我肯定我做了...但是在运行时没有任何更改生效...这个布局属性在 settings.xml 上应该如何工作呢?我的意思是,我可以在那里放置任何非线性布局,Android 如何猜测生成的 PreferenceScreen 的每个组件放置在哪里?是基于ID吗?无论如何,我没有更改ID或结构。我只是更改了边距和填充的参数,但没有应用任何更改。 - Rafael Lima
@RafaelLima 这是基于ID的,所以它不能是任何旧的布局。我的分析是基于开关偏好设置的。如果您使用的是其他内容,则可能需要更改此方法。发布您的 settings.xml,以便我们查看您正在执行的操作。您可以将更新后的布局应用于开关偏好设置,以查看其工作原理。 - Cheticamp
1
它奏效了,可能第一次尝试失败是因为我只在settings.xml的根部设置了android:layout="@layout/custom_preference",现在通过您的示例,我已经知道需要为每个项目设置它。 - Rafael Lima
这很完美。唯一的小问题是,在custom_pref_layout.xml中,您应该使用android:id="@android:id/icon"而不是@+id/icon。后者会添加一个新的ID,而偏好设置系统无法设置图标。 - zilp

网页内容由stack overflow 提供, 点击上面的
可以查看英文原文,
原文链接