FrameLayout的使用进阶
来源:互联网 发布:mac屏幕涂层脱落原因 编辑:程序博客网 时间:2024/05/16 01:29
前提:创建两个Fragment(个人叫FirstFragment,SecondFragment),由于本篇幅不是讲解如何使用Fragment,所以就不上详细创建步骤了。
效果图:
一、如何切换Fragment
作用:管理Fragment的显示,存储。
FragmentTransaction transaction = fm.benginTransatcion();//开启一个事务
transaction.add()
往FragmentManager中添加一个Fragment,并创建Fragment的View,添加到FrameLayout中显示。
注:用代码创建Fragment本身,并不会执行Fragment的生命周期,也就是
FirstFragment fragment = new FirstFragment();这时候是不会执行Fragment的生命周期。其生命周期是由Activity来控制的。所以后面说到的销毁Fragment,指的并不是销毁fragment实例也就是fragment == null,而是重新执行了Fragment的生命周期。(可以这么理解new FirstFragment()只是创造了身体,灵魂的创造需要依靠Activity)
往FragmentManager中销毁一个Fragment,并销毁Fragment的View。如果被移除的Fragment没有添加到回退栈(回退栈后面会详细说),这个Fragment实例会完全被移出FragmentManger。否则只销毁Fragment的视图。(同detch())
transaction.replace()
使用另一个Fragment替换当前的,实际上就是remove()然后add()的合体。
(注:如果remove()的Fragment不存在,不会影响add操作。相当于执行了add()操作
如果replace()的Fragment与当前显示的Fragment相同,则不执行replace()操作)
transaction.hide()
隐藏当前的Fragment,仅仅是将View设为不可见,并不会销毁。transaction.show():(Fragment必须存在于FragmentManager内,才能使用)
显示之前隐藏的Fragment。detach()
移除Fragment的View,和remove()不同,此时fragment的状态依然由FragmentManager维护。
attach()
重建view视图,附加到UI上并显示。transatcion.commit()//提交一个事务
③、三种实际中切换Fragment的方法
第一种:add()+remove() = replace():销毁当前显示的Fragment,添加需要显示的Fragment。
缺点:Fragment会被重新创建,导致View重绘。View重绘的同时也表示用户之前在该View上做的操作都消失了。
优点:节省内存空间。
使用场景:不要求保留用户操作。(用户操作,比如说:ListView滑动到第5个item,但是由于View的重绘,又会回到第一个Item)
示例:
public class MainActivity extends AppCompatActivity { private FirstFragment mFirstFragment; private SecondFragment mSecondFragment; @Override protected void onCreate(Bundle savedInstanceState) { super.onCreate(savedInstanceState); setContentView(R.layout.activity_main); initWidget(); } private void initWidget(){ //初始化Fragment mFirstFragment = new FirstFragment(); mSecondFragment = new SecondFragment(); //首先显示FirstFragment showFragment(mFirstFragment); } private void showFragment(Fragment fragment){ //直接replace()就可以了,不需要先add~~~ getSupportFragmentManager().beginTransaction() .replace(R.id.main_frame,fragment) .commit(); } /** *使用了ActionBar的menu */ @Override public boolean onCreateOptionsMenu(Menu menu) { getMenuInflater().inflate(R.menu.switch_fragment,menu); return super.onCreateOptionsMenu(menu); } @Override public boolean onOptionsItemSelected(MenuItem item) { switch (item.getItemId()){ case R.id.menu_first_fragment: showFragment(mFirstFragment); break; case R.id.menu_second_fragment: showFragment(mSecondFragment); break; } return super.onOptionsItemSelected(item); }}
第二种:show()+hide():将Fragment视图隐藏之后在显示。
缺点:由于Fragment只是被隐藏了,并未被销毁,所以需要占用内存空间来保存。
优点:不用重新创建Fragment
使用场景;需要保留用户数据的情形。
示例:(与上面示例不同的部分)
private void initWidget(){ //初始化Fragment mFirstFragment = new FirstFragment(); mSecondFragment = new SecondFragment(); setUpFragment(); } private void setUpFragment(){ //首先将所有的Fragment添加到FragmentManager中,并隐藏,只显示当前需要的Fragment getSupportFragmentManager().beginTransaction() .add(R.id.main_frame,mFirstFragment) .add(R.id.main_frame,mSecondFragment) .hide(mSecondFragment) .commit(); //设定当前的Fragment,知道下一次hide那个Fragment mCurrentFragment = mFirstFragment; } private void showFragment(Fragment fragment){ if (mCurrentFragment != fragment){ getSupportFragmentManager().beginTransaction() .hide(mCurrentFragment) .show(fragment) .commit();<pre name="code" class="java"> mCurrentFragment = fragment;//设定当前的Fragment} }
private void initWidget(){ //初始化Fragment mFirstFragment = new FirstFragment(); mSecondFragment = new SecondFragment(); setUpFragment(); } private void setUpFragment(){ //首先将所有的Fragment添加到FragmentManager中,并删除View,只显示当前需要的Fragment getSupportFragmentManager().beginTransaction() .add(R.id.main_frame,mFirstFragment) .add(R.id.main_frame,mSecondFragment) .detach(mSecondFragment) .commit(); //设定当前的Fragment,知道下一次hide那个Fragment mCurrentFragment = mFirstFragment; } private void showFragment(Fragment fragment){ if (mCurrentFragment != fragment){ getSupportFragmentManager().beginTransaction() .detach(mCurrentFragment) .attach(fragment) .commit(); mCurrentFragment = fragment;//设定当前的Fragment } }形式上跟第二种方法差不多~~~~,但是内容上却是第一种方法的改进
二、如何保证不发生Fragment重影
①、发生重影的原理:当将app缩小到后台,由于资源回收,系统会回收后台的资源(比如说Activity),并会调用onSaveInstanceState()保存当前状态。然后当app返回到前台的时候,系统会重建被被回收的资源。系统会将onSaveInstanceState()保存的Bundle对象传递给当前重建的Activity。就是onCreate(Bundle saveInstance)中的saveInstance参数。也会调用onRestoreInstanceState(Bundle saveInstance)来接收bundle对象。(详细请参考异常生命周期下的资源重建)
private static final String TAG_FIRST = "FirstFragment"; private static final String TAG_SECOND = "SecondFragment"; private FirstFragment mFirstFragment; private SecondFragment mSecondFragment; private Fragment mCurrentFragment; @Override protected void onCreate(Bundle savedInstanceState) { super.onCreate(savedInstanceState); setContentView(R.layout.activity_main); initWidget(savedInstanceState); } private void initWidget(Bundle savedInstanceState){ if(savedInstanceState ==null){ //初始化Fragment mFirstFragment = new FirstFragment(); mSecondFragment = new SecondFragment(); setUpFragment(); } else { //由于FragmentManager已经存在了这些Fragment直接获取就可以了 mFirstFragment = (FirstFragment) getSupportFragmentManager() .findFragmentByTag(TAG_FIRST); mSecondFragment = (SecondFragment) getSupportFragmentManager() .findFragmentByTag(TAG_SECOND); } } private void setUpFragment(){ //第一步:为每个Fragment添加Tag getSupportFragmentManager().beginTransaction() .add(R.id.main_frame,mFirstFragment,TAG_FIRST) .add(R.id.main_frame,mSecondFragment,TAG_SECOND) .detach(mSecondFragment) .commit(); //设定当前的Fragment,知道下一次hide那个Fragment mCurrentFragment = mFirstFragment; }第二种:(阻止FragmentManager调用onSaveInstanceState()保存Fragment)
三、Fragment与Activity的交互
①、Fragment中调用Activity的方法
错误的使用方法:
在MainActivity添加获取Data的方法
/** * 获取数据 */ public int getData(){ return 100; }在FirstFragment直接调用该方法
//在FirstFragment中 @Override public void onActivityCreated(@Nullable Bundle savedInstanceState) { super.onActivityCreated(savedInstanceState); //直接调用Activity的方法 int data = ((MainActivity)getActivity()).getData(); Log.d("TAG",data+" "); }这样使用的缺点:该Fragment被MainActivity捆绑了。也就是说只能被MainActivity使用,不能被其他Activity使用了。如果有TestActivity使用FirstFragment,就会报错,因为((MainActivity)getActivity()).getData();这行代码不成立。
最佳实践:(通过使用监听器,实现Activity与Fragment之间的解耦)
public class FirstFragment extends Fragment { private OnFirstFragmentListener mListener; @Override public void onAttach(Context context) { super.onAttach(context); //第二步:将Activity转换成监听器 try { mListener = (OnFirstFragmentListener) getActivity(); Log.d("Tag",mListener.getData()+""); }catch (ClassCastException e){ throw new ClassCastException("must implement OnFirstFragmentListener"); } } @Nullable @Override public View onCreateView(LayoutInflater inflater, @Nullable ViewGroup container, @Nullable Bundle savedInstanceState) { View view = inflater.inflate(R.layout.fragment_first,container,false); return view; } //第一步:创建监听器 public interface OnFirstFragmentListener{ int getData(); }}之后Activity实现接口:
public class MainActivity extends AppCompatActivity implements FirstFragment.OnFirstFragmentListener { public int getData(){ return 100; }}
1、向Fragment传递初始化Fragment所必要的数据
需求:有时候我们需要根据Activity掌握的数据创建Fragment。(MainActivity传递文章的id给ArticleActivity,ArticleActivity又需要将id传递给ArticleFragment,然后让ArticleFragment通过加载数据)
最佳实践:()
为Fragment设置创建Fragment的方法,并使用Bundle传递数据,使用getArgument获取数据。
public class FirstFragment extends Fragment{ <pre name="code" class="java"> private static final String ARGS_ID = "id";<pre name="code" class="java">@Override public void onCreate(@Nullable Bundle savedInstanceState) { super.onCreate(savedInstanceState); //获取数据 Bundle bundle = getArguments(); int article_id = bundle.getInt(ARGS_ID); Log.d("TAG",article_id+""); } public static FirstFragment newInstance(int id) { Bundle args = new Bundle(); args.putInt(ARGS_ID,id); FirstFragment fragment = new FirstFragment(); fragment.setArguments(args); return fragment; }}
2、Activity与Fragment之间的交互
因为Activity掌握了Fragment的实例,所以直接通过调用Fragment的public方法就可以了。
③、Fragment与Fragment之间的交互
在Activity中,通过Fragment setTargetFragment(Fragment fragment,int flag);将需要进行交互的Fragment传递给当前Fragment。(int flag为传递的Fragment设定id)
例:
public class MainActivity extends AppCompatActivity{ @Override protected void onCreate(Bundle savedInstanceState) { super.onCreate(savedInstanceState); setContentView(R.layout.activity_main) mFirstFragment = new FirstFragment(); mSecondFragment = new SecondFragment();<span style="white-space:pre"></span>//将SecondFragment的实例传递给FirstFragment mFirstFragment.setTargetFragment(mSecondFragment,0); }}然后在FirstFragment中获取SecondFragment:
public class FirstFragment extends Fragment { @Override public void onActivityCreated(@Nullable Bundle savedInstanceState) { super.onActivityCreated(savedInstanceState); //首先判断获取的是哪个Fragment switch (getTargetRequestCode()){ case 0: SecondFragment secondFragment = (SecondFragment) getTargetFragment(); //...之后进行交互的操作 break; } }}
四、Fragment的回退栈
回退栈的作用: 如果你将Fragment任务添加到回退栈,当用户点击后退按钮时,将看到上一次的保存的Fragment。一旦Fragment完全从后退栈中弹出,用户再次点击后退键,则退出当前Activity。
如何添加回退栈:addBackTo(String name);//name表示该Fragment在栈中的标识,不需要可以设置为null
代码:
private void showFragment(Fragment fragment){ if (mCurrentFragment != fragment){ getSupportFragmentManager().beginTransaction() .detach(mCurrentFragment) .attach(fragment) .addToBackStack(null)//将当前framgent加入回退栈 .commit(); mCurrentFragment = fragment;//设定当前的Fragment }
效果:
- FrameLayout的使用进阶
- 【FrameLayout】使用FrameLayout应该注意的地方
- framelayout的使用
- FrameLayout的使用
- Android布局FrameLayout的使用
- Android布局FrameLayout的使用
- Android之FrameLayout的使用
- FrameLayout使用
- android framelayout的简单使用例子
- 帧布局(FrameLayout)的简单使用
- Android使用FrameLayout应该注意的地方
- Android框架布局FrameLayout的使用…
- 基于Android FrameLayout的使用详解
- 使用FrameLayout应该注意的地方
- 使用FrameLayout应该注意的地方
- 使用FrameLayout制作的摇杆控件
- 10 - 布局Layout:FrameLayout帧布局以及FrameLayout在切换屏幕效果的使用
- 使用FrameLayout实现遮罩层
- Java初学篇之窗口应用小程序
- 【NOIP提高组】爬山
- vi笔记4——vi之超越基础
- 几个常用函数的实现strcpy、 strncpy、 strncat 、 strcmp、 strlen
- vulakn教程--Drawing a Triangle--Pipeline--Shader Module
- FrameLayout的使用进阶
- dos命令无效解决方法
- curl 模拟一个post请求
- CENTOS6.5环境下POSTGRESQL的安装与配置总结以及远程连接问题的解决
- CSS清浮动处理
- java中自定义排序 Comparison method violates its general contract异常
- 网易2017校园招聘笔试题 回文序列
- Android中Adapter之ArrayAdapter使用
- 深度学习基础文章汇总