一、为什么要有Fragment?
Android运行在各种各样的设备中,有小屏幕的手机,还有大屏幕的平板,电视等。同样的界面在手机上显示可能很好看,在大屏幕的平板上就未必了,手机的界面放在平板上可能会有过分被拉长、控件间距过大等情况。针对屏幕尺寸的差距,Fragment 的出现能做到一个App可以同时适应手机和平板。这就是为什么要有Fragment的原因。
android.app.Fragment在API 级别 11 中 添加,已在API 级别 28 中弃用。
二、Fragment为什么被称为第五大组件
Fragment比Activity更节省内存,其切换模式也更加舒适,使用频率不低于四大组件,且有自己的 生命周期,而且必须依附于Activity,不能独立存在。
特点:
- Fragment依赖于Activity,不能独立存在
- 一个Activity可以有多个Fragment
- 一个Fragment可以被多个Activity重用
- Fragment有自己的生命周期,并能接收输入事件
- 可以在Activity运行时动态地添加或删除Fragment
三、Activity创建Fragment的方式
静态创建
- 定义Fragment的xml布局文件
- 自定义Fragment类,继承Fragment类或其子类,同时实现onCreateView()方法,在方法中通过inflater.inflate加载布局文件,接着返回其View
- 在需要加载Fragment的Activity对应布局文件中的name属性设为全限定类名,即包名.fragment
- 最后在Activity调用setContentView()加载布局文件即可
样例:
1.定义Fragment的xml布局文件(新建fragment_home.xml和fragment_mine.xml)
fragment_home.xml:
<?xml version="1.0" encoding="utf-8"?> <LinearLayout xmlns:android="http://schemas.android.com/apk/res/android" android:layout_width="match_parent" android:layout_height="match_parent" android:orientation="vertical" android:background="@color/color_ff0000" android:gravity="center" > <TextView android:id="@+id/tv_on" android:layout_width="wrap_content" android:layout_height="wrap_content" android:text="首页" android:onClick="onClick" android:textColor="@color/white" android:textSize="@dimen/text_size_20"/> </LinearLayout>
fragment_mine.xml
<?xml version="1.0" encoding="utf-8"?> <LinearLayout xmlns:android="http://schemas.android.com/apk/res/android" android:layout_width="match_parent" android:layout_height="match_parent" android:orientation="vertical" android:background="@color/color_188FFF" android:gravity="center" > <TextView android:layout_width="wrap_content" android:layout_height="wrap_content" android:text="我的" android:textColor="@color/white" android:textSize="@dimen/text_size_20"/> </LinearLayout>
2.自定义Fragment类,继承Fragment类或其子类,同时实现onCreateView()方法,在方法中通过inflater.inflate加载布局文件,接着返回其View
public class HomeFragment extends Fragment { private TextView tv_on; @Override public View onCreateView(LayoutInflater inflater, ViewGroup container, Bundle savedInstanceState) { View view = inflater.inflate(R.layout.fragment_home, container,false); MLog.e(this.getClass().getName()+"onCreateView"); tv_on = view.findViewById(R.id.tv_on); tv_on.setOnClickListener(new View.OnClickListener() { @Override public void onClick(View v) { MLog.e(this.getClass().getName()+"准备关闭"); } }); return view; } }
3.在需要加载Fragment的Activity对应布局文件中的name属性设为全限定类名,即包名.fragment.HomeFragment
<?xml version="1.0" encoding="utf-8"?> <LinearLayout xmlns:android="http://schemas.android.com/apk/res/android" android:id="@+id/ll_bg" android:layout_width="match_parent" android:layout_height="match_parent" android:background="@color/color_666666" android:orientation="horizontal"> <fragment android:id="@+id/fragmen_home" android:name="com.scc.demo.fragment.HomeFragment" android:layout_width="0dp" android:layout_weight="1" android:layout_height="match_parent" /> <fragment android:id="@+id/fragmen_mine" android:name="com.scc.demo.fragment.MineFragment" android:layout_width="0dp" android:layout_weight="1" android:layout_height="match_parent" /> </LinearLayout>
4.最后在Activity调用setContentView()加载布局文件即可
public class FragmentActivity extends ActivityBase { @Override public void onCreate(Bundle savedInstanceState) { super.onCreate(savedInstanceState); MLog.e(this.getClass().getName()+"onCreate"); setContentView(R.layout.activity_fragment); } }
动态创建
- 获得FragmentManager对象,通过getSupportFragmentManager()
- 获得FragmentTransaction对象,通过fm.beginTransaction()
- 调用add()方法或者repalce()方法加载Fragment;
- 最后调用commit()方法提交事务
样例:
1.activity的布局文件
1.<?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"> <FrameLayout android:id="@+id/fl_frame" android:layout_width="match_parent" android:layout_height="match_parent" android:layout_above="@+id/rg_bottom_tab"/> <RadioGroup android:id="@+id/rg_bottom_tab" android:layout_width="match_parent" android:layout_height="56dp" android:layout_alignParentBottom="true" android:background="#dcdcdc" android:orientation="horizontal"> <RadioButton android:id="@+id/rb_home" android:layout_width="0dp" android:layout_height="match_parent" android:layout_weight="1" android:button="@null" android:checked="true" android:gravity="center" android:text="首页" android:textSize="@dimen/text_size_18" /> <RadioButton android:id="@+id/rb_list" android:layout_width="0dp" android:layout_height="match_parent" android:layout_weight="1" android:button="@null" android:checked="true" android:gravity="center" android:text="列表" android:textSize="@dimen/text_size_18" /> <RadioButton android:id="@+id/rb_news" android:layout_width="0dp" android:layout_height="match_parent" android:layout_weight="1" android:button="@null" android:checked="true" android:gravity="center" android:text="消息" android:textSize="@dimen/text_size_18" /> <RadioButton android:id="@+id/rb_mine" android:layout_width="0dp" android:layout_height="match_parent" android:layout_weight="1" android:button="@null" android:gravity="center" android:text="我的" android:textSize="@dimen/text_size_18" /> </RadioGroup> </RelativeLayout>
2.自定义Fragment
public class HomeFragment extends Fragment { private TextView tv_on; public static HomeFragment newInstance(String param){ HomeFragment fragment = new HomeFragment(); Bundle args = new Bundle(); args.putString("param", param); fragment.setArguments(args); return fragment; } public HomeFragment(){} @Override public View onCreateView(LayoutInflater inflater, ViewGroup container, Bundle savedInstanceState) { View view = inflater.inflate(R.layout.fragment_home, container,false); MLog.e(this.getClass().getName()+"onCreateView"); Bundle bundle = getArguments(); String param = bundle.getString("param"); tv_on = view.findViewById(R.id.tv_on); tv_on.setText("首页"+param); tv_on.setOnClickListener(new View.OnClickListener() { @Override public void onClick(View v) { MLog.e(this.getClass().getName()+"准备关闭"); } }); return view; } }
3.获得FragmentManager对象,通过getFragmentManager()
public class FragmentActivity extends ActivityBase { private RadioGroup rg_bottom_tab; private SparseArray<Fragment> mFragmentList; @Override public void onCreate(Bundle savedInstanceState) { super.onCreate(savedInstanceState); setContentView(R.layout.activity_fragment); MLog.e(this.getClass().getName()+"onCreate"); initView(); } public void initView(){ rg_bottom_tab = findViewById(R.id.rg_bottom_tab); mFragmentList = new SparseArray<>(); mFragmentList.append(R.id.rb_home, HomeFragment.newInstance("我最帅")); mFragmentList.append(R.id.rb_list, ListFragment.newInstance("我最美")); mFragmentList.append(R.id.rb_news, NewsFragment.newInstance("我最新")); mFragmentList.append(R.id.rb_mine, MineFragment.newInstance("这里是我的")); rg_bottom_tab.setOnCheckedChangeListener(new RadioGroup.OnCheckedChangeListener() { @Override public void onCheckedChanged(RadioGroup group, int checkedId) { // 具体的fragment切换逻辑可以根据应用调整,例如使用show()/hide() FragmentManager fragmentManager = getFragmentManager(); FragmentTransaction transaction = fragmentManager.beginTransaction(); transaction.replace(R.id.fl_frame, mFragmentList. get(checkedId)); transaction.commit(); } }); // 默认显示第一个 FragmentManager fragmentManager = getFragmentManager(); FragmentTransaction transaction = fragmentManager.beginTransaction(); transaction.add(R.id.fl_frame, mFragmentList.get(R.id.rb_home)).commit(); } }1.
四、FragmentPageAdapter和FragmentPageStateAdapter的区别
FragmentPageAdapter在每次切换页面的的时候,是将Fragment进行分离,适合页面较少的Fragment使用以保存一些内存,对系统内存不会多大影响。
FragmentPageStateAdapter在每次切换页面的时候,是将Fragment进行回收,适合页面较多的Fragment使用,这样就不会消耗更多的内存。