【问题标题】:AppCompatPreferenceActivity strange padding on left and right in Android 4.4AppCompatPreferenceActivity 在 Android 4.4 左右奇怪的填充
【发布时间】:2019-01-06 19:59:33
【问题描述】:

我有一个扩展 AppCompatPreferenceActivity 的 SettingsActivity。

我的 pref_headers.xml 看起来像这样:

<preference-headers xmlns:android="http://schemas.android.com/apk/res/android">
    <header
        android:fragment="com.blabla.activities.fragments.ProfileFragment"
        android:icon="@drawable/ic_users"
        android:title="Profil">
    </header>
</preference-headers>

片段代码如下所示:

@TargetApi(Build.VERSION_CODES.HONEYCOMB)
public class ProfileFragment extends PreferenceFragment {
    @BindView(R.id.email)
    TextView email;
    @BindView(R.id.username)
    TextView username;
    @BindView(R.id.loadingPanel)
    RelativeLayout loadingPanel;

    @Override
    public View onCreateView(LayoutInflater inflater, ViewGroup container, Bundle savedInstanceState) {
        View rootView = inflater.inflate(R.layout.fragment_profile, container, false);
        ButterKnife.bind(this, rootView);

        if (setActionbarListener != null) {
            setActionbarListener.setActionbarTitle("Profil");
        }

        loadingPanel.setVisibility(View.VISIBLE);
        UsernameHandler uHandler = UsernameHandler.getInstance(new UsernameResult() {
            @Override
            public void finished(String uname) {
                username.setText(uname);
                loadingPanel.setVisibility(View.GONE);  // hide loading spinner
            }
        });
        email.setText(MainActivity.getFbUser().getEmail());

        return rootView;
    }
}

我的问题是,我正在加载的布局的左侧和右侧都有一些空间。这种填充绝对不是来自布局本身。在 android 8.1 中启动应用程序时没有这样的填充/边距。

看图:

最后是SettingsActivity的代码:

public class SettingsActivity extends AppCompatPreferenceActivity implements OnSetActionbarTitleListener {

    /**
     * A preference value change listener that updates the preference's summary
     * to reflect its new value.
     */
    private static Preference.OnPreferenceChangeListener sBindPreferenceSummaryToValueListener = new Preference.OnPreferenceChangeListener() {
        @Override
        public boolean onPreferenceChange(Preference preference, Object value) {
            String stringValue = value.toString();

            if (preference instanceof ListPreference) {
                // For list preferences, look up the correct display value in
                // the preference's 'entries' list.
                ListPreference listPreference = (ListPreference) preference;
                int index = listPreference.findIndexOfValue(stringValue);

                // Set the summary to reflect the new value.
                preference.setSummary(
                        index >= 0
                                ? listPreference.getEntries()[index]
                                : null);

            } else if (preference instanceof RingtonePreference) {
                // For ringtone preferences, look up the correct display value
                // using RingtoneManager.
                if (TextUtils.isEmpty(stringValue)) {
                    // Empty values correspond to 'silent' (no ringtone).
                    preference.setSummary(R.string.pref_ringtone_silent);

                } else {
                    Ringtone ringtone = RingtoneManager.getRingtone(
                            preference.getContext(), Uri.parse(stringValue));

                    if (ringtone == null) {
                        // Clear the summary if there was a lookup error.
                        preference.setSummary(null);
                    } else {
                        // Set the summary to reflect the new ringtone display
                        // name.
                        String name = ringtone.getTitle(preference.getContext());
                        preference.setSummary(name);
                    }
                }

            } else {
                // For all other preferences, set the summary to the value's
                // simple string representation.
                preference.setSummary(stringValue);
            }
            return true;
        }
    };

    /**
     * Helper method to determine if the device has an extra-large screen. For
     * example, 10" tablets are extra-large.
     */
    private static boolean isXLargeTablet(Context context) {
        return (context.getResources().getConfiguration().screenLayout
                & Configuration.SCREENLAYOUT_SIZE_MASK) >= Configuration.SCREENLAYOUT_SIZE_XLARGE;
    }

    /**
     * Binds a preference's summary to its value. More specifically, when the
     * preference's value is changed, its summary (line of text below the
     * preference title) is updated to reflect the value. The summary is also
     * immediately updated upon calling this method. The exact display format is
     * dependent on the type of preference.
     *
     * @see #sBindPreferenceSummaryToValueListener
     */
    public static void bindPreferenceSummaryToValue(Preference preference) {
        // Set the listener to watch for value changes.
        preference.setOnPreferenceChangeListener(sBindPreferenceSummaryToValueListener);

        // Trigger the listener immediately with the preference's
        // current value.
        sBindPreferenceSummaryToValueListener.onPreferenceChange(preference,
                PreferenceManager
                        .getDefaultSharedPreferences(preference.getContext())
                        .getString(preference.getKey(), ""));
    }

