Fragment讲解
来源:互联网 发布:js 字符串日期格式化 编辑:程序博客网 时间:2024/06/01 09:50
在文章的开头奉送上代码,方便大家对照学习。
1 前言
项目中frgment是常用的东西,最近有空想把它整理整理。
fragment是“片段”的意思。在android中fragment是一种可以嵌入在活动当中的UI片段,它能让程序更加合理和充分地利用大屏幕的空间(如:平板上应用)、解决activity负载过重的问题等。
2 Fragment的生命周期
请记住,fragment必须依存于activity!因此Activity的生命周期会直接影响到Fragment的生命周期,我看一下acitity和fragment的生命周期的比较图:
注意:除了onCreateView,其他的所有方法如果你重写了,必须调用父类对于该方法的实现(即super.方法名)
3 Fragment的使用方法
3.1 静态方式使用Fragment
这是使用Fragment最简单的一种方式,把Fragment当成普通的控件,直接写在Activity的布局文件中。步骤如下:
1、继承Fragment,重写onCreateView决定Fragemnt的布局2、将fragment做为普通的控件在布局文件中使用。3、在Activity中声明此Fragment,就当和普通的View一样
下面我们来举例说明:(我把Fragment嵌入到布局文件中,显示“静态方式”4个字)
3.1.1 Fragmeng布局文件代码如下:
<?xml version="1.0" encoding="utf-8"?><LinearLayout xmlns:android="http://schemas.android.com/apk/res/android" android:id="@+id/parentlayout" android:orientation="vertical" android:layout_width="match_parent" android:layout_height="match_parent"> <TextView android:id="@+id/textView" android:text="静态方式" android:textColor="#000000" android:textSize="30sp" android:gravity="center" android:layout_width="match_parent" android:layout_height="match_parent" /></LinearLayout>
3.1.2 Fragment代码如下:
public class OneFragment extends Fragment { private TextView textView; @Nullable @Override public View onCreateView(LayoutInflater inflater, ViewGroup container, Bundle savedInstanceState) { View view = inflater.inflate(R.layout.fragment_one, container, false); textView = (TextView)view.findViewById(R.id.textView); textView.setText("静态方式"); textView.setOnClickListener(this); return view; }}
3.1.3 Activity 的布局文件代码如下:
<?xml version="1.0" encoding="utf-8"?><LinearLayout xmlns:android="http://schemas.android.com/apk/res/android" android:id="@+id/parentlayout" android:orientation="vertical" android:layout_width="match_parent" android:layout_height="match_parent"><fragment android:id="@+id/oneFragment" android:name="mystudy.czh.com.myapp.OneFragment" android:layout_width="match_parent" android:layout_height="match_parent" /></LinearLayout>
3.1.4 Activity代码如下:
public class MainActivity extends AppCompatActivity { @Override protected void onCreate(Bundle savedInstanceState) { super.onCreate(savedInstanceState); setContentView(R.layout.activity_main); }}
看到没Activity中什么代码都没有,很清爽。这就是fragment的好处:所有的逻辑都在fragment中做处理,acitivity要做的就是控制那个fragment显示即可,这样代码清晰,增强可读性、复用性以及可维护性、减少activity的逻辑负载,非常好!
3.1.5 效果图如下:
3.2 动态方式使用Fragment
动态使用我们讲解如何添加、删除、更新Fragment。
先来学习一下fragment家族中的类有哪些?
1.获取FragmentManage的方式:
getFragmentManager() // v4中,getSupportFragmentManager
2.主要的操作都是FragmentTransaction的方法
FragmentTransaction transaction = fm.benginTransatcion();//开启一个事务transaction.add() //往Activity中添加一个Fragmenttransaction.remove() //从Activity中移除一个Fragment,如果被移除的Fragment没有添加到回退栈(回退栈后面会详细说),这个Fragment实例将会被销毁。transaction.replace()//使用另一个Fragment替换当前的,实际上就是remove()然后add()的合体~transaction.hide()//隐藏当前的Fragment,仅仅是设为不可见,并不会销毁transaction.show()//显示之前隐藏的Fragmentdetach()//会将view从UI中移除,和remove()不同,此时fragment的状态依然由FragmentManager维护。attach()//重建view视图,附加到UI上并显示。transatcion.commit()//提交一个事务
上述,基本是操作Fragment的所有的方式了,在一个事务开启到提交可以进行多个的添加、移除、替换等操作。
其实记住4个步骤就会很简单的使用,步骤如下:
1.获取FragmentManager(getFragmentManager() )2.开启一个事务保证操作的原子性(FragmentTransaction transaction = fm.benginTransatcion();//开启一个事务)3.通过事务FragmentTransaction ,进行fragment的操作4.事务提交(transatcion.commit()//提交一个事务)
实战:fragment实现简单选项卡的功能
效果图如下:
大家可以看出这4个选项卡是一样的,只是图片不一样而已,所以我们这里只贴一个fragment代码就行了。
1.Fragment布局文件代码:
<?xml version="1.0" encoding="utf-8"?><ImageView xmlns:android="http://schemas.android.com/apk/res/android" android:id="@+id/imageView" android:layout_width="match_parent" android:layout_height="match_parent"/>
2.Fragment代码:
public class BingFragment extends Fragment { private ImageView imageView; @SuppressLint("NewApi") @Nullable @Override public View onCreateView(LayoutInflater inflater, ViewGroup container, Bundle savedInstanceState) { View view = inflater.inflate(R.layout.fragment_layout, container, false); imageView = (ImageView)view.findViewById(R.id.imageView); imageView.setBackground(getActivity().getResources().getDrawable(R.drawable.bing_big)); return view; }}
3.Activity布局文件代码如下:
<?xml version="1.0" encoding="utf-8"?><RelativeLayout xmlns:android="http://schemas.android.com/apk/res/android" android:orientation="vertical" android:layout_width="match_parent" android:layout_height="match_parent"> <LinearLayout android:id="@+id/contentLayout" android:orientation="vertical" android:background="#ffffff" android:layout_width="match_parent" android:layout_height="match_parent" android:layout_above="@+id/menuLayout" > </LinearLayout> <LinearLayout android:id="@+id/menuLayout" android:background="#f0f0f0" android:orientation="horizontal" android:layout_width="match_parent" android:layout_height="wrap_content" android:layout_alignParentBottom="true" android:layout_centerHorizontal="true"> <TextView android:id="@+id/fbbTV" android:text="冰冰" android:drawableTop="@drawable/bb" style="@style/tvStyle" /> <TextView android:id="@+id/yhTV" android:text="奕欢" android:drawableTop="@drawable/yh" style="@style/tvStyle" /> <TextView android:id="@+id/yfTV" android:text="亦菲" android:drawableTop="@drawable/yf" style="@style/tvStyle" /> <TextView android:id="@+id/jtTV" android:text="景甜" android:drawableTop="@drawable/jt" style="@style/tvStyle" /> </LinearLayout></RelativeLayout>
4.Activity代码如下:
public class MainActivity extends AppCompatActivity implements View.OnClickListener{private LinearLayout contentLayout;private TextView fbbTV,yhTV,yfTV,jtTV; @Override protected void onCreate(Bundle savedInstanceState) { super.onCreate(savedInstanceState); setContentView(R.layout.activity_main); findView(); defalutFragment(new BingFragment()); } private void findView() { contentLayout = (LinearLayout)findViewById(R.id.contentLayout); fbbTV = (TextView)findViewById(R.id.fbbTV); yhTV = (TextView)findViewById(R.id.yhTV); yfTV = (TextView)findViewById(R.id.yfTV); jtTV = (TextView)findViewById(R.id.jtTV); fbbTV.setOnClickListener(this); yhTV.setOnClickListener(this); yfTV.setOnClickListener(this); jtTV.setOnClickListener(this); } @Override public void onClick(View v) { switch(v.getId()){ case R.id.fbbTV: replaceFragment(new BingFragment() ); break; case R.id.yhTV: replaceFragment(new YiHuanFragment() ); break; case R.id.yfTV: replaceFragment(new YiFeiFragment() ); break; case R.id.jtTV: replaceFragment(new JingTianFragment() ); break; } } /** * @author YuYuanDa * created by 2017-01-13 * 替代fragment */ private void replaceFragment(Fragment fragment){ FragmentTransaction ft = getFragmentManager().beginTransaction(); ft.replace(R.id.contentLayout,fragment);// ft.addToBackStack(null); ft.commit(); } /** * 设置默认fragment * @param fragment */ private void defalutFragment(Fragment fragment){ FragmentTransaction ft = getFragmentManager().beginTransaction(); ft.add(R.id.contentLayout,fragment);// ft.addToBackStack(null); ft.commit(); }}
好了到此为止,就是Fragment的简单使用。
4 Fragment栈管理
我们知道在activity中每当启动一个activity就会压栈,当你返回时,Activity就是按照后进先出的顺序回退。其实fragment也有压栈的功能。
fragment添加到回退栈的方法是:
FragmentTransaction.addToBackStack(String)
先看一个效果图:
点击第一个界面,切换到第二个界面,点击第二个界面,切换到第三个界面,然后点击Back键依次回退。是不是很像activity的回退?代码很简单,我就不贴了。在最后我会附上代码,大家下载代码看一下就行。
5 Fragment与Activity通信
情景1:Fragment和宿主Activity的通信
1.Fragment调用宿主Activity中的方法,可以通过getActivity得到当前绑定的Activity的实例,然后调用宿主activity中的方法,在这里鼓励大家用接口的方式实现。2.Activity调用Fragment的方法,直接通过获取引用调用fragment中的public方法就行。3、如果Activity中未保存任何Fragment的引用,那么没关系,每个Fragment都有一个唯一的TAG或者ID,可以通过getFragmentManager.findFragmentByTag()或者findFragmentById()获得任何Fragment实例,然后进行操作。
注意:如果在Fragment中需要Context,可以通过调用getActivity(),如果该Context需要在Activity被销毁后还存在,则使用getActivity().getApplicationContext()。
我们通过代码来讲解一下第1条:
Fragment类代码如下:
public class CommunicateFragment extends Fragment implements View.OnClickListener{ public interface OnCommunicateBtnClickListener{ public String getActivityName(); } private Button clickTv; @Nullable @Override public View onCreateView(LayoutInflater inflater, ViewGroup container, Bundle savedInstanceState) { View view = inflater.inflate(R.layout.fragment_communicate, container, false); clickTv = (Button) view.findViewById(R.id.clickTv); clickTv.setOnClickListener(this); return view; } @Override public void onClick(View v) { switch(v.getId()){ case R.id.clickTv: //getActivity()强转成OnCommunicateBtnClickListener接口 OnCommunicateBtnClickListener ocbcl = (OnCommunicateBtnClickListener)getActivity(); clickTv.setText(ocbcl.getActivityName()); break; } }}
解析:在这个fragment中我们定义了一个接口OnCommunicateBtnClickListener,将来宿主activity要实现这个接口。
在onClick方法中我们将getActivity()强转成OnCommunicateBtnClickListener,然后调用接口中的方法。
再来看一下MainActivity类代码:
public class CommunicateActivity extends Activity implements CommunicateFragment.OnCommunicateBtnClickListener { @Override public String getActivityName() { return "CommunicateActivity"; } private LinearLayout contentLayout; @Override protected void onCreate(Bundle savedInstanceState) { super.onCreate(savedInstanceState); setContentView(R.layout.activity_communicate); FragmentManager fm = getFragmentManager(); FragmentTransaction ft = fm.beginTransaction(); ft.add(R.id.contentLayout,new CommunicateFragment()); ft.commit(); }}
解析:宿主activity实现OnCommunicateBtnClickListener 接口并实现接口的方法。
情景2:Fragment获取启动Activity的返回数据
依旧是一个简单的场景:两个Fragment,一个Fragment(叫做StartOneFragment),一个Fragment(叫做:SecFragment),当然了,这两个Fragment都有其宿主Activity。
现在,我们从StartOneFragment启动SecFragment,当用户点击返回后,将会接收到SecFragment的返回数据,并显示出来。如下图:
在Fragment中存在startActivityForResult()以及onActivityResult()方法。但是呢,没有setResult()方法,用于设置返回的intent,这样我们就需要通过调用getActivity().setResult(ListTitleFragment.REQUEST_DETAIL, intent);。
由于篇幅问题,Activity的代码我们就不贴了,Fragment具体代码实现如下:
1.StartOneFragment 代码如下:
public class StartOneFragment extends Fragment implements View.OnClickListener{ private Button startBtn,startFragmentBtn; @Nullable @Override public View onCreateView(LayoutInflater inflater, ViewGroup container, Bundle savedInstanceState) { View view = inflater.inflate(R.layout.fragment_startone, container, false); startBtn = (Button)view.findViewById(R.id.startBtn); startFragmentBtn = (Button)view.findViewById(R.id.startFragmentBtn); startBtn.setOnClickListener(this); startFragmentBtn.setOnClickListener(this); return view; } @Override public void onClick(View v) { switch(v.getId()){ case R.id.startBtn: Intent intent = new Intent(getActivity(),SecActivity.class); startActivityForResult(intent,1000); break; case R.id.startFragmentBtn: break; } } @Override public void onActivityResult(int requestCode, int resultCode, Intent data) { super.onActivityResult(requestCode, resultCode, data); if(requestCode==1000&&resultCode== Activity.RESULT_OK){ startBtn.setText(data.getStringExtra("backdata")); } }}
2.SecFragment代码如下
public class SecFragment extends Fragment implements View.OnClickListener{ private Button backBtn; @Nullable @Override public View onCreateView(LayoutInflater inflater, ViewGroup container, Bundle savedInstanceState) { View view = inflater.inflate(R.layout.fragment_sec, container, false); backBtn = (Button)view.findViewById(R.id.backBtn); backBtn.setOnClickListener(this); return view; } @Override public void onClick(View v) { switch (v.getId()){ case R.id.backBtn: Intent intent = getActivity().getIntent().putExtra("backdata","123"); getActivity().setResult(Activity.RESULT_OK,intent); getActivity().finish(); break; } }}
贴出了两个Fragment的代码,在SecFragment 中我们通过getActivity().setResult(Activity.RESULT_OK,intent);来返回数据。
也说明了一个问题:fragment能够从Activity中接收返回结果,但是其自身无法产生返回结果,只有Activity拥有返回结果。
3.效果图如下:
6 用DialogFragment 创建对话框
DialogFragment在android 3.0时被引入。这个表面上看起来和普通的dialog看起来一样,用起来也非常简单,让我们赶紧来看看吧。
这个比较简单我们直接写代码:
6.1 xml代码如下
<?xml version="1.0" encoding="utf-8"?><LinearLayout xmlns:android="http://schemas.android.com/apk/res/android" android:paddingBottom="15dp" android:paddingTop="15dp" android:paddingLeft="10dp" android:paddingRight="10dp" android:orientation="vertical" android:layout_width="match_parent" android:layout_height="match_parent"> <TextView android:text="感谢大家看我的博客!\n我特别高兴!" android:layout_width="match_parent" android:layout_height="wrap_content" android:gravity="center_horizontal" android:textSize="17sp" android:textColor="#000000" /> <Button android:text="确定" android:layout_width="match_parent" android:layout_height="wrap_content" android:id="@+id/button" /></LinearLayout>
6.2 dialog代码如下:
public class MyDialog extends DialogFragment { @Override public View onCreateView(LayoutInflater inflater, ViewGroup container,Bundle savedInstanceState){ View view = inflater.inflate(R.layout.mydialog_layout, container); return view; }}
6.3 dialog显示代码如下:
MyDialog editNameDialog = new MyDialog(); editNameDialog.show(getFragmentManager(), "EditNameDialog");
6.4 效果图如下:
7 FragmentPagerAdapter与FragmentStatePagerAdapter
相信这两个PagerAdapter的子类,大家都不陌生吧~~使用ViewPager和上面二个结合的案例特别多,那么这两个类有何区别呢?
主要区别就在与对于fragment是否销毁,下面细说:
FragmentStatePagerAdapter:会销毁不再需要的fragment,当前事务提交以后,会彻底的将fragmeng从当前Activity的FragmentManager中移除,state标明,销毁时,会将其onSaveInstanceState(Bundle outState)中的bundle信息保存下来,当用户切换回来,可以通过该bundle恢复生成新的fragment,也就是说,你可以在onSaveInstanceState(Bundle outState)方法中保存一些数据,在onCreate中进行恢复创建。
如上所说,使用FragmentStatePagerAdapter当然更省内存,但是销毁新建也是需要时间的。一般情况下,如果你是制作主页面,就3、4个Tab,那么可以选择使用FragmentPagerAdapter,如果你是用于ViewPager展示数量特别多的条目时,那么建议使用FragmentStatePagerAdapter。
篇幅原因,具体的案例就不写了,大家自行测试。
8 给Fragment传递参数的正确方式
google官方不建议把参数放在fragment的构造方法中,因此google官方提供了2个方法:
1.void setArguments(Bundle args); 这个函数为Fragment提供构造参数(也就是数据),参数以Bundle类型封装。因为官方不建议把数据的传递提供写在构造函数当中,因此提供了这个方法。2.Bundle getArguments(); 通过这个函数可以获取到传递给Fragment的参数。可以再Fragment当中直接调用,获取传递的数据。
9 Fragment家族其他常用方法补充
在文章的最后我们补充一下fragment家族的其他重要方法:
9.1 Fragment对象
9.2 FragmentManager对象
9.3 FragmentTransaction对象
10 结尾
在文章的结尾奉送上代码,方便大家对照学习。
呼~~,这篇文章写了好几天,终于整理完了!如果觉的我写的还可以就点个赞吧,谢谢您的鼓励!
在技术的路上我依旧是个小渣渣,加油!勉励自己!
11 参考文档
- Android Fragment 真正的完全解析
- Android Fragment 你应该知道的一切
- 【Android开发】之Fragment重要函数讲解
- Fragment讲解
- Fragment讲解
- Fragment讲解
- fragment的全讲解
- android的fragment讲解
- fragment的全讲解
- fragment 讲解1
- fragment 讲解2
- Android 碎片Fragment讲解
- Android Fragment讲解
- Fragment基础知识讲解
- Fragment基础知识讲解
- fragment的函数讲解
- 史上最详细Fragment讲解
- fragment之函数讲解???
- Android Fragment重要函数讲解
- Fragment 碎片的案例讲解
- 傲慢的上校的fragment讲解
- 基于ubuntu14视觉识别乒乓球_1
- WIN10-64+CUDA8.0+OpenCV3.0+VS2015配置
- mypipe使用中出现的null:4问题
- 译]badblocks指令
- BZOJ 3166 set+可持久化trie树(OR 莫队)
- Fragment讲解
- 专题四-指针和数组(上)
- hdu1285(拓扑排序)
- Linux挂载u盘
- c:if 通过${fn:contains(id,'')多条件判断
- iOS release版本
- 擅长排列的小明 II
- C++基础:标准输入输出
- .NET框架-Try-Parse和Tester-Doer