内容简介:拥有生命周期,含有视图,可视可交互的界面 。后者先创建,前者再销毁注
拥有生命周期,含有视图,可视可交互的界面 。 本文源码可见此处
1.Fragment和Activity生命周期的测试 --- Fragment和Activity生命周期 --- Fragment和Fragment切换时生命周期 --- Fragment与嵌套的子Fragment的生命周期 2.Fragment和Activity或其他Fragment数据传递 --- Activity --> Fragment --- Fragment --> Activity --- Fragment --> Fragment 3.Fragment和ViewPager的结合以及懒加载的实现 4.Fragment中如何载入子Fragment 复制代码
一、生命周期
0.基本的生命周期方法一览
setUserVisibleHint(boolean isVisibleToUser) |--- 第一个回调函数(多Fragment时),isVisibleToUser用户是否可见 onCreate(Bundle savedInstanceState): |--- Fragment初始化时 onAttach(Context context): |--- Fragment与Context已经绑定时 View onCreateView(LayoutInflater inflater, ViewGroup container,Bundle savedInstanceState) |--- 创建Fragment的布局时(加载布局和findViewById,不建议执行耗时的操作) onViewCreated(View view, @Nullable Bundle savedInstanceState) |--- 当视图创建完成 onActivityCreated( Bundle savedInstanceState) |--- 与Fragment绑定的Activity的onCreate方法已经执行完成并返回(可以进行与Activity交互的UI操作) onViewStateRestored(Bundle savedInstanceState) |--- 通知fragment,该视图层已保存 onStart() |--- 界面已经可见 onAttachFragment() |--- 有子Fragment被添加时回调 onResume() |--- 界面已经可交互 onPause() |--- 界面已经可见不可交互 onStop() |--- 界面不可见 onSaveInstanceState(Bundle outState) |--- 保存对象状态 onDestroyView() |--- 销毁与Fragment有关的视图,但未与Activity解除绑定 onDestroy() |--- 销毁Fragment onDetach() |--- 解除与Activity 复制代码
1、当打开Activity时Fragment的生命周期回调:
2019-04-26 16:53:27.702: LifeCycleActivity--onCreate: 2019-04-26 16:53:27.704: Fragment -卍卍卍卍卍卍卍- onAttach: 2019-04-26 16:53:27.704: Fragment -卍卍卍卍卍卍卍- onCreate: 2019-04-26 16:53:27.704: Fragment -卍卍卍卍卍卍卍- onCreateView: 2019-04-26 16:53:27.711: Fragment -卍卍卍卍卍卍卍- onViewCreated: 2019-04-26 16:53:27.711: Fragment -卍卍卍卍卍卍卍- onActivityCreated: 2019-04-26 16:53:27.711: Fragment -卍卍卍卍卍卍卍- onViewStateRestored: 2019-04-26 16:53:27.714: LifeCycleActivity--onStart: 2019-04-26 16:53:27.715: Fragment -卍卍卍卍卍卍卍- onStart: 2019-04-26 16:53:27.720: LifeCycleActivity--onResume: 2019-04-26 16:53:27.720: Fragment -卍卍卍卍卍卍卍- onResume: 复制代码
2.当跳转到其他Activity时
2019-04-26 17:35:30.611: Fragment -卍卍卍卍卍卍卍- onPause: 2019-04-26 17:35:30.611: LifeCycleActivity--onPause: 2019-04-26 17:35:31.342: Fragment -卍卍卍卍卍卍卍- onSaveInstanceState: 2019-04-26 17:35:31.344: LifeCycleActivity--onSaveInstanceState: 2019-04-26 17:35:31.345: Fragment -卍卍卍卍卍卍卍- onStop: 2019-04-26 17:35:31.346: LifeCycleActivity--onStop: 复制代码
3.跳转后返回时
2019-04-26 17:41:28.254: LifeCycleActivity--onRestart: 2019-04-26 17:41:28.255: LifeCycleActivity--onStart: 2019-04-26 17:41:28.256: Fragment -卍卍卍卍卍卍卍- onStart: 2019-04-26 17:41:28.258: LifeCycleActivity--onResume: 2019-04-26 17:41:28.258: Fragment -卍卍卍卍卍卍卍- onResume: 复制代码
4.退出该Activity
2019-04-26 18:12:25.328: Fragment -卍卍卍卍卍卍卍- onPause: 2019-04-26 18:12:25.328: LifeCycleActivity--onPause: 2019-04-26 18:12:25.864: Fragment -卍卍卍卍卍卍卍- onStop: 2019-04-26 18:12:25.865: LifeCycleActivity--onStop: 2019-04-26 18:12:25.865: Fragment -卍卍卍卍卍卍卍- onDestroyView: 2019-04-26 18:12:25.867: Fragment -卍卍卍卍卍卍卍- onDestroy: 2019-04-26 18:12:25.867: Fragment -卍卍卍卍卍卍卍- onDetach: 2019-04-26 18:12:25.868: LifeCycleActivity--onDestroy: 复制代码
5.Fragment被替换时的生命周期
后者先创建,前者再销毁
2019-04-26 20:10:20.095 : Fragment -卍卍卍卍卍卍卍- onAttach: 2019-04-26 20:10:20.095 : Fragment -卍卍卍卍卍卍卍- onCreate: 2019-04-26 20:10:20.095 : Fragment -卍卍卍卍卍卍卍- onCreateView: 2019-04-26 20:10:20.112 : Fragment -卍卍卍卍卍卍卍- onViewCreated: 2019-04-26 20:10:20.112 : Fragment -卍卍卍卍卍卍卍- onActivityCreated: 2019-04-26 20:10:20.113 : Fragment -卍卍卍卍卍卍卍- onViewStateRestored: 2019-04-26 20:10:20.113 : Fragment -卍卍卍卍卍卍卍- onStart: 2019-04-26 20:10:20.115 : Fragment -卍卍卍卍卍卍卍- onResume: 2019-04-26 20:10:20.115 : Fragment -卍卍卍卍卍卍卍- onPause: 2019-04-26 20:10:20.115 : Fragment -卍卍卍卍卍卍卍- onStop: 2019-04-26 20:10:20.116 : Fragment -卍卍卍卍卍卍卍- onDestroyView: 2019-04-26 20:10:20.118 : Fragment -卍卍卍卍卍卍卍- onDestroy: 2019-04-26 20:10:20.118 : Fragment -卍卍卍卍卍卍卍- onDetach: 复制代码
6.嵌套Fragment的生命周期
注 卍卍卍卍卍卍卍
表示父, ☯☯☯☯☯☯☯☯表示子
---->[打开时]-----------先父后子,注意在onStart之后子Fragment开始attach--------------- 2019-04-27 08:36:44.332 : Fragment -卍卍卍卍卍卍卍- onAttach: 2019-04-27 08:36:44.332 : Fragment -卍卍卍卍卍卍卍- onCreate: 2019-04-27 08:36:44.346 : Fragment -卍卍卍卍卍卍卍- onCreateView: 2019-04-27 08:36:44.351 : Fragment -卍卍卍卍卍卍卍- onViewCreated: 2019-04-27 08:36:44.351 : Fragment -卍卍卍卍卍卍卍- onActivityCreated: 2019-04-27 08:36:44.351 : Fragment -卍卍卍卍卍卍卍- onViewStateRestored: 2019-04-27 08:36:44.352 : Fragment -卍卍卍卍卍卍卍- onStart: 2019-04-27 08:36:44.353 : Fragment -☯☯☯☯☯☯☯☯- onAttach: 2019-04-27 08:36:44.353 : Fragment -卍卍卍卍卍卍卍- onAttachFragment: <--- 注意这里 2019-04-27 08:36:44.353 : Fragment -☯☯☯☯☯☯☯☯- onCreate: 2019-04-27 08:36:44.354 : Fragment -☯☯☯☯☯☯☯☯- onCreateView: 2019-04-27 08:36:44.358 : Fragment -☯☯☯☯☯☯☯☯- onViewCreated: 2019-04-27 08:36:44.358 : Fragment -☯☯☯☯☯☯☯☯- onActivityCreated: 2019-04-27 08:36:44.358 : Fragment -☯☯☯☯☯☯☯☯- onViewStateRestored: 2019-04-27 08:36:44.358 : Fragment -☯☯☯☯☯☯☯☯- onStart: 2019-04-27 08:36:44.365 : Fragment -卍卍卍卍卍卍卍- onResume: 2019-04-27 08:36:44.365 : Fragment -☯☯☯☯☯☯☯☯- onResume: ---->[退出时]-----------先子后父交替回调--------------- 2019-04-27 08:44:13.697 : Fragment -☯☯☯☯☯☯☯☯- onPause: 2019-04-27 08:44:13.698 : Fragment -卍卍卍卍卍卍卍- onPause: 2019-04-27 08:44:14.639 : Fragment -☯☯☯☯☯☯☯☯- onStop: 2019-04-27 08:44:14.639 : Fragment -卍卍卍卍卍卍卍- onStop: 2019-04-27 08:44:14.654 : Fragment -☯☯☯☯☯☯☯☯- onDestroyView: 2019-04-27 08:44:14.654 : Fragment -卍卍卍卍卍卍卍- onDestroyView: 2019-04-27 08:44:14.655 : Fragment -☯☯☯☯☯☯☯☯- onDestroy: 2019-04-27 08:44:14.655 : Fragment -☯☯☯☯☯☯☯☯- onDetach: 2019-04-27 08:44:14.655 : Fragment -卍卍卍卍卍卍卍- onDestroy: 2019-04-27 08:44:14.655 : Fragment -卍卍卍卍卍卍卍- onDetach: 复制代码
二、数据传递
1. Activity-->Fragment
实现:在Activity传入颜色数据,在Fragment中接收数据并使用
---->[在Activity中设置Fragment的参数]----------------------------------- FragmentManager fm = getFragmentManager();//1.获取FragmentManager FragmentTransaction ft = fm.beginTransaction();//2.fm开启事务 Bundle bundle = new Bundle();//创建Bundle对象 bundle.putString("data", "#ff0000");//为bundle赋值 BoxFragment boxFragment = new BoxFragment(); boxFragment.setArguments(bundle);//为Fragment设置Arguments //3.动态添加 (控件id,fragment对象,tag) ft.add(R.id.fl_fragmemt_content, new ResultFragment()); ft.commit();//4.提交事务 ---->[在BoxFragment中读取参数并使用]----------------------------------- TextView txt = view.findViewById(R.id.id_tv_txt); Bundle bundle = getArguments(); if (bundle != null) { String result = bundle.getString("color"); view.setBackgroundColor(Color.parseColor(result)); txt.setText(result); } 复制代码
这可以稍微改进一下:将Bundle在Fragment中创建,通过一个静态方法+入参创建Fragment
---->[在BoxFragment中添加静态方法]----------------------------------- public static BoxFragment newInstance(String color) { BoxFragment fragment = new BoxFragment(); Bundle bundle = new Bundle(); bundle.putString("color", color); fragment.setArguments(bundle); return fragment; } ---->[在Activity中创建对象]----------------------------------- BoxFragment boxFragment = BoxFragment.newInstance("#238AF8") 复制代码
好处在于方便创建Fragment,比如加个红色:
BoxFragment radFragment = BoxFragment.newInstance("#ff0000") 复制代码
2. Fragment-->Activity
点击Fragment内的View,Fragment将颜色值传给Activity
- 方式一、通过回调
---->[在BoxFragment中添加回调接口]----------------------------------- public interface OnDataSend { void send(String data); } private OnDataSend mOnDataSend; public void setmOnDataSend(OnDataSend mOnDataSend) { this.mOnDataSend = mOnDataSend; } ---->[在BoxFragment#onViewCreated触发回调]----------------------------------- txt.setOnClickListener(v -> { if (mOnDataSend != null) { mOnDataSend.send(txt.getText().toString().toUpperCase()); } }); ---->[在Activity中设置回调]----------------------------------- radFragment.setmOnDataSend { id_tv_result.text = it } 复制代码
- 方式二、向上转型,获取宿主对象并调用方法
---->[在Activity中添加公共方法]----------------------------------- fun setData(s: String) { id_tv_result.text = s } ---->[在BoxFragment#onViewCreated获取宿主对象并调用方法]----------- txt.setOnClickListener(v -> {//这里强转最好加个instanceof判断 LifeCycleActivity activity = (LifeCycleActivity) getActivity(); activity.setData(txt.getText().toString().toUpperCase()); }); 复制代码
挺方便的,不过这对宿主Activity增加了负担,不须强转成宿主类型,感觉有点狭隘
感觉新建一个接口用来规定数据传输的方法,应该会好一些,就像正规军和游击队吧...
//数据传送的接口(当然你可以定义很多接口,这里只举个例子) public interface IBoxSender { void setData(String data); } ---->[在Activity实现接口]----------------------------------- class LifeCycleActivity : AppCompatActivity(), IBoxSender { ... override fun setData(s: String) { id_tv_result.text = s } } ---->[在BoxFragment#onViewCreated获取宿主对象并调用方法]----------- txt.setOnClickListener(v -> {//这里强转最好加个instanceof判断 IBoxSender sender = (IBoxSender) getActivity(); sender.setData(txt.getText().toString().toUpperCase()); }); //从我个人审美来说,这样似乎更优雅一点 复制代码
当然你也可以将控件直接传给Fragment,但感觉太无聊了,就不说了
3.Fragment-->Fragment
红色Fragment在点击时,将自己的颜色值传送给蓝色Fragment,蓝色Fragment接收后变色
很容易想到分两步:红色Fragment --> Activity , Activity --> 蓝色Fragment
//数据传送的接口 public interface IBoxSender { void setData(String data); void update(String color); //增加接口 } ---->[在Activity实现接口方法]----------------------------------- override fun update(color: String) { fragmentManager.beginTransaction() .replace(R.id.fl_title, BoxFragment.newInstance(color)) .commit() } ---->[在BoxFragment#onViewCreated获取宿主对象并调用方法]----------- txt.setOnClickListener(v -> {//这里强转最好加个instanceof判断 IBoxSender sender = (IBoxSender) getActivity(); sender.update(txt.getText().toString()); }); 复制代码
4.Fragment可以写构造函数传入参数吗?
这是曾经让我疑惑的一点:构造函数入参来传参不是挺好的吗?但是:
貌似AS 不给我们用构造,需要通过 Fragment#setArguments(Bundle)
来传参
如果我任性,偏要用呢?----虽然画红线但是还是运行还是能跑起来的,效果也没有差别, 于是乎,问题来了: 为什么谷歌的大佬不推荐我们在Fragment中使用构造函数呢?
|--- 在旋转屏幕时:Fragment将面临 销毁+重建 ,但测试中Fragment并没有什么变化 |--- 重建的Fragment是系统帮我们做的,那它怎么还原刚才的参数呢(颜色)?一个词 :Bundle |--- 下面是Fragment中创建ragment静态方法,其中用反射实例化了无参构造,并将配置参数进行还原 |--- 所以为什么不能自定义Fragment的构造函数不言而喻:Fragment销毁+重建只会使用无参构造 public static Fragment instantiate(Context context, String fname) { return instantiate(context, fname, null); } public static Fragment instantiate(Context context, String fname, @Nullable Bundle arg) try { Class<?> clazz = sClassMap.get(fname); if (clazz == null) { // Class not found in the cache, see if it's real, and try to add it clazz = context.getClassLoader().loadClass(fname); if (!Fragment.class.isAssignableFrom(clazz)) { throw new InstantiationException("Trying to instantiate a class " + f + " that is not a Fragment", new ClassCastException()); } sClassMap.put(fname, clazz); } Fragment f = (Fragment) clazz.getConstructor().newInstance(); <--- 注意这里用的是无参构造创建f对象 if (args != null) { <--- 当Binder对象非空时,会将args再给f对象,也就还原了配置 args.setClassLoader(f.getClass().getClassLoader()); f.setArguments(args); } return f; } catch (ClassNotFoundException e) { ..... } } 复制代码
你可以试一下:使用Fragment一参构造,然后转屏时,程序会崩掉,所以咱们还是别任性...
三、Fragment与ViewPager的爱恨情仇
1.最简单的Fragment + ViewPager
public class ViewPagerActivity extends AppCompatActivity { @Override protected void onCreate(@Nullable Bundle savedInstanceState) { super.onCreate(savedInstanceState); setContentView(R.layout.activity_viewpager); ViewPager viewPager = findViewById(R.id.id_vp); //颜色数组 String[] colors = new String[]{"#F73815", "#FAA43E", "#FCE73C", "#51F81E", "#1E94F8", "#8CE9F4", "#B24DF4"}; //详情数组 String[] info = new String[]{"红", "橙", "黄", "绿", "蓝", "靛", "紫"}; viewPager.setAdapter(new FragmentPagerAdapter(getSupportFragmentManager()) {//设置FragmentPagerAdapter @Override public Fragment getItem(int position) { return BoxFragment.newInstance(colors[position],info[position]); } @Override public int getCount() { return colors.length; } }); } } 复制代码
2.滑动时Fragment的生命周期回调
-
打开时
isVisibleToUser
出现了,而且是最先调用的,一开始是红色 isVisibleToUser= true
总的来说就是生成了红色和黄色两个Fragment并对两者其进行了初始化
2019-04-26 23:12:59.444 - isVisibleToUser: 红---false 2019-04-26 23:12:59.444 - isVisibleToUser: 橙---false 2019-04-26 23:12:59.444 - isVisibleToUser: 红---true 2019-04-26 23:12:59.446 - onAttach: 红 2019-04-26 23:12:59.446 - onCreate: 红 2019-04-26 23:12:59.446 - onAttach: 橙 2019-04-26 23:12:59.446 - onCreate: 橙 2019-04-26 23:12:59.447 - onCreateView: 红 2019-04-26 23:12:59.455 - onViewCreated: 红 2019-04-26 23:12:59.456 - onActivityCreated: 红 2019-04-26 23:12:59.456 - onViewStateRestored: 红 2019-04-26 23:12:59.456 - onStart: 红 2019-04-26 23:12:59.456 - onResume: 红 2019-04-26 23:12:59.457 - onCreateView: 橙 2019-04-26 23:12:59.463 - onViewCreated: 橙 2019-04-26 23:12:59.463 - onActivityCreated: 橙 2019-04-26 23:12:59.463 - onViewStateRestored: 橙 2019-04-26 23:12:59.464 - onStart: 橙 2019-04-26 23:12:59.464 - onResume: 橙 复制代码
-
滑到下一屏()橙色
橙色和用户见面了,所以橙色的 isVisibleToUser= true
这时对黄色Fragment(即下一页)进行了初始化,俗称预加载
2019-04-26 23:16:53.738 - isVisibleToUser: 黄---false 2019-04-26 23:16:53.738 - isVisibleToUser: 红---false 2019-04-26 23:16:53.738 - isVisibleToUser: 橙---true 2019-04-26 23:16:53.739 - onAttach: 黄 2019-04-26 23:16:53.740 - onCreate: 黄 2019-04-26 23:16:53.743 - onCreateView: 黄 2019-04-26 23:16:53.766 - onViewCreated: 黄 2019-04-26 23:16:53.767 - onActivityCreated: 黄 2019-04-26 23:16:53.767 - onViewStateRestored: 黄 2019-04-26 23:16:53.767 - onStart: 黄 2019-04-26 23:16:53.767 - onResume: 黄 复制代码
-
滑到下一屏(黄色)
黄色和用户见面了,所以黄色的 isVisibleToUser= true
红色(上上页)销毁了,绿色(下一页)进行初始化
2019-04-26 23:19:38.122 - isVisibleToUser: 绿---false 2019-04-26 23:19:38.123 - isVisibleToUser: 橙---false 2019-04-26 23:19:38.123 - isVisibleToUser: 黄---true 2019-04-26 23:19:38.124 - onAttach: 绿 2019-04-26 23:19:38.125 - onCreate: 绿 2019-04-26 23:19:38.129 - onPause: 红 2019-04-26 23:19:38.130 - onStop: 红 2019-04-26 23:19:38.132 - onDestroyView: 红 2019-04-26 23:19:38.140 - onCreateView: 绿 2019-04-26 23:19:38.154 - onViewCreated: 绿 2019-04-26 23:19:38.155 - onActivityCreated: 绿 2019-04-26 23:19:38.155 - onViewStateRestored: 绿 2019-04-26 23:19:38.155 - onStart: 绿 2019-04-26 23:19:38.156 - onResume: 绿 复制代码
之后都是相似的,当前页的上上页(如果有的话)会被销毁,下一页(如果有的话)会被初始化到onResume
3.懒加载的实现
也就是不想要预加载,毕竟有些时候不想提前为以后的消耗买单
- 方法一、针对Fragment,让其不要加载下一页数据(
但Fragment还是会创建的
)
private boolean initialization; // 界面是否已初始化完毕 private boolean isVisibleToUser; // 是否对用户可见 @Override public void setUserVisibleHint(boolean isVisibleToUser) { super.setUserVisibleHint(isVisibleToUser); this.isVisibleToUser = isVisibleToUser; lazyLoad(); } private void lazyLoad() { if (initialization && isVisibleToUser) { loadData(); } } /** * 核心加载方法(可抽象) */ private void loadData() { Log.e("loadData", "initData: "+info); } @Override public void onActivityCreated(@Nullable Bundle savedInstanceState) { Log.e(TAG, "Fragment -卍卍卍卍卍卍卍- onActivityCreated: " + info); initialization = true; lazyLoad(); super.onActivityCreated(savedInstanceState); } 复制代码
- 方法2:针对ViewPager
预加载是ViewPager的锅,虽然可以设置预加载多个,但是不能不预加载...
锅是这行代码的private static final int DEFAULT_OFFSCREEN_PAGES = 1;// 默认的加载页面
所以自定义一个View 将ViewPager代码拷贝一份,上面哪行改成0,代码不贴了, 详见此处 :
但是,考虑到兼容问题,还是用懒加载Fragment比较好,毕竟创建两个对象也没什么大不了,加载数据限制住就OK了
4.ViewPager的动画效果
既然提到ViewPager就简单说一下吧
|--- 使用方式 ------------------------------------------ viewPager.setPageTransformer(true, new VPTFadeScale()); public class VPTFadeScale implements ViewPager.PageTransformer { private static float MIN_SCALE = 0.7f; //A==>B A的position 0==>-1 B的position 1==>0 @Override public void transformPage(View page, float position) { int width = page.getWidth(); int height = page.getHeight(); if (position < -1) {//非A、B页 page.setAlpha(1); } else if (position <= 0) {//A页的动画 page.setAlpha(1 + position * 2); page.setScaleX(1); page.setScaleY(1); page.setPivotX(0); page.setPivotY(height / 2); page.setRotationX(-100 * position); page.setRotationY(-100 * position); } else if (position <= 1) {//B页的动画 page.setAlpha(1 - position); page.setTranslationX(width * (-position)); // 0.75~1 float scaleFactor = MIN_SCALE + (1 - MIN_SCALE) * (1 - Math.abs(position)); page.setScaleX(scaleFactor); page.setScaleY(scaleFactor); } } } 复制代码
5、ViewPager滑动监听
根据滑动时的参数可以做一些好玩的事
//[]ViewPager滑动监听 viewPager.addOnPageChangeListener(new ViewPager.OnPageChangeListener() { /** * 当页面滑动过程中的回调 * @param position 当前滑动页面的位置 * @param positionOffset 下一页在当前页所占的宽度百分比 * @param positionOffsetPixels 下一页在当前页所占的宽度像素值 */ @Override public void onPageScrolled(int position, float positionOffset, int positionOffsetPixels Log.e(TAG, "onPageScrolled: " + "position==>" + position + "----positionOffset==>" + positionOffset + "----positionOffsetPixels" + positionOffsetPixels); } /** * 某个页面被选中(从0计数) 翻页成功才会调用 * @param position 翻页后的视图在集合中位置 */ @Override public void onPageSelected(int position) { Log.e(TAG, "onPageSelected: " + position); } /** * 页面状态发生变化的回调 1 滑动开始到手指离开前 2 手指离开后到结束之间 0 滑动结束 * @param state 状态 */ @Override public void onPageScrollStateChanged(int state) { Log.e(TAG, "onPageScrollStateChanged: " + state); } }); 复制代码
四、子Fragment的使用
1.基本使用
关键是通过 getChildFragmentManager
获取管理器,注意要在onStart或之后获取
---->[PagerFragment]------------一个孩子---------- @Override public void onStart() { SideFragment fragment = new SideFragment(); getChildFragmentManager() .beginTransaction() .add(R.id.fl_side, fragment) .show(fragment) .commit(); } ---->[PagerFragment]------------多个孩子---------- @Override public void onStart() { super.onStart(); SideFragment side = new SideFragment(); BoxFragment title = BoxFragment.newInstance("#eeeeee"); BoxFragment footer = BoxFragment.newInstance("#eeeeee"); getChildFragmentManager() .beginTransaction() .add(R.id.fl_side, side) .add(R.id.fl_title, title) .add(R.id.fl_bottom, footer) .show(title) .show(side) .show(footer) .commit(); } 复制代码
2.隐藏子Fragment
效果是点击主Fragment侧边栏会显示/隐藏切换
private boolean sideShowing = true; @Override public void onViewCreated(View view, @Nullable Bundle savedInstanceState) { Log.e(TAG, "Fragment -卍卍卍卍卍卍卍- onViewCreated: "); super.onViewCreated(view, savedInstanceState); view.setOnClickListener(v -> { if (sideShowing) { hideAt(0); } else { showAt(0); } sideShowing = !sideShowing; }); } public void hideAt(int i) { List<Fragment> fragments = getChildFragmentManager().getFragments(); getChildFragmentManager().beginTransaction().hide(fragments.get(i)).commit(); } public void showAt(int i) { List<Fragment> fragments = getChildFragmentManager().getFragments(); getChildFragmentManager().beginTransaction().show(fragments.get(i)).commit(); } 复制代码
四、其他要说的
1. startActivityForResult + onActivityResult
view.setOnLongClickListener(v -> { Intent i = new Intent(Intent.ACTION_PICK, MediaStore.Images.Media.EXTERNAL_CONTENT_URI); startActivityForResult(i, 0);// 设定结果返回 return false; }); @Override public void onActivityResult(int requestCode, int resultCode, Intent data) { super.onActivityResult(requestCode, resultCode, data); if (data != null) { switch (requestCode) { case 0: //打开相册并选择照片,这个方式选择单张 // 获取返回的数据,这里是android自定义的Uri地址 Uri selectedImage = data.getData(); Log.e("startActivityForResult", "startActivityForResult: " + selectedImage); break; } } } 复制代码
2.动态权限申请
注意申请时用 XXXFragment.this.requestPermissions
否则 onRequestPermissionsResult
无法回调
private static final int PERMISSION_REQ_ID = 22; private static final String[] REQUESTED_PERMISSIONS = { Manifest.permission.RECORD_AUDIO,//录音权限 Manifest.permission.CAMERA,//相机权限 Manifest.permission.WRITE_EXTERNAL_STORAGE//SD卡写权限 }; view.setOnClickListener(v -> {//点击申请权限 if (checkSelfPermission(REQUESTED_PERMISSIONS[0], PERMISSION_REQ_ID) && checkSelfPermission(REQUESTED_PERMISSIONS[1], PERMISSION_REQ_ID) && checkSelfPermission(REQUESTED_PERMISSIONS[2], PERMISSION_REQ_ID)) { //执行到此处说明已有权限成功 Toast.makeText(getActivity(), "已有权限成功", Toast.LENGTH_SHORT).show(); } }); /** * 检查权限的方法 * * @param permission 权限 * @param requestCode 请求码 * @return 是否拥有权限 */ public boolean checkSelfPermission(String permission, int requestCode) { if (ContextCompat.checkSelfPermission(getActivity(), permission) != PackageManager.PERMISSION_GRANTED) { //发送权限请求 PagerFragment.this.requestPermissions(REQUESTED_PERMISSIONS, requestCode); <-- 注意申请时用XXXFragment.this. return false; } return true; } @Override public void onRequestPermissionsResult(int requestCode, @NonNull String[] permissions, @NonNull int[] grantResults) { super.onRequestPermissionsResult(requestCode, permissions, grantResults); switch (requestCode) { case PERMISSION_REQ_ID: {//请求码 if (grantResults[0] != PackageManager.PERMISSION_GRANTED || grantResults[1] != PackageManager.PERMISSION_GRANTED || grantResults[2] != PackageManager.PERMISSION_GRANTED) { //三个权限有任意的未被允许,弹吐司,退出 Toast.makeText(getActivity(), "用户没有允许权限", Toast.LENGTH_SHORT).show(); getActivity().finish(); break; } Log.e(TAG, "onRequestPerm: OK"); break; } } } 复制代码
3.Fragment的优势
[1].将整个界面的责任碎片化,分散到各个部分,缓解Activity的负担 [2].方便修改/更新:那个地方出现问题/需要更新界面样式,可以直接去找对应的Fragment,而不是像以前在Activity里大海捞针 [3].方便复用: Fragment迁移很方便,哪里需要哪里搬。遇到差不多的需求,改改就能用了。 [4].运行中可以动态地移除、加入、交换,使用灵活 [5].可以`startActivityForResult + onActivityResult`,有目的的开启一个Activity [6].可以动态申请权限 requestPermissions + onRequestPermissionsResult [7].ViewPager和Fragment结合容易实现切换效果 复制代码
以上所述就是小编给大家介绍的《Android 点将台:撒豆成兵[- Fragment -]》,希望对大家有所帮助,如果大家有任何疑问请给我留言,小编会及时回复大家的。在此也非常感谢大家对 码农网 的支持!
猜你喜欢:- Android点将台:烽火狼烟[-Handler-]
- Android点将台:济世儒侠[-ContentProvider-]
- Android点将台:颜值担当[-Activity-]
- Android点将台:绝命暗杀官[-Service-]
- Android点将台:金科玉律[-AIDL-]
- Android点将台:传令官[-BroadcastReciver-](使用级)
本站部分资源来源于网络,本站转载出于传递更多信息之目的,版权归原作者或者来源机构所有,如转载稿涉及版权问题,请联系我们。