    @Override
    protected void onCreate(Bundle savedInstanceState) {
        super.onCreate(savedInstanceState);
        setupActionBar();
    }


    /**
     * Set up the {@link android.app.ActionBar}, if the API is available.
     */
    private void setupActionBar() {
        getLayoutInflater().inflate(R.layout.pref_toolbar, (ViewGroup)findViewById(android.R.id.content));
        Toolbar toolbar = findViewById(R.id.toolbar);
        setSupportActionBar(toolbar);

        if (toolbar != null) {
            getSupportActionBar().setDisplayHomeAsUpEnabled(true);
        }

        setActionBarBelowContent();
    }

    private void setActionBarBelowContent() {
        int horizontalMargin = (int) TypedValue.applyDimension(TypedValue.COMPLEX_UNIT_DIP, 2, getResources().getDisplayMetrics());
        int verticalMargin = (int) TypedValue.applyDimension(TypedValue.COMPLEX_UNIT_DIP, 2, getResources().getDisplayMetrics());
        int actionBarHeight = UserInterfaceUtils.getActionBarHeight(MainActivity.context);
        getListView().setPadding(0, actionBarHeight+10, 0, verticalMargin);
    }

    @Override
    public void onHeaderClick(Header header, int position) {
        setActionBarBelowContent();
        super.onHeaderClick(header, position);
    }

    @Override
    public boolean onMenuItemSelected(int featureId, MenuItem item) {
        int id = item.getItemId();
        if (id == android.R.id.home) {
            onBackPressed();
            return true;
        }
        return super.onMenuItemSelected(featureId, item);
    }

    /**
     * {@inheritDoc}
     */
    @Override
    public boolean onIsMultiPane() {
        return isXLargeTablet(this);
    }

    /**
     * {@inheritDoc}
     */
    @Override
    @TargetApi(Build.VERSION_CODES.HONEYCOMB)
    public void onBuildHeaders(List<Header> target) {
        loadHeadersFromResource(R.xml.pref_headers, target);
    }

    /**
     * This method stops fragment injection in malicious applications.
     * Make sure to deny any unknown fragments here.
     */
    @Override
    protected boolean isValidFragment(String fragmentName) {
        return PreferenceFragment.class.getName().equals(fragmentName)
                || SettingsFragment.class.getName().equals(fragmentName)
                || FeedbackFragment.class.getName().equals(fragmentName)
                || ProfileFragment.class.getName().equals(fragmentName)
                || AGBFragment.class.getName().equals(fragmentName)
                || PrivacyFragment.class.getName().equals(fragmentName)
                || FAQFragment.class.getName().equals(fragmentName)
                || LicenseFragment.class.getName().equals(fragmentName);
    }

    @Override
    public void onBackPressed() {
        super.onBackPressed();
        setActionbarTitle("Einstellungen");
    }

    @Override
    public void setActionbarTitle(String title) {
        getSupportActionBar().setTitle(title);
    }
}

编辑 - 添加布局

<RelativeLayout xmlns:android="http://schemas.android.com/apk/res/android"
    xmlns:app="http://schemas.android.com/apk/res-auto"
    android:id="@+id/item_list_item"
    android:layout_width="match_parent"
    android:layout_height="match_parent">

    <android.support.v7.widget.CardView
        android:layout_width="match_parent"
        android:layout_height="wrap_content"
        app:cardUseCompatPadding="true"
        app:cardElevation="4dp"
        app:cardCornerRadius="0dp">

        <LinearLayout
            android:layout_width="match_parent"
            android:layout_height="match_parent"
            android:layout_marginTop="10dp"
            android:padding="15dp"
            android:orientation="vertical">

            <LinearLayout
                android:layout_width="wrap_content"
                android:layout_height="wrap_content"
                android:orientation="horizontal">

                <TextView
                    android:id="@+id/preUsername"
                    android:layout_width="match_parent"
                    android:layout_height="wrap_content"
                    android:text="Dein Benutzername:"
                    android:textAppearance="@style/profileText"
                    android:textStyle="bold"/>

                <TextView
                    android:id="@+id/username"
                    android:layout_width="match_parent"
                    android:layout_height="wrap_content"
                    android:textAppearance="@style/profileText"
                    android:layout_marginLeft="5dp"/>

            </LinearLayout>

            <LinearLayout
                android:layout_width="wrap_content"
                android:layout_height="wrap_content"
                android:orientation="horizontal">

                <TextView
                    android:id="@+id/preEmail"
                    android:layout_width="match_parent"
                    android:layout_height="wrap_content"
                    android:textAppearance="@style/profileText"
                    android:textStyle="bold"
                    android:text="Deine Email:"/>

                <TextView
                    android:id="@+id/email"
                    android:layout_width="match_parent"
                    android:layout_height="wrap_content"
                    android:textAppearance="@style/profileText"
                    android:layout_marginLeft="5dp"/>

            </LinearLayout>

        </LinearLayout>
    </android.support.v7.widget.CardView>

    <RelativeLayout
        android:id="@+id/loadingPanel"
        android:layout_width="match_parent"
        android:layout_height="match_parent"
        android:layout_gravity="center_vertical|center_horizontal"
        android:gravity="center">

        <ProgressBar
            android:id="@+id/progressBar"
            style="@style/MyProgressBarSpinner"
            android:layout_width="wrap_content"
            android:layout_height="wrap_content"
            android:indeterminate="true" />
    </RelativeLayout>

