fragment详解
来源:互联网 发布:matlab向量组成矩阵 编辑:程序博客网 时间:2024/06/16 17:56
最近在做项目的时候发现用的activity太多,感觉太过泛滥了,但是用fragment时却让人头疼,不知道从何做起,于是我决定要深趴一下fragment,希望能够让activity和fragment完美的结合在一起。
在这里我要先讲解一下fragment导包的问题,以及导包之后存在的使用的区别,看下图
初识不同版本的fragment
由于app包中的fragment是兼容android3.0(API 11)以上版本的,以下就不会再兼容,如果3.0以下的版本需要fragment怎么办呢?所以这时候v4包的用处就来了,虽然现在市场上3.0以下的版本不多了,但还是有一定的市场的。所以建议用v4包的。以下是V4包和app包的api的主要区别。
v4包:
在导包上-->import android.support.v4.app.FragmentManager
在管理器创建上-->FragmentManager fm=getSupportFragmentManager
在主类中-->Activity extends FragmentActivity
在版本支持上-->android3.0以下版本(3.0以上版本也支持)
app包:
在导包上-->import android.app.FragmentManager
在管理器创建上-->FragmentManager fm=getFragmentManager
在主类中-->Activity extends Activity(因为Activity本身就属于app包中-->android.app.Activity)
在版本支持上-->android3.0以上版本-->不可以在低版本中用!
各位兄台看懂了吗?这就是区别,有时候做个对比能够让自己加深记忆,更好的理解,好了,下面讲解对fragment的具体用法,来体会一下它的独特之处吧。
2.对fragment管理的重要的两个类
2.1 fragmentManager
本人比较喜欢寻根究底,看了源代码后,发现
FragmentManager主要针对的是已经嵌套在activity中的单个fragment对象的操作
FragmentManager执行的如下操作------>主要是用来获取已经存在的fragment,否则在代码中需新建
1.通过findFragmentById()(用于在activity layout中提供一个UI的fragment)或findFragmentByTag()(使用于有或没有UI的fragment)获取activity中存在的fragment---->tag标签经常在java代码中使用,如convertView中的setTag()和getTag()
(如在布局中添加<fragment/>标签,必须为其指定Id或Tag,作为其唯一标识符)
2.将fragment从后台堆栈中弹出(相当于位于顶部的fragment被back后弹出内存),使用popBackStack()-->模拟用户按下back指令
3.使用addOnBackStackChangeListener()注册一个监听后台堆栈变化的监听器listener
以上标明蓝色是FragmentManager最重要的几个方法。
2.2 fragmentTransaction
FragmentTransaction主要针对的是对fragment进行添加,移除,替换操作。看源码
不用看都懂了吧,但是有一点很重要,相对应FragmentManager来说,它没有给出条件,只是提供了一系列的对Fragment操作的API.用处可不小哦。
FragmentTransaction提供的重要API如下
显示:add() replace() show() attach()
隐藏:remove() hide() detach()
3.fragment和activity之间的联系
Fragment:获取它所在的Activity--->可通过getActivity获得,在启动另一个activity中常用,如:
Intent intent=new Intent(getActivity, AnotherActivity);---->需用activity启动另一个activity
startActivity(intent);(但是建议跳转操作应该交给activity来管理,否则就失去了fragment的使用机制了)
Activity:获取它包含的Fragment--->调用Activity关联的FragmentManager的findFragmentById(int id)或findFragmentByTag(String tag)方法获得
4.fragment使用方法
fragment的产生主要是由于在大屏幕或电视等设备上使用app时,由于大屏幕设备空间大,显示一个activity时会浪费很多控件,造成视觉感官不好,因此fragment就应运而生,为了适应大屏幕设备显示activity的问题,fragment有效弥补了剩余空间的浪费,使得在一个大屏幕设备中能够很好的显示两个界面,fragment就像是activity中的一个控件,因为它能够像其他控件一样嵌套在activity中,控制其UI大小,和其他控件没太大区别,又像是一个完整的activity,因为它和activity一样有自己的生命周期,且能够对界面中的事件做出响应。而fragment的生命周期却和activity绑定在一起,跟着activity变化着。
底部导航栏制作(一) :新建一个项目fragmentOne,然后在layout下建立一个xml布局文件fragment_one:
<?xml version="1.0" encoding="utf-8"?><RelativeLayout xmlns:android="http://schemas.android.com/apk/res/android" android:layout_width="match_parent" android:layout_height="match_parent" ><TextView android:layout_width="match_parent" android:layout_height="wrap_content" android:gravity="center_horizontal" android:text="我是第一个fragment" android:textSize="20sp" /></RelativeLayout>
这个文件只有一个textView.现在我们再新建一个fragment_two,复制一份fragment_one再稍作修改即可:
<span style="font-size:12px;"><?xml version="1.0" encoding="utf-8"?><RelativeLayout xmlns:android="http://schemas.android.com/apk/res/android" android:layout_width="match_parent" android:layout_height="match_parent" ><TextView android:layout_width="match_parent" android:layout_height="wrap_content" android:gravity="center_horizontal" android:text="我是fragmentTwo" android:textSize="20sp" /></RelativeLayout></span>
再在fragmentOne写入以下代码,我加入了fragment的完整生命周期方法,等下通过操作看其如何变化
public class FragmentOne extends Fragment {@Overridepublic View onCreateView(LayoutInflater inflater, ViewGroup container,Bundle savedInstanceState) {// TODO Auto-generated method stubLog.i("tedu", "fragmentoneon---createview");return inflater.inflate(R.layout.fragment_one, null);}@Overridepublic void onCreate(Bundle savedInstanceState) {// TODO Auto-generated method stubsuper.onCreate(savedInstanceState);Log.i("tedu", "fragmentone----create");}@Overridepublic void onStart() {// TODO Auto-generated method stubsuper.onStart();Log.i("tedu", "fragmentone----start");}@Overridepublic void onResume() {// TODO Auto-generated method stubsuper.onResume();Log.i("tedu", "fragmentone----resume");}@Overridepublic void onPause() {// TODO Auto-generated method stubsuper.onPause();Log.i("tedu", "fragmentone----pause");}@Overridepublic void onStop() {// TODO Auto-generated method stubsuper.onStop();Log.i("tedu", "fragmentone---stop");}@Overridepublic void onDestroyView() {// TODO Auto-generated method stubsuper.onDestroyView();Log.i("tedu", "fragmentone----destroyview");}@Overridepublic void onAttach(Activity activity) {// TODO Auto-generated method stubsuper.onAttach(activity);Log.i("tedu", "fragmentone------onattach");}@Overridepublic void onDetach() {// TODO Auto-generated method stubsuper.onDetach();Log.i("tedu", "fragmentoneDetach");}}fragmentTwo和fragmentThree就不写了,跟以上的代码一样,稍作修改即可
现在在MainActivity的xml布局文件中插入如下代码:
<RelativeLayout xmlns:android="http://schemas.android.com/apk/res/android" xmlns:tools="http://schemas.android.com/tools" android:layout_width="match_parent" android:layout_height="match_parent" tools:context=".MainActivity" > <FrameLayout android:id="@+id/fl_content" android:layout_width="match_parent" android:layout_height="match_parent" android:layout_above="@+id/rg_bottom" /> <RadioGroup android:id="@+id/rg_bottom" android:layout_width="match_parent" android:layout_height="wrap_content" android:layout_alignParentBottom="true" android:orientation="horizontal" > <RadioButton android:id="@+id/rb_one" android:layout_width="match_parent" android:layout_height="40dp" android:layout_margin="3dp" android:layout_weight="1" android:background="#999999" android:button="@null" android:gravity="center" android:text="one" /> <RadioButton android:id="@+id/rb_two" android:layout_width="match_parent" android:layout_height="40dp" android:layout_margin="3dp" android:layout_weight="1" android:background="#999999" android:button="@null" android:gravity="center" android:text="two" /> <RadioButton android:id="@+id/rb_three" android:layout_width="match_parent" android:layout_height="40dp" android:layout_margin="3dp" android:layout_weight="1" android:background="#999999" android:button="@null" android:gravity="center" android:text="three" /> </RadioGroup></RelativeLayout>
public class MainActivity extends FragmentActivity {private FragmentOne fOne;private FragmentTwo fTwo;private FragmentThree fThree;private Fragment currentFragment;private RadioGroup rghome;@Overrideprotected void onCreate(Bundle savedInstanceState) {super.onCreate(savedInstanceState);setContentView(R.layout.activity_main);rghome=(RadioGroup) findViewById(R.id.rg_bottom);setDefaultFragment();setListeners();}private void setDefaultFragment() {FragmentTransaction transaction = getSupportFragmentManager().beginTransaction();fOne = new FragmentOne();transaction.add(R.id.fl_content, fOne);currentFragment = fOne;transaction.commit();}public void setListeners() {rghome.setOnCheckedChangeListener(new RadioGroup.OnCheckedChangeListener() { public void onCheckedChanged(RadioGroup arg0, int checkedId) { // 开启Fragment事务 switch (checkedId) { case R.id.rb_one: if(fOne==null) { fOne = new FragmentOne(); } switchFragment(fOne); break; case R.id.rb_two: if(fTwo==null) { fTwo = new FragmentTwo(); } switchFragment(fTwo); break; case R.id.rb_three: if(fThree==null) { fThree = new FragmentThree(); } switchFragment(fThree); break; } }});}private void switchFragment(Fragment fragment) {// 判断当前显示的Fragment是不是切换的fragmentif (currentFragment != fragment) {// 判断切换的fragment是否已经添加过if (!fragment.isAdded()) {// 如果没有添加,先把当前的fragment隐藏,把切换的fragment加上getSupportFragmentManager().beginTransaction().hide(currentFragment).add(R.id.fl_content, fragment).commit();} else {// 如果已经添加过,则先把当前的fragment隐藏,把切换的fragment隐藏起来getSupportFragmentManager().beginTransaction().hide(currentFragment).show(fragment).commit();}currentFragment = fragment;}}
观察第16行,我在这里添加了一个setDefaultFragment的方法,我将fragmentOne设置成默认的布局,并将其传入当前的对象currentFragment,在oncreate的时候首次进行加载,当对一个fragment进行点击的时候,我将对应的fragment传入第52行的switchFragment方法中,在55行的switchFragment方法中,设置了一个fragment参数,方便将传入的值向上转型为fragment,因为传入的值是不确定的,这里利用了多态。在switchFragment方法中,会先判断当前的传入的fragment是否是传入的fragment,如果不是,会再判断其是否已经添加进transaction事务中,调用isAdd()即可,如果没有则创建一个transaction,将当前的fragment隐藏再将传入的fragment添加起来,如果添加了,则直接隐藏当前fragment,再显示传入的fragment即可。
看下图演示
当对每个fragment第一次点击的时候,会执行每个fragment的生命周期方法,当第二次点击的时候就不再发生变化,因为fragment布局已经都加入到了mainActivity的布局中,只需 show()和hide()方法即可。在程序运行中,其实add方法只运行一次,只有当所有的fragment加入到了transaction之后,以后执行的就只有transaction的hide()和show()方法,因为fragment就如同一个个布局叠加在一起,相当于其他布局中的visible属性。这是对fragment的高效率的用法。、
底部导航栏制作(二):第二种方式使用transaction的replace方法,而不是add()
只需改变以下代码即可
private void setDefaultFragment() {FragmentTransaction transaction = getSupportFragmentManager().beginTransaction();fOne = new FragmentOne();transaction.replace(R.id.fl_content, fOne);transaction.commit();}public void setListeners() {rghome.setOnCheckedChangeListener(new RadioGroup.OnCheckedChangeListener() { public void onCheckedChanged(RadioGroup arg0, int checkedId) { FragmentManager ff=getSupportFragmentManager(); FragmentTransaction transaction2 =ff.beginTransaction(); switch (checkedId) { case R.id.rb_one: if(fOne==null) { fOne = new FragmentOne(); } transaction2.replace(R.id.fl_content, fOne); transaction2.commit(); break; case R.id.rb_two: if(fTwo==null) { fTwo = new FragmentTwo(); } transaction2.replace(R.id.fl_content, fTwo); transaction2.commit(); break; case R.id.rb_three: if(fThree==null) { fThree = new FragmentThree(); } transaction2.replace(R.id.fl_content, fThree); transaction2.commit(); break; } }});调用了transaction事务的replace方法,这样看起来显得更加简单,但是会有一个问题,看如下演示
如右图,当点击two的时候,第一个fragmentone会先执行pause-stop-destroyview销毁,再创建fragmenttwo,当点击three时,fragmenttwo即执行同样的生命周期方法销毁view再点击时又会再重新创建,即repalce方法相当于执行了,remove()和add()方法。所以相对来说,用add对程序更加优化。
对于fragment调用add的时候出现的叠加问题的解决
1.在fragment的布局文件中将fragment根节点的背景颜色改为白色(不推荐)--->这个简单你们可以自行尝试
2.使用transaction的show()和hide()的方法--->这些方法相当于其他控件的visible,看源码
Hides an existing fragment. This is only relevant for fragments whose views have been added to a container, as this will cause the view to be hidden.
隐藏的是已经加入containaer容器的fragments,而fragment其实还在容器中。相对于remove( )
Remove an existing fragment. If it was added to a container, its view is also removed from that container.
remove的话是从container容器中将fragment移除,等于销毁了。
- Fragment详解
- Fragment详解
- Fragment 详解
- Fragment详解
- Fragment详解
- Fragment详解
- Fragment详解
- Fragment详解
- Fragment详解
- Fragment详解
- Fragment详解
- Fragment详解
- Fragment详解
- Fragment 详解
- fragment详解
- Fragment详解
- Fragment详解
- Fragment详解
- C语言内存布局
- iOS复杂动画之抽丝剥茧(Objective-C & Swift)
- 转一个quaternion基础的
- 【转】Android:LinearLayout布局中Layout_weight的深刻理解
- ConcurrentHashMap使用要点
- fragment详解
- 非常轻量级的ImageLoader
- this 指针
- poj 1019Number Sequence(数学 巧妙~~~)
- wpf 颜色渐变的圆
- java特性之自动拆装箱
- Map、Set、List部分总结
- == 与 equals的区别
- php中self 、parent的用法