Android入门——Fragment详解之基本概念与用法(一)
来源:互联网 发布:2016淘宝女装店铺推荐 编辑:程序博客网 时间:2024/05/21 12:46
引言
Android在3.0中引入了Fragments的概念,其目的是用在大屏幕设备上–例如平板电脑上,支持更加动态和灵活的UI设计。平板电脑的屏幕要比手机的大得多,有更多的空间来放更多的UI组件,并且这些组件之间会产生更多的交互。Fragment允许这样的一种设计,而不需要你亲自来管理 Viewhierarchy的复杂变化。 通过将Activity的布局分散到Fragment中, 你可以在运行时修改Activity的外观,并在由Activity管理的back stack中保存那些变化。
一、Fragment概述
Android开发过程中,我们可以把Fragment想成Activity中的模块,这个模块有自己的布局,有自己的生命周期,单独处理自己的输入,在Activity运行的时候可以加载或者移除Fragment模块。从一定程度上来说,与Web开发中的iframe和DIV布局思想有点类似。例像网易新闻、易车等应用程序将一个fragment放在左边显示文章列表,在右边用另一个Fragment来显示一篇文章——两个Fragment在同一个Activity中并排着,并且每个Fragment都有其自己的生命周期回调方法序列用以处理各自的用户输入事件。因此,用户可以在同一个Activity中选择和阅读文章,而不是在一个Activity中选择,在另一个Activity中阅读。这样设计的好处就是当程序运行在平板尺寸屏幕设备上时,可以在Activity A中嵌入两个Fragment。但是,当运行在手机尺寸屏幕上,就没有足够的空间容纳两个Fragment了,因此Activity A只能引用包含文章列表的Fragment,在当用户选择一篇文章时,可以启动Activity B,它包含了用来阅读文章的第二个fragment。这样,应用程序通过以不同组合的复用fragments支持了平板电脑和手机,再比如官方的这个例子:
二、Fragment的生命周期
因为Fragment必须嵌入在Acitivity中使用,所以Fragment的生命周期和它所在的Activity是密切相关的。如果Activity是暂停状态,其中所有的Fragment都是暂停状态;如果Activity是stop状态,这个Activity中所有的Fragment都不能被启动;如果Activity被销毁,那么它其中的所有Fragment都会被销毁。但是,当Activity在活动状态,可以独立控制Fragment的状态,比如加上或者移除Fragment。当这样进行fragment transaction(转换)的时候,可以把fragment放入Activity的back stack中,这样用户就可以进行返回操作。
一旦Activity进入resumed状态(也就是running状态),我们就可以自由地添加和删除Fragment了。因此,只有当Activity在resumed状态时,Fragment的生命周期才能独立的运转,其它时候是依赖于Activity的生命周期变化的。
三、Fragment生命周期分析
1. 当创建Fragment时,它会经历以下状态.
onAttach()——>onCreate()——>onCreateView()——>
onActivityCreated()——>
2. 当Fragment对用户可见的:
onStart()——>onResume()——>
3. 当Fragment进入“后台模式”的时:
onPause()——>onStop()——>
4. 当Fragment被销毁了(或者持有它的Activity被销毁了)时:
onPause()——>onStop()——>onDestroyView()——>onDestroy() ——>onDetach()——>
5. 与Activity一样,在以下的状态中,可以使用Bundle对象保存一个Fragment的对象。
onCreate()——>onCreateView()——>onActivityCreated()——>
四、Fragment的状态
- 运行状态:但Fragment处于前台,用户可见,可获取焦点
- 暂停状态:其他Activity位于前台,该Fragment依然可以见,但不能获取焦点
- 停止状态:该Fragment完全不可见,失去焦点
- 销毁状态:该Fragment被完全删除或所依附的Activity被结束。
五、Fragment的基本操作和使用
要使用Fragment,可通过继承Fragment类,复写相关方法来实现加载Fragment自身的UI并初始化Fragment相关变量,控制Fragment与Activity的交互,通常都需要指定一个UI,但也可以为Activity创建一个没有UI只提供后台行为的Fragment。
1、创建Fragment分为:Java代码动态创建与xml静态创建
1.1、xml静态创建
- 首先在依附的Activity的布局文件中定义fragment节点(其中fragment节点里的id和name必填,name对应着我们自定义的Fragment的子类的完整类名,还有一个tag属性也应该是唯一的可以通过findFragmentByTag(tag)获取对应的Fragement)
<?xml version="1.0" encoding="utf-8"?><LinearLayout xmlns:android="http://schemas.android.com/apk/res/android" android:orientation="vertical" android:layout_width="match_parent" android:layout_height="match_parent"> <TextView android:text="Hello Fragment!" android:layout_width="wrap_content" android:layout_height="wrap_content" style="@style/TitleStyle"/> <!--name:对应着我们继承Fragment的子Fragment类--> <fragment android:id="@+id/id_fragment_main" android:name="com.crazymo.fragmentsdemo.MainFragment" android:layout_width="match_parent" android:layout_height="wrap_content" /></LinearLayout>
- 再继承Fragment重写相关方法
package com.crazymo.fragmentsdemo;import android.app.Fragment;import android.content.Context;import android.os.Bundle;import android.support.annotation.Nullable;import android.util.Log;import android.view.LayoutInflater;import android.view.View;import android.view.ViewGroup;/** * Created by cmo on 16-4-19. */public class MainFragment extends Fragment { private final String TAG="FramentDemo"; @Override public void onAttach(Context context) { Log.d(TAG, "onAttach:刚刚与Activity对接"); super.onAttach(context); } @Override public void onCreate(Bundle savedInstanceState) { Log.d(TAG, "onCreate:初始化Fragment对象"); super.onCreate(savedInstanceState); } @Nullable @Override public View onCreateView(LayoutInflater inflater, ViewGroup container, Bundle savedInstanceState) { Log.d(TAG, "onCreateView:初始化Fragment的UI"); return inflater.inflate(R.layout.fragment_main, container, false);//参数依次为:布局id,依附的容器 } @Override public void onActivityCreated(Bundle savedInstanceState) { Log.d(TAG, "onActivityCreated:Activity和Fragment都已经创建好了"); super.onActivityCreated(savedInstanceState); } @Override public void onStart() { Log.d(TAG, "onStart:Fragment变为可见,待交互"); super.onStart(); } @Override public void onResume() { Log.d(TAG, "onResume"); super.onResume(); } @Override public void onPause() { Log.d(TAG, "onPause:与Activity的OnPause绑定"); super.onPause(); } @Override public void onStop() { Log.d(TAG, "onStop:与Activity的OnStop绑定"); super.onStop(); } @Override public void onDestroyView() { Log.d(TAG, "onDestroyView:Fragment即将被保存或者删除"); super.onDestroyView(); } @Override public void onDestroy() { Log.d(TAG, "onDestroy:还与Activity藕断丝连中可以在Activity中找到"); super.onDestroy(); } @Override public void onDetach() { Log.d(TAG, "onDetach:彻底和Activity分手了"); super.onDetach(); }}
- 然后再定义Fragment自身的布局xml
<!--fragment_main.xml--><?xml version="1.0" encoding="utf-8"?><LinearLayout xmlns:android="http://schemas.android.com/apk/res/android" android:orientation="vertical" android:layout_width="match_parent" android:layout_height="match_parent"> <TextView android:layout_width="match_parent" android:layout_height="wrap_content" style="@style/TitleStyle" android:text="Fragment详解(一)"/> <ImageView android:layout_width="match_parent" android:layout_height="match_parent" android:src="@mipmap/ic_launcher"/></LinearLayout>
- 接着在onCreatedView方法里把布局xml映射为view并返回(一般通过Inflater对象的inflate(R.layout.fragment_main, container, false)方法)
return inflater.inflate(R.layout.fragment_main, container, false);//参数依次为:布局id,依附的容器
1.2、java代码动态创建
getFragmentManager().beginTransaction().add(R.id.id_fragment_main,new MainFragment()).commit();//第一个参数为容器的Id,这里为FrameLayout的Id,第二个参数为Fragment对象实例getFragmentManager().beginTransaction().add(R.id.id_fragment_main,new MainFragment(),"MainFragment").commit();//第三个参数为tag
- 首先还是定义Fragemnt对应的布局文件和继承Fragment实现自己的Fragment
- 然后在依附的Activity的布局文件中线使用FrameLayout占位
<LinearLayout xmlns:android="http://schemas.android.com/apk/res/android" android:layout_width="match_parent" android:layout_height="match_parent" android:orientation="vertical" android:baselineAligned="false" > <FrameLayout android:id="@+id/id_fragment_main" android:layout_width="match_parent" android:layout_height="match_parent"/> </LinearLayout>
- 再获取FragmentManager(在V4包中通过getSupportFragmentManager())
FrgamentManager fragmentManager=getFragmentManager();
- 通过beginTransaction方法开启事务FragmentTransaction
FragmentTransaction fragmentTransaction=fragmentManager.beginTransaction();
- 使用FragmentTransaction 的add或者replace方法向容器内添加Fragment(需要传入容器的id和Fragment的实例对象。)
fragmentTrancsaction.add(id_fragment_main,new MainFragment());//容器的id,Fragment的实例对象
- 提交事务
fragmentTransaction.commit();
2、Fragment的删除remove
Fragment的删除也还是借助FragmentManager和FragmentTransaction,主要有两个步骤:
- 先通过FragmentManager对象的findFragmentById和findFragmentByTag获取对应的Fragment
- 再传入到remove方法中,并commit。
3、Fragment的替换replace
Fragment的替换replace这个方法真的有点奇怪,并没有像我们正常的逻辑,至少应该提供源Fragment和目标Fragment两个参数,但并没有只是提供了一个容器Id和目标Fragment(即将被添加到容器里展示的Fragment),当年学习的时候也觉得很奇怪,这里先不深究,以后再去分析。
fragmentManager.beginTransaction().replace(R.id.id_fragment_main,new OtherFragment()).commit();//容器Id,新的Fragment对象
4、Fragment的隐藏hide和显示show
对于Fragment的hide或者show只需要传递我们一个将要hide或者show的Fragment即可。(需要注意的是无论是hide还是show都是针对顶层Fragment,也就是假设你要show的Fragment不是顶层的是show不出来的)
private void hideFragment(String tag){ Fragment mainFragment = fragmentManager.findFragmentByTag(tag); fragmentManager.beginTransaction().hide(mainFragment).addToBackStack(tag).commit(); } private void showFragment(String tag){ Fragment mainFragment = fragmentManager.findFragmentByTag(tag); fragmentManager.beginTransaction().show(mainFragment).addToBackStack(tag).commit(); }
5、Fragment 的attach和detach
- public abstract FragmentTransaction attach(Fragment fragment); 它利用Fragment对象的onCreateView()来重建视图,并重新把UI附着到fragment上(由于是将fragment添加到队列,且只能添加到列队头部),所以attach()操作的结果是,最新操作的页面始终显示在最前面,此时调用fragment.isAdded()将返回True。
fragmentManager.beginTransaction().attach(mainFragment).addToBackStack(tag).commit();
- public FragmentTransaction detach(Fragment fragment):与attach所做的工作相反,它将参数中的fragment与UI分离,此时的状态与把fragment放入返回栈时一样,虽然将view从viewtree中删除,并将fragment从Activity的队列中移除!但对应的fragment实例并不会删除( 在使用detach()后,使用fragment.isAdded()返回的值是false),还是可以被fragmentManager管理的,所以通过FragmentManager.findViewByTag()仍然是会有值的。
fragmentManager.beginTransaction().detach(mainFragment).addToBackStack(tag).commit();
六、Fragment的基本应用完整例子
主布局的xml文件:
<?xml version="1.0" encoding="utf-8"?><LinearLayout xmlns:android="http://schemas.android.com/apk/res/android" android:orientation="vertical" android:layout_width="match_parent" android:layout_height="match_parent"> <FrameLayout android:id="@+id/id_fragment_main" android:layout_width="match_parent" android:layout_height="0dp" android:layout_weight="1" /> <Button android:id="@+id/id_addfragment_btn" android:layout_width="match_parent" android:layout_height="wrap_content" android:text="添加Fragment1"/> <Button android:id="@+id/id_replacefragment_btn" android:layout_width="match_parent" android:layout_height="wrap_content" android:text="替换为Fragment2"/> <Button android:id="@+id/id_removefragment_btn" android:layout_width="match_parent" android:layout_height="wrap_content" android:text="移除Fragment1"/> <Button android:id="@+id/id_hidefragment_btn" android:layout_width="match_parent" android:layout_height="wrap_content" android:text="hide MainFragement"/> <Button android:id="@+id/id_showfragment_btn" android:layout_width="match_parent" android:layout_height="wrap_content" android:text="show MainFragement"/></LinearLayout>
MainFragment的布局文件:
<?xml version="1.0" encoding="utf-8"?><LinearLayout xmlns:android="http://schemas.android.com/apk/res/android" android:orientation="vertical" android:layout_width="match_parent" android:layout_height="match_parent"> <TextView android:layout_width="match_parent" android:layout_height="wrap_content" style="@style/TitleStyle" android:text="MainFragment"/> <ImageView android:layout_width="match_parent" android:layout_height="match_parent" android:src="@mipmap/ic_launcher"/></LinearLayout>
OtherFragment的布局文件:
<?xml version="1.0" encoding="utf-8"?><LinearLayout xmlns:android="http://schemas.android.com/apk/res/android" android:orientation="vertical" android:layout_width="match_parent" android:layout_height="match_parent"> <TextView android:layout_width="match_parent" android:layout_height="wrap_content" style="@style/TitleStyle" android:text="OtherFragment"/> <ImageView android:layout_width="match_parent" android:layout_height="match_parent" android:src="@mipmap/ic_blue_launcher"/></LinearLayout>
MainActivity的代码:
package com.crazymo.fragmentsdemo;import android.app.Activity;import android.app.Fragment;import android.app.FragmentManager;import android.app.FragmentTransaction;import android.nfc.Tag;import android.support.annotation.NonNull;import android.support.annotation.StringRes;import android.support.v7.app.AppCompatActivity;import android.os.Bundle;import android.util.Log;import android.view.View;import android.widget.Button;public class MainActivity extends Activity implements View.OnClickListener { private final String TAG="FramentDemo"; private Button mAddBtn,mRemoveBtn,mRelpaceBtn,mHideBtn,mShowBtn; private FragmentManager fragmentManager=getFragmentManager(); @Override protected void onCreate(Bundle savedInstanceState) { super.onCreate(savedInstanceState); Log.d(TAG, "Activity onCreate"); setContentView(R.layout.activity_main); init(); } private void init(){ getViews(); setClickListener(); } private void getViews(){ mAddBtn= (Button) findViewById(R.id.id_addfragment_btn); mRelpaceBtn=(Button)findViewById(R.id.id_replacefragment_btn); mRemoveBtn= (Button) findViewById(R.id.id_removefragment_btn); mHideBtn= (Button) findViewById(R.id.id_hidefragment_btn); mShowBtn= (Button) findViewById(R.id.id_showfragment_btn); } private void setClickListener(){ mAddBtn.setOnClickListener(this); mRemoveBtn.setOnClickListener(this); mRelpaceBtn.setOnClickListener(this); mHideBtn.setOnClickListener(this); mShowBtn.setOnClickListener(this); } @Override protected void onStart() { Log.d(TAG, "Activity onStart"); super.onStart(); } @Override protected void onRestart() { Log.d(TAG,"Activity onReStart"); super.onRestart(); } @Override protected void onResume() { Log.d(TAG,"Activity onResume"); super.onResume(); } @Override protected void onPause() { Log.d(TAG,"Activity onPause"); super.onPause(); } @Override protected void onStop() { Log.d(TAG,"Activity onStop"); super.onStop(); } @Override protected void onDestroy() { Log.d(TAG,"Activity onDestory"); super.onDestroy(); } private void addFragemnt(@StringRes int viewGroupId,@NonNull Fragment fragment,String tag){ fragmentManager=getFragmentManager(); fragmentManager.beginTransaction().add(viewGroupId,fragment,tag) .addToBackStack(tag).commit(); } private void removeFragment(String tag){ Fragment fragment = fragmentManager.findFragmentByTag(tag); fragmentManager.beginTransaction().remove(fragment).commit(); } private void replaceFragment(@StringRes int viewGroupId,@NonNull Fragment fragment){ fragmentManager.beginTransaction().add(viewGroupId, fragment).commit(); } private void hideFragment(String tag){ Fragment mainFragment = fragmentManager.findFragmentByTag(tag); fragmentManager.beginTransaction().hide(mainFragment).addToBackStack(tag).commit(); } private void showFragment(String tag){ Fragment mainFragment = fragmentManager.findFragmentByTag(tag); fragmentManager.beginTransaction().show(mainFragment).addToBackStack(tag).commit(); } @Override public void onClick(View v) { switch (v.getId()){ case R.id.id_addfragment_btn: int viewGroupId=R.id.id_fragment_main; addFragemnt(viewGroupId,new MainFragment(),"MainFragment"); break; case R.id.id_removefragment_btn: removeFragment("MainFragment"); break; case R.id.id_replacefragment_btn: //Fragment fragment2 = fragmentManager.findFragmentByTag("MainFragment"); //fragmentManager.beginTransaction().remove(fragment2).commit(); int viewGroup=R.id.id_fragment_main; replaceFragment(viewGroup,new OtherFragment()); break; case R.id.id_hidefragment_btn: hideFragment("MainFragment"); break; case R.id.id_showfragment_btn: showFragment("MainFragment"); break; default: break; } }}
MainFragment的代码
package com.crazymo.fragmentsdemo;import android.app.Fragment;import android.content.Context;import android.os.Bundle;import android.support.annotation.Nullable;import android.util.Log;import android.view.LayoutInflater;import android.view.View;import android.view.ViewGroup;/** * Created by cmo on 16-4-19. */public class MainFragment extends Fragment { private final String TAG="FramentDemo"; @Override public void onAttach(Context context) { Log.d(TAG, "onAttach:刚刚与Activity对接"); super.onAttach(context); } @Override public void onCreate(Bundle savedInstanceState) { Log.d(TAG, "onCreate:初始化Fragment对象"); super.onCreate(savedInstanceState); } @Nullable @Override public View onCreateView(LayoutInflater inflater, ViewGroup container, Bundle savedInstanceState) { Log.d(TAG, "onCreateView:初始化Fragment的UI"); return inflater.inflate(R.layout.fragment_main, container, false); } @Override public void onActivityCreated(Bundle savedInstanceState) { Log.d(TAG, "onActivityCreated:Activity和Fragment都已经创建好了"); super.onActivityCreated(savedInstanceState); } @Override public void onStart() { Log.d(TAG, "onStart:Fragment变为可见,待交互"); super.onStart(); } @Override public void onResume() { Log.d(TAG, "onResume"); super.onResume(); } @Override public void onPause() { Log.d(TAG, "onPause:与Activity的OnPause绑定"); super.onPause(); } @Override public void onStop() { Log.d(TAG, "onStop:与Activity的OnStop绑定"); super.onStop(); } @Override public void onDestroyView() { Log.d(TAG, "onDestroyView:Fragment即将被保存或者删除"); super.onDestroyView(); } @Override public void onDestroy() { Log.d(TAG, "onDestroy:还与Activity藕断丝连中可以在Activity中找到"); super.onDestroy(); } @Override public void onDetach() { Log.d(TAG, "onDetach:彻底和Activity分手了"); super.onDetach(); }}
OtherFragment的代码
package com.crazymo.fragmentsdemo;import android.app.Fragment;import android.os.Bundle;import android.support.annotation.Nullable;import android.view.LayoutInflater;import android.view.View;import android.view.ViewGroup;/** * Created by cmo on 16-4-21. */public class OtherFragment extends Fragment { @Nullable @Override public View onCreateView(LayoutInflater inflater, ViewGroup container, Bundle savedInstanceState) { return inflater.inflate(R.layout.fragment_other,null); }}
- Android入门——Fragment详解之基本概念与用法(一)
- Android入门——Fragment详解之Fragment与Activity通信及数据交换(二)
- Android入门之Fragment用法
- Android入门之Fragment用法
- Android入门之Fragment用法
- Android入门之Fragment用法
- Android入门之Fragment用法
- Android入门之Fragment用法
- Android之Fragment入门一
- Android基础——Fragment基础入门(一)
- Android-Fragment入门用法
- Android开发之Fragment详解(一)
- Android基础使用之Fragment详解一
- 中断详解(一)——基本概念
- Android fragment入门一
- UITableView之(一):基本概念和用法
- Android之Fragment(一)
- 编程回忆之Android回忆(Android入门之Fragment用法)
- D4A (Design for All)
- POJ2823 Sliding Window(单调队列)
- lucene5.3.1 索引增删改查
- [POJ1389]Area of Simple Polygons(扫描线+线段树)
- 创建删除数据库
- Android入门——Fragment详解之基本概念与用法(一)
- MSBuild命令行编译Xamarin 项目
- 插入文档命令
- 对于日访问量达到1W IP的处理方法
- 【网虫】怎么知道网站是什么线路的?
- 更新文档命令
- const有什么用途?
- poj1046 枚举
- 手把手教你XIB拖商城类应用的待发货列表