</RelativeLayout>

【问题讨论】:

  • 您也可以发布您的布局吗?
  • @MRah 我将它添加到问题中,但如前所述,我认为它与片段本身的布局无关。
  • 这是来自您的卡片视图布局的卡片兼容性填充
  • @MRah 不,不是。当我使用清晰的相对布局时,我什至得到了填充,其中只有一个文本视图或类似的东西。所以我真的很确定,这与我的片段布局本身无关。
  • 这些事情有时会在不同的 API 级别之间流动。我认为您的问题源于 API 版本之间的布局差异。您能否发布一个简单的演示应用程序来显示此问题以帮助追踪问题?如果你这样做,我想你会得到一个快速的答案。

标签: android android-preferences preferenceactivity


【解决方案1】:

这是根据设计,即您在 KitKat 设备上获得填充的预期行为。来自Official documentation

在棒棒糖之前的平台上,CardView 不会裁剪 圆角卡。相反,它为内容添加了填充,因此 它不会与圆角重叠。您可以禁用此功能 将此字段设置为 false 的行为。

解决方案:

在 XML 布局中:app:cardPreventCornerOverlap="false"

在 Java 中:setPreventCornerOverlap(false);

所以在你的情况下:

<android.support.v7.widget.CardView
    android:layout_width="match_parent"
    android:layout_height="wrap_content"
    app:cardUseCompatPadding="true"
    app:cardElevation="4dp"
    app:cardPreventCornerOverlap="false"
    app:cardCornerRadius="0dp">

希望对你有帮助!

【讨论】:

  • 遗憾的是,这并不能解决我的问题 :( 我什至在不使用 cardview 时也遇到了这个问题。
【解决方案2】:

你说得对,这个填充不是因为CardView

由于prefs 填充,它发生在棒棒糖前:

为了在您的情况下删除此边框,您只需在创建视图后从父视图中删除填充

 @Override
    public void onViewCreated(View view, @Nullable Bundle savedInstanceState) {
        super.onViewCreated(view, savedInstanceState);
        View containerParent = (View)view.getParent();
        containerParent.setPadding(0, 0, 0, 0);
    }

这将删除棒棒糖前的填充

【讨论】:

    【解决方案3】:

    如果您使用的是app:cardUseCompatPadding=true。使用负 layout_margin 来平衡兼容库中不需要的填充。示例如下:

    <android.support.v7.widget.CardView
    
       android:layout_width="match_parent"
       android:layout_margin="-10dp"
       android:layout_height="wrap_content"
       app:cardUseCompatPadding="true"
       app:cardElevation="4dp"
       app:cardCornerRadius="0dp">
    
    // Your other views
    
    </android.support.v7.widget.CardView>
    

    这将删除不需要的空间并在所有操作系统中看起来都相似(未在 Orio 中测试)

    有关cardviewAndroid CardView文档的更多详细信息。并检查这个stackoverflow答案Android layout unwanted padding

    【讨论】:

    • 正如我在 cmets 和其他答案中所述。此问题与 CardView 的任何填充无关。
    【解决方案4】:

    我想我记得我对Preferences 有过这样的问题。我想我用过:

    if(view != null) {
        ListView lv = (ListView) view.findViewById(android.R.id.list);
        lv.setPadding(0, 0, 0, 0);
    }
    

    onCreateView().

    【讨论】:

    • 你的意思是来自SettingsActivity的onCreate?那么视图是从哪里来的呢?我认为这不能解决我的问题,因为您正在尝试更改 Settingsactivity 中初始列表视图的填充。但我已经在我自己的 Fragment 下一层了。
    【解决方案5】:

    在扩展ProfileFragment 时,您是否尝试使用PreferenceFragmentCompat,例如:public class ProfileFragment extends PreferenceFragmentCompat? 看起来PreferenceFragmentdeprecated

    【讨论】:

      猜你喜欢
      • 2018-07-10
      • 2017-08-03
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 2015-02-15
      • 1970-01-01
      • 1970-01-01
      • 2015-03-20
      相关资源
      最近更新 更多