[Android] 使用Fragment创建动态UI
来源:互联网 发布:爱思助手mac版 编辑:程序博客网 时间:2024/05/13 03:00
使用Fragment创建动态UI
要在Android上面创建一个动态的、多面板的UI,你需要将这些UI组件和activity的行为封装成模块(modules),这样就可以在你的activity中进行交互。你可以使用Fragment类来创建这些模块,这个类的行为有点像是嵌套的activity,可以定义自己的布局(layout)以及管理它自己的生命周期。
当一个fragment指定了它的布局,它就可以和其他的fragment组成不同的组合放在activity里,当运行在屏幕尺寸不同的device上时可以修改布局配置(一个小屏幕可能同时只能显示一个fragment,而一个大屏幕可能可以显示两个或更多)。
这节课来介绍的是使用fragment创建动态的UI并提升你的app在不同尺寸的设备上的用户体验,所有内容都继续支持那些还运行在Android 1.6上点设备。
创建一个Fragment
你可以把Fragment想成是activity的一个模块化的部分,有它自己的生命周期,可以接收输入事件,并且在activity运行的时候也可以进行添加或移除的动作(有点像是“子activity”的感觉,可以在不同的activity中重复使用)。这节课介绍的是怎样使用Support Library继承(extend)fragment,这样你的app就算是在运行着Android 1.6的设备上也可以保持兼容。
注:如果你决定自己app的最小API level是11或者是更高的话,那么就不用再使用Support Library,取而代之地可以使用framework内建的Fragment类以及相关的API。请注意,这节课重点关注的是Support Library里的API,使用的是特定的包签名(package signature),可能和导入在platform中的版本在API名字上略有差异。
在开始这节课之前,你需要使用Support Library创建你的Android Project。如果你之前没有使用过Support Library,那就跟着Support Library Setup这篇文档(需要翻墙)使用v4 library建立你的project。你也可以使用v7 appcompat library在你的activity中引入app bar,这个库与Android 2.1(API level 7)兼容,并且也包含了Fragment API。
创建一个Fragment类
要创建一个fragment,先继承Fragment类,然后重写(override)关键的生命周期方法来插入你自己的代码逻辑,这和使用Activity类的方法很相似。
一个重要的区别是,在创建fragment时,你必须使用onCreateView() callback来定义布局。事实上,要让你的fragment运行起来,这个是你唯一需要的callback。举个例子,下面是一个简单的fragment,指明了它自己的布局:
import android.os.Bundle;import android.support.v4.app.Fragment;import android.view.LayoutInflater;import android.view.ViewGroup;public class ArticleFragment extends Fragment { @Override public View onCreateView(LayoutInflater inflater, ViewGroup container, Bundle savedInstanceState) { // Inflate the layout for this fragment return inflater.inflate(R.layout.article_view, container, false); }}
更多关于fragment的生命周期及callback方法可以参考developer guide中的Fragments章节。
使用XML向Activity添加Fragment
由于fragment是可以重复使用的、模型化的UI组件,每一个Fragment类的实例(instance)都要与一个父FragmentActivity相关联。你可以通过在activity的布局XML文件中定义各个fragment来实现这种关联。注:FragmentActivity是一个特殊的activity,由Support Library提供,用来处理版本低于API level 11的系统中的fragment,如果你的app最低系统版本为API level 11或者更高,那么你就可以使用正常的Activity类。
如下的示例布局文件是在当device的屏幕被认为是“large”的时候向activity中添加两个fragment(在路径名中使用large限定符指明):
res/layout-large/news_articles.xml
<LinearLayout xmlns:android="http://schemas.android.com/apk/res/android" android:orientation="horizontal" android:layout_width="fill_parent" android:layout_height="fill_parent"> <fragment android:name="com.example.android.fragments.HeadlinesFragment" android:id="@+id/headlines_fragment" android:layout_weight="1" android:layout_width="0dp" android:layout_height="match_parent" /> <fragment android:name="com.example.android.fragments.ArticleFragment" android:id="@+id/article_fragment" android:layout_weight="2" android:layout_width="0dp" android:layout_height="match_parent" /></LinearLayout>
提示:想要了解更多关于创造不同屏幕尺寸的布局,请阅读Support Different Screen Sizes。
然后在你的activity中使用这个布局:
译者注:文件位置为 java/com/example/android/fragments/MainActivity.java
import android.os.Bundle;import android.support.v4.app.FragmentActivity;public class MainActivity extends FragmentActivity { @Override public void onCreate(Bundle savedInstanceState) { super.onCreate(savedInstanceState); setContentView(R.layout.news_articles); }}
如果你使用的是v7 appcompat library,你的MainActivity应该继承的是AppCompatActivity,这是FragmentActivity的一个子类。要获取更多信息,请阅读Adding the APP Bar。
注:如果你在布局XML文件中定义了fragment来将它们添加到activity的布局,那么在运行时你将没办法将这些fragment移除。如果你想要在与用户交互时可以替换你的fragment,那么你必须让activity先开始,然后再添加fragment,即后续章节所讲。
创建一个灵活的UI
为了将你的应用设计成可以支持广泛的屏幕尺寸范围,你可以在不同的布局配置中重新使用你的fragment,基于现有的屏幕空间来提高用户体验。
例如,在单视图的手机上同时只显示一个fragment可能是更恰当的;相反的,你可能想要在平板上并排显示这些fragment,因为它有更大的屏幕尺寸,一个给用户显示更多的信息。
图1: 两个fragment,对于同一个activity在不同的屏幕尺寸上显示不同的配置。在大屏幕上,两个fragment可以并排摆放;然而在手机上,同一时间只有一个fragment是比较合适的,所以在用户操作时fragment之间会互相替换。
FragmentManager类提供了在运行时可以向activity添加、移除或替换fragment的方法,以实现动态的体验。
在运行时向Activity添加Fragment
与其在布局文件中为activity定义fragment(之前所提到的使用<fragment>元素),你可以在activity运行时向activity添加fragment。如果你打算在activity的生命周期中改变fragment,那么这种方法是必须的。
要执行一项事务(transcation),例如添加或移除fragment,你需要使用FragmentManager来创建一个FragmentTranscation,它提供了添加、移除、替换以及执行其他fragment事务的API。
如果你的activity允许fragment被移除或替换,那么你应该在activity 的onCreate()方法中向activity添加初始fragment(s)。
处理fragment时的一个非常重要的原则(特别时在运行时添加fragment)就是你的activity布局必须包含了一个View容器,可以将fragment插在里面。
下面的这种布局可以作为一种替代选择,替代之前所提到的在同一时间只能显示一个fragment的布局。为了使fragment能够被互相替换,activity的布局包含了一个空的Framelayout,这个framelayout扮演者fragment容器的角色。
要注意的是这个布局文件要与之前的layout文件同名,但是布局的路径并不含有large限定符,所以实际上这个布局是使用在设备的屏幕比large要小的时候,因为这时屏幕并不适合同时显示两个fragment。
res/layout/new_articles.xml
<FrameLayout xmlns:android="http://schemas.android.com/apk/res/android" android:id="@+id/fragment_container" android:layout_width="match_parent" android:layout_height="match_parent" />
在你的activity类中,调用getSupportFragmentManager()使用Support Library APIs得到FragmentManager。然后调用beginTranscation()来创建一个FragmentTranscation,然后调用add()来添加一个fragment。
你可以使用同一个FragmentTranscation对activiy执行多个fragment事务。当你准备好要让这些更改生效时,你必须调用commit()。
下面这个例子介绍了如何向上面的这个布局添加fragment:
译者注:文件位置为 java/com/example/android/fragments/MainActivity.java
import android.os.Bundle;import android.support.v4.app.FragmentActivity;public class MainActivity extends FragmentActivity { @Override public void onCreate(Bundle savedInstanceState) { super.onCreate(savedInstanceState); setContentView(R.layout.news_articles); // Check that the activity is using the layout version with // the fragment_container FrameLayout if (findViewById(R.id.fragment_container) != null) { // However, if we're being restored from a previous state, // then we don't need to do anything and should return or else // we could end up with overlapping fragments. if (savedInstanceState != null) { return; } // Create a new Fragment to be placed in the activity layout 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(); } }}
因为这个fragment是在运行时被添加到了Framelayout这个容器中(而不是在activity的布局中使用<fragment>元素),所以activity也可以将这个fragment移除,亦或者是使用其他的fragment来代替之前的这个。
替换Fragment
替换fragment的步骤与添加fragment相似,但需要调用的方法是replace(),而不是add()。
请记住,当你执行fragment事务,例如替换或移除fragment的时候,允许用户会退到之前并“取消”之前的改变往往是必要的。为了允许用户在fragment事务中操作回退,你需要在提交FragmentTranscation之前调用addToBackStack()。
注:当你移除或替换了一个fragment并且把事务添加到回退栈(back stack)时,这个被移除/替换的fragment处在停止(stopped)的状态,而不是销毁了(destoryed)的状态。如果用户操作回来并恢复这个fragment,它会重新开始(restart)。如果你没有把这个事务添加到回退栈的话,这个fragment在替换或移除时就会被销毁。
替换fragment的示例:
译者注:文件位置为 java/com/example/android/fragments/ArticleFragment.java
// code snippet// Create fragment and give it an argument specifying the article it should showArticleFragment 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 backtransaction.replace(R.id.fragment_container, newFragment);transaction.addToBackStack(null);// Commit the transactiontransaction.commit();// code snippet
addToBackStack()方法有一个可选的字符串输入变量,可以指明唯一的事务的名字。除非你想要使用FragmentManager.BackStackEntry API执行高级的fragment操作,否则这个名字是不需要的(译者注:平常带null就好)。
与其他Fragment通信
为了能够重复使用fragment UI组件,你需要将每一个fragment构建成完全独立的、模块化的组件,并且定义有自己的布局及行为。一旦你定义好了这些可以重复使用的fragment,你就可以将它们关联到activity,使用你的应用逻辑连接它们,来实现一个整体复合的UI。
时常地你会想要让一个fragment可以与其他的fragment进行通信,例如基于用户事件来改变内容。所有的fragment到fragment的通信都是通过与之关联的activity来完成的。两个fragment之前永远都不能直接通信。
定义一个接口
为了允许fragment向它的activity通信,你可以在fragment类里定义一个接口(interface)并在activity里实现(implement)它。Fragment会在它生命周期的onAttach()方法中捕获到接口的实现,然后可以调用这个接口方法来和activity通信。
以下是fragment到activity通信的举例:
译者注:文件位置为 java/com/example/android/fragments/HeadlinesFragment.java
public class HeadlinesFragment extends ListFragment { OnHeadlineSelectedListener mCallback; // Container Activity must implement this interface public interface OnHeadlineSelectedListener { public void onArticleSelected(int position); } @Override public void onAttach(Activity activity) { super.onAttach(activity); // This makes sure that the container activity has implemented // the callback interface. If not, it throws an exception try { mCallback = (OnHeadlineSelectedListener) activity; } catch (ClassCastException e) { throw new ClassCastException(activity.toString() + " must implement OnHeadlineSelectedListener"); } } // ...}
现在,通过调用onArticleSelected()方法(或者是接口里的其他方法),fragment可以通过使用OnHeadlineSelectedListener接口的实例mCallback向activity传递信息。
举个例子,当用户在列表项目上进行点击时,fragment里的如下方法就会被调用。Fragment使用callback接口向父activity传递事件。
译者注:文件位置为 java/com/example/android/fragments/HeadlinesFragment.java
// ... @Override public void onListItemClick(ListView l, View v, int position, long id) { // Send the event to the host activity mCallback.onArticleSelected(position); }// ...
实现这个接口
为了从fragment接收事件回调,盛装fragment的activity比需要实现在fragment类中定义的借口。
例如,如下activity实现了上面例子中的借口。
译者注:文件位置为 java/com/example/android/fragments/MainActivity.java
public static class MainActivity extends Activity implements HeadlinesFragment.OnHeadlineSelectedListener{ ... public void onArticleSelected(int position) { // The user selected the headline of an article from the HeadlinesFragment // Do something here to display that article }}
向Fragment传递信息
父activity可以通过findFragmentById()捕获Fragment实例来向fragment传递信息,然后可以直接调用fragment的公有方法。译者注:文件位置为 java/com/example/android/fragments/MainActivity.java
public static class MainActivity extends Activity implements HeadlinesFragment.OnHeadlineSelectedListener{ ... public void onArticleSelected(int position) { // The user selected the headline of an article from the HeadlinesFragment // Capture the article fragment from the activity layout ArticleFragment articleFrag = (ArticleFragment) getSupportFragmentManager().findFragmentById(R.id.article_fragment); if (articleFrag != null) { // If article frag is available, we're in two-pane layout... // Call a method in the ArticleFragment to update its content articleFrag.updateArticleView(position); } else { // If the frag is not available, we're in the one-pane layout and must swap frags... // 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(); } }}
原始地址
谷歌开发者training(需要翻墙):https://developer.android.com/training/basics/fragments/index.html
代码下载
http://download.csdn.net/detail/qiwenhe1990/9369199 0 0
- [Android] 使用Fragment创建动态UI
- 使用Fragment创建动态UI
- Android 学习笔记七:使用Fragment创建动态UI
- Training--使用Fragment创建动态UI
- Android官方开发文档Training系列课程中文版:使用Fragment构建动态UI之Fragment创建
- 使用Fragment创建一个动态UI - 与其他Fragment通信
- 利用Fragment创建动态UI 之 使用Support Library
- [Andriod官方训练教程]使用Fragment创建一个动态的UI之创建一个Fragment
- Training--使用Fragment创建动态UI(1)-- 创建一个Fragment
- Android 动态创建fragment
- android 动态创建Fragment
- 使用Fragment建立动态UI
- Android学习路线(二十一)运用Fragment构建动态UI——创建一个Fragment
- Training--使用Fragment创建动态UI(3)-- 与其他Fragment通信
- 安卓训练-开始-使用 Fragment 构造动态 UI-创建 Fragment
- Android:创建动态UI
- 利用Fragment创建动态UI 之 创建一个Fragment
- Training--使用Fragment创建动态UI(2)--构建一个灵活的UI
- poj 3045 Cow Acrobats 【二分】
- 【杭电】[2013]蟠桃记
- spring配置详解-连接池配置
- python len isalpha 中文小坑
- java线程——信号量(Semaphore)+障栅(CyclicBarrier)
- [Android] 使用Fragment创建动态UI
- UVa129 相邻重复子串
- POJ2528 Mayer's posters
- C++拷贝对象
- OpenGL超级宝典7th简体中文-第二章-我们的第一个OpenGL程式
- select @@SERVERNAME
- Java常见问题汇总
- shell 命令之 find 命令四
- 二叉树搜索树的插入算法