Android如何使用Fragment构建动态界面

来源:互联网 发布:音响频谱软件 编辑:程序博客网 时间:2024/06/14 15:21

在手机应用开发中,经常遇到这样的需求,某一个界面由几个界限明显的模块构成,对其中一个模块的操作(如选中某项)会影响其他模块的显示内容,甚至影响其他模块是否还存在在界面上。如果单纯用activity来实现的话,就需要为这几个模块的各种排列的组成分别定义Acitivity,来满足某条件下界面的需求,十分不方便。此时,Fragment应运而生,它就像是一个mini的Activity,有自己的界面布局,有自己的生命周期,可以由多个Fragment构成一个Activity,并且可以在程序运行时,任意动态的增加,删除Fragment或更新其上显示的内容。多么的方便,有了Fragment的帮助,使我们能更加方便的开发出响应灵活,动态性高的界面。下面就来看看,如何使用Fragment神器吧~

举例说明:

现在我们要开发一个简单的示例,主界面上包含一个List导航,两个item,ArticleOne, ArticleTwo.点击item1,界面显示Article1的内容,点击item2,界面显示Article2的内容。

1. 定义一个MainActivity作为一切界面的载体。Layout中只有一个FrameLayout作为container,其android:id="@+id/fragment_container"。

2. 定义一个ListFragment用来显示导航List。

public class HeadlinesFragment extends ListFragment{ ... }

用ArticleOne, ArticleTwo.两个字符串来inflate ListFragment。ListFragment内置了一个ListView(mList)并提供setListAdapter方法为其填充数据。具体见源码,在此不赘述。

在MainActivity的onCreate方法中,实例化ListFragment,并通过如下代码将fragment add到container(@+id/fragment_container)中。

 // Create an instance of ExampleFragment            HeadlinesFragment firstFragment = new HeadlinesFragment();            // In case this activity was started with special instructions from an Intent,            // pass the Intent's extras to the fragment as arguments            firstFragment.setArguments(getIntent().getExtras());            // Add the fragment to the 'fragment_container' FrameLayout            getSupportFragmentManager().beginTransaction()                    .add(R.id.fragment_container, firstFragment).commit();

则启动该acitivity后,会显示ListFragment的布局及内容。

3. 定义一个ArticleFragment用来显示article的内容。

public class ArticleFragment extends Fragment {
ArticleFragment的布局只需要一个简单的TextView显示文本内容。ArticleFragment中需要一个updateArticleView方法,根据当前用户选择的导航中哪个item来决定将自己的文本更新成什么(自己的界面自己负责更新是一个好的代码结构)。还需要一个成员变量mCurrentPosition来保存当前用户选择的item的位置,哪个组件会知道用户的选择呢?肯定是ListFragment所在的组件,也就是container,container位于MainActivity中,自然Article的生杀大权也在它的手中,这是后话了。position的值会由负责实例化ArticleFragment的组件在new AriticleFragment时由setArgument方法传入。在AriticleFragment的onStart方法中根据position的值来updateArticleView。为什么选在onStart方法中?应为它在onCreate方法之后由系统自动调用,此时Fragment的布局都已经创建好了,可以放心的update view中的内容了,详见后面生命周期一节。

4. 为ListFragment注册onClick事件,实现切换Fragment的效果。

一个Acitivity和两个布局不同的Fragment都创建好了,现在该为他们编写各种交互行为了。

首先,Acitivity中的FrameLayout做为各Fragment的container,会在MainAcitivity的onCreate方法中首先被实例化。由于它只是一个container没有实际供显示的内容,所以我们要考虑,activity启动时中默认要显示什么内容?当然是导航List了,所以在container创建好后 ,立刻通过FragmentManager将ListFragment add到container中(代码见条目2)。

然后,要为ListFragment中的item注册点击事件了,由于点击事件的响应行为是改变Fragment,所以一定要将事件的响应代码写在activity里,应为只有它才应该对container负责,对各个fragment负责(这是个好的代码结构)。现在出现了一个小问题,导航上的item是属于ListView的,所以我们的目的是调用listView.setOnClickListener(xxx).而ListView是属于ListFragment的,我们如何在MainActivity中为ListView添加监听呢?可能有的看官会脱口而出,在MainActivity中调用ListFragment的getListView拿到listView,再对其setOnClickListener呗。的确,可以这样做,但是这样就会将ListFragment的实现过多的暴露给MainActivity,别忘了我们用的HeadLinesFragment只是我们继承自ListFragment的一个子类,回头我们一高兴,不继承自ListFragment了,继承自一个更牛X的类,难道还要去修改MainAcitivity中对ListFragment的使用么?耦合度太高了,显然不太好,我们要时刻记得,类的职责要分清楚,不是你的事儿就不要非在自己这儿实现,虽然这样有时候实现起来会更简便,但会导致你的代码越来越乱,最终难以维护。那现在应该怎样在MainActivity中实现对ListView的监听比较好呢?ListFragment提供了一个onListItemClick()方法供子类实现,setOnClickListener的重复性工作已经在ListFragment中做好了不用操心。我们只需将希望onClick时发生的行为写在这个Override的方法里即可。但是MainActivity中才拥有关于这些行为的代码,总不能为了重写这个方法让MainActivity也继承ListFragment吧!?当然不要了~这时就用到了接口回调(曾经让我不明觉厉很久的词汇啊!)。也就是说在HeadlinesFragment中定义一个接口,并在这个override自父类的onListItemClick()方法中调用这个接口的onArticleSelected()方法(当然这个方法也是自定义的,看名字,这是根据当前的业务行为定义的,如何调用?使用成员变量)。而这个接口方法的真正实现交由MainActivity来实现,ok,done!一切就是这么自然的发生了,神奇的接口回调,其实更像是一个方法类型的参数的传递。因为Java中不能传递方法,那么当我们想要将实现在某类中的方法传递给另一个类,在某个特定的时机去执行时该怎么办呢?只需要让这个方法属于某一个接口,再在目标类中包含一个这个接口类型的成员变量,在你需要的地方使用该成员变量调用这个方法即可。

public class MainActivity extends FragmentActivity         implements HeadlinesFragment.OnHeadlineSelectedListener {

最后贴上这个重要的接口方法onArticleSelected()的实现。关键是FragmentTransaction的使用。

// Create fragment and give it an argument for the selected article            ArticleFragment newFragment = new ArticleFragment();            Bundle args = new Bundle();            args.putInt(ArticleFragment.ARG_POSITION, position);            newFragment.setArguments(args);            FragmentTransaction transaction = getSupportFragmentManager().beginTransaction();            // Replace whatever is in the fragment_container view with this fragment,            // and add the transaction to the back stack so the user can navigate back            transaction.replace(R.id.fragment_container, newFragment);            transaction.addToBackStack(null);            // Commit the transaction            transaction.commit();

OK~ 

注:代码来自Android官网,下载地址:http://developer.android.com/shareables/training/FragmentBasics.zip (需翻墙,不能的网友可留邮箱我转给你)

代码中实现了根据屏幕的大小自动决定Acitivity上显示几个Fragment。有兴趣的请自行研读。提示:只是定义了两个不同的container的layout,一个放在layout下,一个放在layout-large下,其他自动适配的行为,android系统自动搞定!





0 0
原创粉丝点击