关于fragment的生命周期:
Fragemnt是一个碎片,只是覆盖原来的布局而已,当Fragemnt和原来的布局一样大,则完全覆盖,
若小,则没有覆盖完原来的布局,原来的布局还会显示没有覆盖的部分,
但该fragment最大只能和原来的布局一样大,即fragment使宽和高都设置的match_parent。
一:基本用法:
添加和移除的例子:
先上图:原本为蓝色的背景被紫色覆盖了,说明原来的控件id为 ll_main_content 被fragment_one.xml布局覆盖了
Step 1:创建一个fragment布局:fragment_one.xml
<?xml version="1.0" encoding="utf-8"?>
<LinearLayout xmlns:android="http://schemas.android.com/apk/res/android"
android:id="@+id/ll_Root"
android:background="@color/colorPrimary"
android:orientation="vertical"
android:layout_width="match_parent"
android:layout_height="match_parent">
<TextView
android:layout_width="match_parent"
android:layout_height="match_parent"
android:text="第一个fragment"/>
</LinearLayout>
Step 2:创建一个继承fragment的类
//==Step 1 :继承 Fragment
public class FragmentOne extends Fragment {
//==Step 2 :重写onCreateView
@Nullable
@Override
public View onCreateView(@NonNull LayoutInflater inflater, @Nullable ViewGroup container, @Nullable Bundle savedInstanceState) {
/**将xml(布局)资源文件加载成为View
inflate()的作用就是将一个xml定义的布局文件实例化为view控件对象
resource(第一个参数):View的layout的ID,即某个布局文件
root(第二个参数):填的是形参的ViewGroup对象,需要附加到resource资源文件的根控件,inflate()会返回一个View对象。
如果第三个参数attachToRoot为true,就将这个root作为根对象返回,
否则仅仅将这个root对象的LayoutParams属性附加到resource对象的根布局对象上,也就是布局文件resource的最外层的View上。
如果root为null则会忽略view根对象的LayoutParams属性(注意,即相当于没有设置布局)。
attachToRoot(第三个参数):是否将root附加到布局文件的根视图上
*/
View view=inflater.inflate(R.layout.fragment_one,container,false);
LinearLayout llRoot=view.findViewById(R.id.ll_Root);//可以获取该布局的控件id
return view;
}
}
Step 3:activity_main.xml布局内容为:
<?xml version="1.0" encoding="utf-8"?>
<LinearLayout xmlns:android="http://schemas.android.com/apk/res/android"
xmlns:app="http://schemas.android.com/apk/res-auto"
xmlns:tools="http://schemas.android.com/tools"
android:layout_width="match_parent"
android:layout_height="match_parent"
android:orientation="vertical"
tools:context=".MainActivity">
<!--此处为添加fragment的地方-->
<LinearLayout
android:id="@+id/ll_main_content"
android:layout_width="match_parent"
android:layout_height="0dp"
android:layout_weight="1"
android:background="@color/colorAccent"
android:orientation="horizontal"/>
<LinearLayout
android:layout_width="match_parent"
android:layout_height="wrap_content"
android:orientation="horizontal">
<Button
android:id="@+id/bt_load"
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:text="加载" />
<Button
android:id="@+id/bt_remove"
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:text="移除"/>
</LinearLayout>
</LinearLayout>
Step 4:MainActivity的代码如下:
public class MainActivity extends AppCompatActivity {
private FragmentOne fragmentOne;
@Override
protected void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
setContentView(R.layout.activity_main);
//获取控件
Button btLoad=findViewById(R.id.bt_load);//加载
Button btRemove=findViewById(R.id.bt_remove);//移除
btLoad.setOnClickListener(new View.OnClickListener() {
@Override
public void onClick(View v) {
//=====================加载fragment
//1.获取fragment管理器
FragmentManager fragmentManager=MainActivity.this.getSupportFragmentManager();
//2.开启fragment事务
FragmentTransaction transaction=fragmentManager.beginTransaction();
//3.创建写好的fragment,把要显示的fragment对象添加到transaction
fragmentOne = new FragmentOne();
//参数1为要把fragment加载到哪个控件的id,参数2为要加载的fragment
transaction.add(R.id.ll_main_content, fragmentOne);
//4.显示fragment
transaction.show(fragmentOne);
//5.提交事务
transaction.commit();
}
});
btRemove.setOnClickListener(new View.OnClickListener() {
@Override
public void onClick(View v) {
//==移除fragment ps:因为transaction 只能提交一次,所以只能再次创建该对象
FragmentManager fragmentManager=MainActivity.this.getSupportFragmentManager();
FragmentTransaction transaction=fragmentManager.beginTransaction();
transaction.remove(fragmentOne).commit();
}
});
}
}
二、懒加载和切换不同的fragment
先上图:红色边白色,说明切换了fragment了
Step 1:在此之前先准备需要用到的文件:在drawable 层 添加
1.bg_order_top.xml:作用:在button上面画一条灰色的线
<?xml version="1.0" encoding="utf-8"?>
<layer-list xmlns:android="http://schemas.android.com/apk/res/android">
<!--因为下面画了一个四边有1dp灰色的白色矩形,我们要的是只有上面有灰色,
所以除了top,其它都加-1dp的边距,让其它的灰色边框去掉
-->
<item
android:bottom="-1dp"
android:right="-1dp"
android:left="-1dp">
<!-- 画背景:rectangle 为画矩形-->
<shape android:shape="rectangle">
<!--画一个白色的矩形背景 ps:colorWhite为白色,自己去color文件添加-->
<solid
android:color="@color/colorWhite"/>
<!--在白色的四边上加上1dp的灰色 ps:colorGray 灰色,自己去color文件添加-->
<stroke android:width="1dp"
android:color="@color/colorGray"/>
</shape>
</item>
</layer-list>
2.selector_rb_main_home.xml 作用:当选中按钮时,按钮背景为一张图片,不选中时,为另一图片。 ps:这用到的图片,自行准备
<?xml version="1.0" encoding="utf-8"?>
<selector xmlns:android="http://schemas.android.com/apk/res/android">
<!--注意!!android:state_checked="true" 所在的item一定要在排在其它item的上面(排第一)-->
<!--android:state_checked="true" 说明,当该复选框被选中时,就调用这个item,该item的图片为:ic_rb_home_red-->
<item android:drawable="@drawable/ic_rb_home_red" android:state_checked="true"/>
<!--当不选中时,调用该item,图片为:ic_rb_home-->
<item android:drawable="@drawable/ic_rb_home"/>
</selector>
3.selector_rb_main_user.xml 作用同上
<?xml version="1.0" encoding="utf-8"?>
<selector xmlns:android="http://schemas.android.com/apk/res/android">
<item android:drawable="@drawable/ic_rb_user_red" android:state_checked="true"/>
<item android:drawable="@drawable/ic_rb_user"/>
</selector>
4.selector_rb_main.xml 作用:当按钮选中时,为一种颜色,不选中时为另一种颜色(ps:颜色请自行去color文件写)
<?xml version="1.0" encoding="utf-8"?>
<selector xmlns:android="http://schemas.android.com/apk/res/android">
<item android:color="@color/colorRed"
android:state_checked="true"/>
<item android:color="@color/colorBlack"/>
</selector>
Step 2:准备两个fragment用的布局:
1.fragment_home.xml
<?xml version="1.0" encoding="utf-8"?>
<LinearLayout xmlns:android="http://schemas.android.com/apk/res/android"
android:id="@+id/ll_Root"
android:background="@color/colorRed"
android:orientation="vertical"
android:layout_width="match_parent"
android:layout_height="match_parent">
<TextView
android:layout_width="match_parent"
android:layout_height="match_parent"
android:text="第一个fragment"/>
</LinearLayout>
2.fragment_user.xml
<?xml version="1.0" encoding="utf-8"?>
<LinearLayout xmlns:android="http://schemas.android.com/apk/res/android"
android:id="@+id/ll_Root"
android:orientation="vertical"
android:background="@color/colorWhite"
android:layout_width="match_parent"
android:layout_height="match_parent">
<TextView
android:layout_width="match_parent"
android:layout_height="match_parent"
android:text="第二个fragment"/>
</LinearLayout>
Step 3:准备两个class继承fragment:
1.HomeFragment
//==Step 1 :继承 Fragment
public class HomeFragment extends Fragment {
//==Step 2 :重写onCreateView
@Nullable
@Override
public View onCreateView(@NonNull LayoutInflater inflater, @Nullable ViewGroup container, @Nullable Bundle savedInstanceState) {
/**将xml(布局)资源文件加载成为View
inflate()的作用就是将一个xml定义的布局文件实例化为view控件对象
resource(第一个参数):View的layout的ID,即某个布局文件
root(第二个参数):填的是形参的ViewGroup对象,需要附加到resource资源文件的根控件,inflate()会返回一个View对象。
如果第三个参数attachToRoot为true,就将这个root作为根对象返回,
否则仅仅将这个root对象的LayoutParams属性附加到resource对象的根布局对象上,也就是布局文件resource的最外层的View上。
如果root为null则会忽略view根对象的LayoutParams属性(注意,即相当于没有设置布局)。
attachToRoot(第三个参数):是否将root附加到布局文件的根视图上
*/
View view=inflater.inflate(R.layout.fragment_home,container,false);
LinearLayout llRoot=view.findViewById(R.id.ll_Root);//可以获取该布局的控件id
return view;
}
}
2.UserFragment
//==Step 1 :继承 Fragment
public class UserFragment extends Fragment {
//==Step 2 :重写onCreateView
@Nullable
@Override
public View onCreateView(@NonNull LayoutInflater inflater, @Nullable ViewGroup container, @Nullable Bundle savedInstanceState) {
View view=inflater.inflate(R.layout.fragment_user,container,false);
return view;
}
}
Step 4:activity_main.xml布局内容为:
<?xml version="1.0" encoding="utf-8"?>
<LinearLayout xmlns:android="http://schemas.android.com/apk/res/android"
xmlns:app="http://schemas.android.com/apk/res-auto"
xmlns:tools="http://schemas.android.com/tools"
android:layout_width="match_parent"
android:layout_height="match_parent"
android:background="@color/colorWhite"
tools:context=".MainActivity"
android:orientation="vertical">
<!--被fragment覆盖的部分-->
<LinearLayout
android:id="@+id/ll_main_content"
android:layout_width="match_parent"
android:layout_height="0dp"
android:layout_weight="1"
android:orientation="horizontal" />
<!--功能按钮-->
<RadioGroup
android:layout_width="match_parent"
android:layout_height="wrap_content"
android:paddingBottom="5dp"
android:orientation="horizontal"
android:background="@drawable/bg_order_top"
android:paddingTop="5dp">
<RadioButton
android:id="@+id/rb_main_home"
android:layout_width="0dp"
android:layout_weight="1"
android:layout_height="match_parent"
android:button="@null"
android:gravity="center_horizontal"
android:drawableTop="@drawable/selector_rb_main_home"
android:text="主页"
android:textColor="@drawable/selector_rb_main"/>
<RadioButton
android:id="@+id/rb_main_user"
android:layout_width="0dp"
android:layout_weight="1"
android:layout_height="match_parent"
android:button="@null"
android:gravity="center_horizontal"
android:drawableTop="@drawable/selector_rb_main_user"
android:textColor="@drawable/selector_rb_main"
android:text="我的" />
</RadioGroup>
</LinearLayout>
Step 5:开始使用:MainActivity 代码如下:
public class MainActivity extends AppCompatActivity {
private RadioButton rbHome;
private RadioButton rbUser;
private Fragment[] fragments=new Fragment[]{null,null};//存放fragment
@Override
protected void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
setContentView(R.layout.activity_main);
//=====Step 1:获取控件
rbHome = findViewById(R.id.rb_main_home);
rbUser = findViewById(R.id.rb_main_user);
//======Step 2:懒加载:默认选择的fragment(HomeFragment)
initFragment(0);
//默认选中主页
rbHome.setChecked(true);
//======Step 3:点击事件监听
listenerView();
}
private void listenerView() {
//Step 3.1:点击rbHome(主页) 切换为主页的(HomeFragment)
rbHome.setOnClickListener(new View.OnClickListener() {
@Override
public void onClick(View v) {
initFragment(0);
}
});
//Step 3.2:点击rbUser(我的) 切换为我的的(UserFragment)
rbUser.setOnClickListener(new View.OnClickListener() {
@Override
public void onClick(View v) {
initFragment(1);
}
});
}
public void initFragment(int value){
//===========加载fragment
//1.获取fragment管理器
FragmentManager fragmentManager=this.getSupportFragmentManager();
//2.开启fragment事务
FragmentTransaction transaction=fragmentManager.beginTransaction();
//3.声明全局的数组fragments ,把要显示的fragment对象添加到transaction
if (fragments[value]==null){
switch (value){
case 0://为 0 时 切换为 HomeFragment
fragments[value]=new HomeFragment();
break;
case 1://为 1 时 切换为 UserFragment
fragments[value]=new UserFragment();
break;
}
transaction.add(R.id.ll_main_content,fragments[value]);
}
//4.隐藏其它fragment
for (int i = 0; i < fragments.length; i++) {
if (fragments[i]!=null && value!=i){
transaction.hide(fragments[i]);
}
}
//5.显示fragment并提交
transaction.show(fragments[value]).commit();
}
}
PS:当要在当前fragment获取当前的content 或 activity时,要在此方法获取:
例部分代码如下:
public class HomeFragment extends Fragment {
private Activity activity;
//在方法获取当前content,在onCreateView获取有时会获取不到
@Override
public void onAttach(@NonNull Context context) {
super.onAttach(context);
this.activity= (Activity) context;
}
PS:在fragment直接传参可以用bundle:例:
要传参的fragment(继承fragment的类):
Bundle bundle=new Bundle();
bundle.putInt("int",12);
bundle.putString("string","小明");
//例如 要接受参数的fragment 名为:HomeFragmentList ,就如下设置其参数
HomeFragmentList home=new HomeFragmentList();
home.setArguments(bundle);
要接受的fragment:部分代码如下:
@Nullable
@Override
public View onCreateView(@NonNull LayoutInflater inflater, @Nullable ViewGroup container, @Nullable Bundle savedInstanceState) {
Bundle bundle=getArguments();
int it=bundle.getInt("it");
String str=bundle.getString("string");