Android杂谈(7)搞一搞Fragment+官方API底部导航制作
来源:互联网 发布:js时间戳有什么作用 编辑:程序博客网 时间:2024/04/30 03:54
转载请注意:http://blog.csdn.net/wjzj000/article/details/51879798
本菜GitHub上开源了一个小的Android项目,感兴趣的看官大大们可以star下:
https://github.com/zhiaixinyang/MyFirstApp
进入暑假,啥也不想搞。所以就抱着几本书敲敲东西。
首先记录一下Fragment的一些用法和问题:
Fragment的生命周期:
正常的周期顺序是:
onAttach -> onCreate -> onCreateView -> onActivityCreated -> onStart -> onResume -> onPause -> onStop -> onDistroyView -> onDistroy -> onDetach
特别来看一下Fragment比Activity多的几个方法的用处。
onAttach(Activity):当Fragment与Activity发生关联时调用。
onCreateView(LayoutInflater, ViewGroup,Bundle):创建该Fragment的视图
onActivityCreated(Bundle):当Activity的onCreate方法返回时调用
onDestoryView():与onCreateView想对应,当该Fragment的视图被移除时调用
onDetach():与onAttach相对应,当Fragment与Activity关联被取消时调用
经测试,除了onCreateView方法,其他的所有方法如果被重写了,我们都得调用它的父类此方法。
1. 当一个fragment被创建的时候,它会经历以下状态.
- onAttach()
- onCreate()
- onCreateView()
- onActivityCreated()
2. 当这个fragment对用户可见的时候,它会经历以下状态。
- onStart()
- onResume()
3. 当这个fragment进入“后台模式”的时候,它会经历以下状态。
- onPause()
- onStop()
4. 当这个fragment被销毁了(或者持有它的activity被销毁了),它会经历以下状态。
- onPause()
- onStop()
- onDestroyView()
- onDestroy()
- onDetach()
静态使用
静态的使用还是比较简单的,只需要在activity的布局中写几个需要用到的<fragment>标签,然后在标签中android:name=""写上自己的Fragment类的全称即可。
而具体的代码在Fragment中写就好。简易的流程就是:继承Fragment,重写onCreateView方法,通过LayoutInflater加载fragment的布局,拿到返回值的View然后return。那么这个Fragment就算写好了。因为我们在activity布局中声明了这个Fragment类,所以在对应的Activity类中我们并不需要做些什么。只需要在onCreate方法中通过setContent把activity的布局文件加载进去就好。其他的业务逻辑在Fragment类中处理。那么这个我们的Fragment其实就可以当做比较复杂的控件来使用了。
(动态使用方式下文有补充)
不过,今天在敲Fragment的时候,遇到了尴尬的小情况,是关于v4包和app包下的fragment的区别,实际上之前从来没深究过这个问题,今天特地记下来。
首先我是习惯性在fragment类中继承v4下的Fragment类,然后在布局中添加相关fragment标签,可是在运行时报出了这样的错误Binary XML file line #8: Error inflating class fragment并提示说that is not a Fragment。
瞎捣鼓了很久才发现是v4和app捣的鬼,当把fragment中的继承换为app包下的Framgent后,程序可以正常运行。
这就促使了我去了解一下这俩个包下的Fragment的区别。
关于这两个Fragment使用<fragment>标签的问题
(1)app.fragment和v4.fragment都是可以使用<fragment>标签的:
如果是app.fragment,那么加载fragment的activity则没有什么特殊的地方继承Activity即可。
(2)当v4.fragment使用<fragment>标签的时候就需要注意:
那么加载fragment的activity必须继承FragmentActivity,否则就会报错。
其他的不同点也有,比如最常见的就是兼容问题.....(本彩笔觉得,兼容这个年代不是问题了吧...)
app包中的fragment,是在3.0之后才有的。
android.support.v4.app.Fragment:可以兼容到1.6的版本。
(2016年8月11补充基础使用)
不得不承认自己真的很菜。关于Fragment的动态加载,一上午都在纠结一个问题。实际上问题出在自身基础不熟练。
在Activity中的layout里动态添加一个Fragment时,layout的里的空间一直写的事<fragment>所以一直报错(这个标签用于静态加载时)。换成<xxxxxLayout>就行了(一般使用FrameLayout),也就是用正常的布局控件,而不是fragment控件。
虽然浪费了很多时间,但是有一个关setArguments(bundle)的收获。
关于动态加载的用法:
FragmentManager fm = getFragmentManager();fm.beginTransaction().add(R.id.test_frag, new FragmentTest()).commit();
这里的R.id.test_frag 其实就是activity布局中的一个布局控件的id。也就是你想让Fragment出现的地方。
一般使用FrameLayout。
更多的时候我们使用的是替换方法:fm.beginTransaction().replace的方式替换Fragment。用法依然同上,第一个参数是id,第二个是Fragment
类。然后就是调用commit提交方法。一个简单的应用,我们可以通过这种方式制作底部导航栏...当然现阶段有很多
解决方案可以做底部导航栏。这里只是一个思路...
(后文有补充,关于使用官方API做底部导航)
关于setArguments(bundle):
这个newInstance是系统提供的静态工厂模式方法。这里的效果是在使用Fragment时通过静态的newInstance方法初始化Fragment,并且传入自己想要传递的值。那么为什么不适用new Fragment的方法在构造方法中传值呢?
public static Fragment newInstance(String text){ Bundle bundle=new Bundle(); bundle.putString(ARGUMENT,text); FragmentTest fragmentTest=new FragmentTest(); fragmentTest.setArguments(bundle); return fragmentTest;}
在动态加载的时候通过newInstance(String text)加载Fragment并且传入想更新UI的数据,在onCreateView内可以随意取出。如果通过构造方法传,是拿不到值的,因为源码中Fragment的启动方法是使用的无参构造方法,所以我们在构造方法中传值其实并没有被调用。
提供静态工厂而不是使用默认构造函数的原因:
fragmnet经常会被销毁重新实例化,Android framework只会调用fragment无参的构造函数。在系统自动实例化fragment的过程中,你没有办法干预。一些需要外部传入的参数来决定的初始化就没有办法完成。使用静态工厂方法,将外部传入的参数可以通过Fragment.setArgument保存在它自己身上,这样我们可以在Fragment.onCreate(...)调用的时候将这些参数取出来。
2016年12月6日补充-官方API实现底部导航:
首先是activity的布局文件:
<?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/frg_content" android:layout_width="match_parent" android:layout_height="0dp" android:layout_weight="1"/> <!--必须写,官方要求,而且id写法必须是@android:id/tabcontent,写法很死,id名都得固定--> <android.support.v4.app.FragmentTabHost android:id="@android:id/tabhost" android:layout_width="match_parent" android:background="@color/white" android:layout_height="wrap_content"> <FrameLayout android:id="@android:id/tabcontent" android:layout_width="0dp" android:layout_height="0dp" /> </android.support.v4.app.FragmentTabHost></LinearLayout>
此处写法比较蛋疼,就得这么写,而且最下面的那个<FrameLayout>没什么卵用,但是不写还不行,而且id还必须那么写...而且宽和高不整成0,它还会把真正的<FrameLayout>给挤掉...回到Actvity之中:
private FragmentTabHost mTabHost; private LayoutInflater layoutInflater; @Override protected void onCreate(Bundle savedInstanceState) { super.onCreate(savedInstanceState); setContentView(R.layout.activity_main); layoutInflater=LayoutInflater.from(this); /** * 这里可以这么理解: * TabHost就是底部导航栏的长条集合,而它的内部类TabSpec就是具体的按钮 */ mTabHost = (FragmentTabHost)findViewById(android.R.id.tabhost); mTabHost.setup(this, getSupportFragmentManager(), R.id.realtabcontent); //这里构造方法传递的值并不会对实际效果产生影响,其实和下文的TabHost.TabSpec重名 TabHost.TabSpec one=mTabHost.newTabSpec("one"); /** * R.layout.fth_tabspec_item * 就是底部按钮的布局文件,自己想要啥样的就整成啥样的。 * 我这里是一个ImageView和一个TextView竖直排列 */ View oneView= layoutInflater.inflate(R.layout.fth_tabspec_item,null); ImageView iv= (ImageView) oneView.findViewById(R.id.iv_fth); //这里是一个图片选择selector iv.setBackgroundResource(R.drawable.tab_icon_select); TextView tv= (TextView) oneView.findViewById(R.id.tv_fth); tv.setText("One!"); one.setIndicator(oneView); TabHost.TabSpec two=mTabHost.newTabSpec("one"); View twoView= layoutInflater.inflate(R.layout.fth_tabspec_item,null); ImageView iv_= (ImageView) twoView.findViewById(R.id.iv_fth); iv_.setBackgroundResource(R.drawable.tab_icon_select); TextView tv_= (TextView) twoView.findViewById(R.id.tv_fth); tv_.setText("Two!"); two.setIndicator(twoView); //给导航按钮绑定你所要跳转的Fragment,具体有啥实现效果直接在Fragment中写就好 mTabHost.addTab(one,OneFragment.class, null); mTabHost.addTab(two,ThreeFragment.class, null); }
这里边涉及到的相关文件源码:
R.drawable.tab_icon_select:
(相关用法,参看http://blog.csdn.net/wjzj000/article/details/50937031)
<?xml version="1.0" encoding="utf-8"?><selector xmlns:android="http://schemas.android.com/apk/res/android"> <!-- btn_ok就是一个图片 --> <item android:state_focused="true" android:drawable="@drawable/btn_ok"/> <item android:state_selected="true" android:drawable="@drawable/btn_ok"/> <item android:drawable="@drawable/ic_launcher"/></selector>
R.layout.fth_tabspec_item:<?xml version="1.0" encoding="utf-8"?><LinearLayout xmlns:android="http://schemas.android.com/apk/res/android" android:orientation="vertical" android:layout_width="wrap_content" android:gravity="center" android:layout_height="wrap_content"> <ImageView android:id="@+id/iv_fth" android:layout_width="40dp" android:layout_height="40dp" /> <TextView android:id="@+id/tv_fth" android:layout_width="wrap_content" android:textColor="@color/text_color_select" android:layout_height="wrap_content" /></LinearLayout>
结合布局文件和最终效果比较好理解。
- Android杂谈(7)搞一搞Fragment+官方API底部导航制作
- Android Fragment实现底部导航
- Android 底部导航栏的使用 fragment
- android基于Fragment实现底部导航切换
- Android 底部导航栏界面(Fragment)
- Android底部导航栏—RadioButton+Fragment
- Android底部导航栏—FragmentTabHost+Fragment
- xamarin android Fragment实现底部导航栏
- android 创建底部导航栏 (radiogroup+fragment)
- Android学习--底部导航Fragment填充
- android 底部导航栏 ViewPager+RadioGroup+Fragment
- Android底部凸出导航,Fragment互相嵌套
- xamarin android Fragment实现底部导航栏
- Android使用Fragment仿微信底部导航栏
- android TabHost制作底部导航栏
- Android底部导航栏界面(Fragment中嵌套Fragment)
- Fragment实现底部导航
- Fragment底部导航
- wind下compser安装配置
- 常用网站
- ScrollView嵌套ListView冲突问题的最优解决方案
- Meeting Rooms II
- 安装storm1.0.1后worker启动不起来 nimbus.log中显示executor循环not alive
- Android杂谈(7)搞一搞Fragment+官方API底部导航制作
- JSON拼接字符串
- schedule调度相关
- 基于电商的推荐系统看用户行为分析
- 2016Python学习笔记之一
- jstat使用方法
- ffmpeg处理RTMP流媒体的命令大全
- linux下安装nginx详细教程
- Camera的onPreviewFrame回调方法中图片帧数据data最后显示出现错位拼接的bug