杨子刚的博客


Android Fragment

2013-12-01

Fragment的自定义属性

我们可以在layout中来定义一个fragment,系统会自动的去加载layout文件中指定的fragment类,这个功能实在非常的方便。目前我们再深入一步:如果我们想通过layout文件,来为fragment设置一些自定义参数怎么办呢?比如说women想在layout文件中,指定这个fragment应该加载哪个布局文件。下面我们来仔细看一下怎么来实现这个功能。

首先我们需要创建res/values/attrs.xml文件,文件内容如下:

<?xml version="1.0" encoding="utf-8"?>
<resources>
    <declare-styleable name="FragmentOne">          
        <attr name="extraInformation" format="string" />
        <attr name="fraction" format="fraction" />
    </declare-styleable>
</resources>

在这个文件中,我们为类FragmentOne设置了两个自定义属性,属性的类型分别为string、fraction。

Activity的布局文件-activity_hello_fragment.xml:

 1 <LinearLayout xmlns:android="http://schemas.android.com/apk/res/android"
 2     xmlns:tools="http://schemas.android.com/tools"
 3     xmlns:app="http://schemas.android.com/apk/res-auto"
 4     android:layout_width="match_parent"
 5     android:layout_height="match_parent"
 6     android:orientation="horizontal"
 7     android:baselineAligned="false" >
 8 
 9     <fragment
10         android:id="@+id/fragmentOne"
11         android:name="com.ingphone.hellofragment.FragmentOne"
12         android:layout_width="0dp"
13         android:layout_height="match_parent"
14         android:layout_weight="1"
15         app:extraInformation="custom attr ok"
16         app:fraction="100%"
17         tools:ignore="MissingPrefix" />
18 
19     <fragment
20         android:id="@+id/fragmentTwo"
21         android:name="com.ingphone.hellofragment.FragmentTwo"
22         android:layout_width="0dp"
23         android:layout_height="match_parent"
24         android:layout_weight="1" />
25 
26 </LinearLayout>

第3行指定了一个命名空间:app,内容是http://schemas.android.com/apk/res-auto;看到网上有人说可以写成http://schemas.android.com/apk/ + package name的形式,我试了试,不成功。

15、16行为我们的自定义属性设置值。

17行为让Lint忽略15、16行引起的错误,在eclipse下面,15、16行会报错,无法编译,但是其实是可以编译的,如果不加17行,也可以在修改完这个布局文件后,clean project,也不会有错误。

最后一步就是在fragment的类中,读取这些属性-FragmentOne.java:

package com.ingphone.hellofragment;

import com.example.hellofragment.R;

import android.app.Activity;
import android.content.res.TypedArray;
import android.os.Bundle;
import android.support.v4.app.Fragment;
import android.util.AttributeSet;
import android.util.Log;
import android.view.LayoutInflater;
import android.view.View;
import android.view.ViewGroup;

public class FragmentOne extends Fragment {
    @Override
    public View onCreateView(LayoutInflater inflater, ViewGroup container,
            Bundle savedInstance) {
        return inflater.inflate(R.layout.activity_fragment_two, container,
                false);
    }

    @Override
    public void onInflate(Activity activity, AttributeSet attrs,
            Bundle savedInstanceState) {
        super.onInflate(activity, attrs, savedInstanceState);
        Log.v("HelloFragmentArguments", "onInflate called");

        TypedArray a = activity.obtainStyledAttributes(attrs,
                R.styleable.FragmentOne);

        CharSequence myString = a
                .getText(R.styleable.FragmentOne_extraInformation);
        if (myString != null) {
            Log.e("HelloFragmentArguments",
                    "My String Received : " + myString.toString());
        }
        
        float mFraction = a.getFraction(R.styleable.FragmentOne_fraction, 1, 1, 0);
        Log.e("HelloFragmentArguments", "fraction is " + mFraction);

        a.recycle();
    }

}

只要实现onInflate这个函数就OK了。

完整的项目代码请见HelloFragmentArguments