在布局文件中使用Fragment的步骤

为了在Activity布局文件中使用Fragment我们需要四个步骤。

1.定义一个Activity,他继承android.support.v4.app.FragmentActivity,下面是关键代码

import android.support.v4.app.FragmentActivity;

public class MainActivity extends FragmentActivity {

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

2.定义Activity的布局文件activity_main.xml,注意fragment是小写的,且name属性的值必须是完全限定包名

 <LinearLayout xmlns:android="http://schemas.android.com/apk/res/android"
android:layout_width="fill_parent"
android:layout_height="fill_parent"
android:orientation="vertical" > <fragment
android:name="com.example.v4fragmenttest.MyFragment"
android:id="@+id/myfragmentid"
android:layout_width="400px"
android:layout_height="500px"
android:layout_gravity="center"
/> </LinearLayout>

3.自定义一个Fragment,他继承android.support.v4.app.Fragment,关键代码如下

import android.support.v4.app.Fragment;

public class MyFragment extends Fragment {

	@Override
@Nullable
public View onCreateView(LayoutInflater inflater,
@Nullable ViewGroup container, @Nullable Bundle savedInstanceState) {
//System.out.println("Fragment onCreateView");
//System.out.println(container == null);
return inflater.inflate(R.layout.fragment, container, false);
} }

4.定义Fragment对应的布局文件fragment.xml(名字任意),fragment.xml和普通的布局文件是完全一样的

 <TextView xmlns:android="http://schemas.android.com/apk/res/android"
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:layout_gravity="center"
android:text="这是Fragment的TextView,他是水平居中的" />

完整的源码下载:点我下载


可以发现在布局文件中使用自定义view和和fragment是有些类似的,但是有些区别

1.自定义view在布局文件中定义是<com.xxnote.myview />,Fragment则是<fragment  android:name="com.example.v4fragmenttest.MyFragment" />的形式

2.自定义view要继承view,而自定义Fragment需要继承android.support.v4.app.Fragment

同时也可以发现,自定义的Fragment本质就是一个继承了android.support.v4.app.Fragment的类,在他的onCreateView里面返回一个View,这个View会替换掉Activity布局文件里面的fragment标签

另外SDK文档中有这么一句话

Note: Each fragment requires a unique identifier that the system can use to restore the fragment if the activity is restarted (and which you can use to capture the fragment to perform transactions, such as remove it). There are three ways to provide an ID for a fragment:

  • Supply the android:id attribute with a unique ID.
  • Supply the android:tag attribute with a unique string.
  • If you provide neither of the previous two, the system uses the ID of the container view.

可见每一个Fragment都需要一个unique identifier,有三种方式可以为他提供unique identifier,

第一种是使用Fragment的android:id属性作为unique identifier,如下:

 <fragment
android:name="com.example.v4fragmenttest.MyFragment"
android:id="@+id/myfragmentid"
android:layout_width="400px"
android:layout_height="500px"
android:layout_gravity="center"
/>

第二种是使用Fragment的android:tag属性作为unique identifier

<fragment
android:name="com.example.v4fragmenttest.MyFragment"
android:tag="myfragmenttag"
android:layout_width="400px"
android:layout_height="500px"
android:layout_gravity="center"
/>

第三种是如果上面两种都没提供,系统会使用父容器的id作为unique identifier,如下

 <LinearLayout xmlns:android="http://schemas.android.com/apk/res/android"
android:id="@+id/myactivitylayout"
android:layout_width="fill_parent"
android:layout_height="fill_parent"
android:orientation="vertical" > <fragment
android:name="com.example.v4fragmenttest.MyFragment"
android:layout_width="wrap_content"
android:layout_height="wrap_content"
/> </LinearLayout>

上面的Fragment的unique identifier就是父容器的id,可以使用getSupportFragmentManager().findFragmentById(R.id.layoutfragment)来获取这个Fragment。

但是试了下发现上面三种方式都没提供的话也没什么影响,这个应该是用代码添加Fragment的时候才会用到,在布局文件中使用Fragment没啥用,以后再好好研究下

下午研究了下,终于搞清楚unique identifier了,unique identifier的作用就是用来传给FragmentManager的findFragmentByTag或者findFragmentById这两个方法的,这两个方法根据唯一的unique identifier来确定到底是要查找那个Fragment,那么问题来了,如果这些Fragment的unique identifier相同会出现什么情况呢?这时通过这个unique identifier查找到的Fragment是用这个unique identifier设置的最后一个Fragment,即使这个Fragment被remove了,再用这个unique identifier来查找Fragment也无法查找到其他的Fragment,只会返回null。

什么情况下会出现unique identifier相同的情形呢?一种情况是同一个布局中有多个使用父容器的id作为unique identifier的Fragment,即上面的为Fragment分配unique identifier的第三种方式,第二种情况就是通过代码添加Fragment,如下:

 fragmentTransaction.add(R.id.myactivitylayout, new MyFragment(), "000");

第三种情况就是第一种和第二种情况的结合了。

通过代码添加Fragment的时候第一个参数必须是父容器的id,即上面的R.id.myactivitylayout,所以这些添加的Fragment都会有相同的unique identifier,因此我们会无法查找所有的Fragment,这时第三个参数派上了用场, fragmentTransaction.add(R.id.myactivitylayout, new MyFragment(), "000"); 这句里面的第三个参数"000"也会作为Fragment的unique identifier,查找的时候使用FragmentManage的findFragmentByTag方法就可以了。因此最好不要使用FragmentManager的findFragmentById方法来查找Fragment,而是使用FragmentManage的findFragmentByTag方法来查找Fragment。

还有一些要注意的地方就是在布局xml里面的fragment是无法删除和replace的;对于一个fragmentTransaction只能调用一次commit()方法,再进行add、remove、replace后必须commit才生效,如果一个fragmentTransaction已经commit过一次了,那么再要进行add、remove、replace的时候就调用getSupportFragmentManager().beginTransaction()方法重新获得一个fragmentTransaction,然后使用这个fragmentTransaction来add、remove、replace我们的Fragment,最后了commit一下就生效了;commit是异步的,因此当我们commit之后立刻查找Fragment很可能会返回null。

上一篇:Android 自定义View及其在布局文件中的使用示例


下一篇:c# 正则表达式用法