首页 > 代码库 > 在PreferenceAcitity中使用Fragement时避免额外的Left和RightPadding

在PreferenceAcitity中使用Fragement时避免额外的Left和RightPadding

On Android 4.4

遇到过这样的问题:

注意到,上面的ActionBar部分的左右各有48像素的padding。

 

要了解该问题的成因,要首先了解其结构:

  1. 该页面的Activity是一个PreferenceActivity,是个三级页面,是通过上一个PreferenceActivity调用startWithFragment启动的;
  2. 该页面的内容是放置了一个Fragment,该Fragment,实现了自己的ActionBar (ActionBar是来自Fragment而不是Acitivity)

我们通过hierarchyviewer看一下它的界面构成:

 

截图中的PreferenceFrameLayout就是这个关键类。

PreferenceAcitivity的布局文件是 frameworks/base/core/res/res/layout/preference_list_fragment.xml

但是,PreferenceFrameLayout类的风格却是由android内部的一个风格控制的:(frameworks/base/core/res/res/values/styles.xml)

<stylename="Widget.Holo.PreferenceFrameLayout">                                                                                                                                                        
    <itemname="android:borderTop">0dip</item>
    <itemname="android:borderBottom">@dimen/preference_fragment_padding_bottom</item>
    <itemname="android:borderLeft">?attr/preferenceFragmentPaddingSide</item>
    <itemname="android:borderRight">?attr/preferenceFragmentPaddingSide</item>
</style>

preferenceFragmentPaddingSide的值在不同平台值不同,在这里定义为16dip (16*3 = 48)

他通过默认风格引用的(frameworks/base/core/res/res/values/themes.xml)

<itemname="preferenceFrameLayoutStyle">@android:style/Widget.PreferenceFrameLayout</item>
这样,在默认情况下,PreferenceActivity都会带有边框Padding。

 

但是PreferenceFrameLayout还有一个特殊属性:layout_removeBorders。这个属性为true时,表示忽略padding。他对应的是PreferenceFrameLayout.LayoutParams.removeBorders 这个变量。

PreferenceFragment这个和PreferenceActivity匹配的Fragment,就具有该属性:(frameworks/base/core/res/res/layout/preference_list_fragment.xml)

<LinearLayoutxmlns:android="http://schemas.android.com/apk/res/android"
    android:orientation="vertical"
    android:layout_height="match_parent"
    android:layout_width="match_parent"
    android:background="@android:color/transparent"
    android:layout_removeBorders="true">
.....


因此,PreferenceFragment放到PreferenceActivity的时候,这个边框就没有了

不幸的时,以上所有的layout属性都是Private的,无法更改,因此,当我们的Fragment不是PreferenceFragment或者它的派生类的时候,就不能消除边框了。

 

不过,我们还有其他的解决方法,万幸的是PreferenceFrameLayout和PreferenceFrameLayout.LayoutParams都是Public的。因此,我们可以直接代码修改:

@Override
public View onInflateView(LayoutInflater inflater, ViewGroup container,
    Bundle savedInstanceState) {
    View view = inflater.inflate(
        ....., container,false);
    if(container != null) {
        ViewGroup prefView = (ViewGroup)container.getParent();
        ViewGroup.LayoutParams layoutParams = (ViewGroup.LayoutParams)prefView.getLayoutParams();
        if(layoutParams instanceofPreferenceFrameLayout.LayoutParams) {
            ((PreferenceFrameLayout.LayoutParams)layoutParams).removeBorders =true;
        }
    }
    returnview;
}


在Fragment的onInflateView函数中强制修改removeBorders就可以达到这样的目的。

当然,需要正确找到PreferenceFrameLayout的第一个子View,修改该子View的LayoutParams才能生效,这需要根据不同的情况来分别对待。