Android 学习笔记七:使用Fragment创建动态UI

Fragment 是啥

Fragment 翻译过来就是碎片的意思。fragment 和 Activity很像,都有自己的布局,都有自己对应的java类,都有一样的生命周期。

Fragment 应该理解为一个UI片段,是业务逻辑上的一个模块,比如我们有一个注册新用户的Activity,它包含了设置邮箱密码和填写个人资料两步,我们可以把这两部分别做成一个 fragment。在手机上 我们分成两步,要点击下一步才会填写个人资料,在平板上我们可以直接在一个屏幕中显示出来。

Fragment 存在的意义就是把UI按功能抽离出来封装成独立模块,然后在不同的activity中引用这些UI模块。所以如果应用设计合理,Activity中只是拼装fragment,而不会直接在activity中写按钮之类的组件,所有的UI实现都由Fragment来完成。这样可以做到在根据设备大小的不同显示不同的布局,甚至可以让用户自由定制自己的布局。

为不同大小的屏幕创建不同的布局

假设我们要做一个阅读应用,在手机上有两个界面,一个是文章列表,一个是文章内容。在手机上是点击文章列表跳转到文章内容。但是在平板上因为屏幕大,我们希望能左侧显示列表,右侧直接显示文章内容,而不需要切换。

那么这个时候我们需要用 Fragment 来实现。首先我们创建两个Fragment的XML文件,他们和Activity的写法没区别:

fragment_detail.xml:




    


fragment_list.xml:




    


然后我们创建对应的java类,这些JAVA类要继承自 android.app.Fragment,并且重写 onCreateView 方法来指定对应的视图:

FragmentDetail.java:

public class FragmentDetail extends Fragment {
    @Override
    public View onCreateView(LayoutInflater inflater, ViewGroup container,
                             Bundle savedInstanceState) {
        // Inflate the layout for this fragment
        return inflater.inflate(R.layout.fragment_detail, container, false);
    }
}

FragmentList.java

public class FragmentList extends Fragment {
    @Override
    public View onCreateView(LayoutInflater inflater, ViewGroup container,
                             Bundle savedInstanceState) {
        // Inflate the layout for this fragment
        return inflater.inflate(R.layout.fragment_list, container, false);
    }
}

现在我们有了两个Fragment可以用,那么只需要在 activity_main.xml 中引用即可:



    


这是默认的布局,其中只用了 FragmentList ,也就是默认只是显示一个文章列表,点击之后才会显示文章详情。

然后我们再创建 res/layout-large/activity_main.xml ,在平板上左边显示列表,右边显示详情:



    

    


分别在手机上和平板上运行代码,可以看到如下图不同的布局,左边是手机 右边是平板:

动态创建Fragment

上面的用法只是静态引用 Fragment,其实Fragment 真正强大的地方在于它可以动态操作。现在我们实现上面一个没完成的功能:在手机上点击列表跳转到 文章详情。

为了动态替换Fragment,我们首先需要给他指定一个容器,这里我们用一个 FrameLayout 作为容器。修改 activity_main.xml 如下:



    

        

    


然后我们在 fragment_list.xml 中增加一个按钮,然后在 MainActivity.java 中监听按钮的点击事件,并且用 FragmentManager 来动态替换掉当前的fragment:

public class MainActivity extends AppCompatActivity {

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

    public void initialize() {
        Button button = (Button) findViewById(R.id.button);
        button.setOnClickListener(new View.OnClickListener() {
            @Override
            public void onClick(View v) {
                FragmentDetail detail = new FragmentDetail();
                FragmentManager fragmentManager = getFragmentManager();
                FragmentTransaction transaction = fragmentManager.
                        beginTransaction();
                transaction.addToBackStack(null);     //入栈,以便可以通过点击后退按钮返回
                transaction.replace(R.id.frame1, detail);     //替换一下
                transaction.commit();
            }
        });
    }
    @Override
    public void onBackPressed() {
        if (getFragmentManager().getBackStackEntryCount() > 0 ){//当栈中还有fragment的时候,弹出。
            getFragmentManager().popBackStack();
        } else {
            super.onBackPressed();
        }
    }

}

上面代码中,通过 getFragmentManager() 获取一个 fragmentManager 实例,然后通过它提供的 replace 方法就可以动态替换掉一个 Fragment

Fragment 与 Activity 之间通信

Fragment 和 Activity 可以互相拿到对方的实例引用,因此可以互相通信。在Activity 中通过 getSupportFragmentManager().findFragmentById(R.id.article_fragment) 来拿到fragment引用。在 Fragment 中通过覆盖 public void onAttach(Activity activity) 方法就可以拿到 activity 引用,或者直接通过 getActivity() 方法获取。

官方不建议多个fragment之间直接通信,而是通过他们的 Activity 进行通信。也就是说不应该在一个 Fragment 中直接调用 另一个Fragment的方法。

在官方教程中,建议通过接口来实现通信。在 Fragment 中提供一个接口,然后在 Activity 中实现。通过这个接口进行通信,这样在 Fragment 中就不会和 Activity 有耦合。
接口的写法参见这里: http://developer.android.com/training/basics/fragments/communicating.html

你可能感兴趣的:(android入门)