Android开发学习笔记(三) —— 探究Fragment

一、什么是Fragment

1.1 概述

Fragment是Android3.0后引入的一个新的API,它出现的初衷是为了适应大屏幕的平板电脑。开发者可以利用Fragment框架构建更灵活的界面,并在不同的设备上实现统一的用户体验。

Fragment可以看作是一个子Activity,它具有自己的生命周期,但必须寄生在Activity中才能运行,受Activity生命周期影响。

1.2 为什么会有Fragment?

拿新闻板块举例。下图是使用平板和手机使用Fragment针对新闻板块的不同处理情况。

(来自菜鸟教程的图片)

显然对于平板来说,这么大的屏幕只放新闻简介就有点太浪费了,UI设计也不好看。但是利用两个Fragment,一个展示新闻简介,一个展示新闻具体内容,同时展现在屏幕上,那这样就合理利用了整个屏幕,UI设计也就好看多了。

同样的UI设计方案应用到手机上就不太行了,因为手机屏幕太小了。所以更合理的设计是展示新闻简介的Fragment先占据整个屏幕,当触发点击事件后,被展示新闻具体内容的Fragment覆盖。

二、Fragment的基本使用

2.1 静态加载Fragment

步骤如下:

  1. 通过 getSupportFragmentManager() 方法获取FragmentManager对象。
  2. 通过 FragmentManager.beginTransaction()方法获取FragmentTransaction对象。
  3. 调用add()方法或这replace()方法加载 Fragment
  4. 最后调用commit()方法提交事务。

创建的fragmentone.xml、fragmenttwo.xml如下

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
<!-- fragmentone.xml -->
<LinearLayout xmlns:android="http://schemas.android.com/apk/res/android"
android:layout_width="match_parent"
android:layout_height="match_parent"
android:gravity="center"
>
<TextView
android:id="@+id/fragmentone_tv"
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:text="今天星期四,懂?"
android:textSize="32sp"/>
</LinearLayout>
<!-- fragmenttwo.xml -->
<LinearLayout xmlns:android="http://schemas.android.com/apk/res/android"
xmlns:tools="http://schemas.android.com/tools"
android:layout_width="match_parent"
android:layout_height="match_parent"
android:gravity="center"
>
<android.widget.Button
android:id="@+id/fragmenttwo_btn"
android:layout_width="200dp"
android:layout_height="120dp"
android:text="点击改变文字"
android:textSize="32sp" />
</LinearLayout>

然后在activity_main.xml中使用

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
<LinearLayout
android:id="@+id/ll"
xmlns:android="http://schemas.android.com/apk/res/android"
android:layout_height="match_parent"
android:layout_width="match_parent"
android:orientation="horizontal"
android:gravity="center">

<fragment
android:name="com.example.myapplication.FragmentOne"
android:id="@+id/fragmentone"
android:layout_width="match_parent"
android:layout_height="match_parent"
android:layout_weight="1"
/>

<fragment
android:name="com.example.myapplication.FragmentTwo"
android:id="@+id/fragmenttwo"
android:layout_width="match_parent"
android:layout_height="match_parent"
android:layout_weight="1"
/>
</LinearLayout>

需要注意的是<fragment>标签中必须设置idname(对应的自己创建的继承于Fragment的子类)

其中FragmentOne类和FragmentTwo类的实现如下

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
//FragmentOne.java
public class FragmentOne extends Fragment {
public View onCreateView(@NonNull LayoutInflater inflater, @Nullable ViewGroup container, @Nullable Bundle savedInstanceState) {
//加载fragment,尽量写全局,然后判断是否已经创建
View FragmentOne = inflater.inflate(R.layout.fragmentone, container, false);
return FragmentOne;
}
}
//FragmentTwo.java
public class FragmentTwo extends Fragment {
public View onCreateView(@NonNull LayoutInflater inflater, @Nullable ViewGroup container, @Nullable Bundle savedInstanceState) {
//加载fragment
View FragmentTwo = inflater.inflate(R.layout.fragmenttwo, container, false);
return FragmentTwo;
}
}

先不设置两个Fragment的关联。

MainActivity.java中不需要任何代码设置。

2.2 动态加载Fragment

两个fragment的xml文件和fragment子类同上。只不过 activity_main.xml 中需要修改,不是使用<fragment>标签,而是<FrameLayout>标签,需要定义id,没有name属性。

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
<LinearLayout
android:id="@+id/ll"
xmlns:android="http://schemas.android.com/apk/res/android"
android:layout_height="match_parent"
android:layout_width="match_parent"
android:orientation="vertical"
android:gravity="center">

<android.widget.Button
android:id="@+id/changefragmentbtn"
android:layout_width="match_parent"
android:layout_height="wrap_content"
android:text="change"/>

<FrameLayout
android:id="@+id/framelayout"
android:layout_width="match_parent"
android:layout_height="match_parent"
android:layout_weight="1"
android:background="@drawable/wallhaven"
/>
</LinearLayout>

通过点击按钮来更换fragment。

MainActivity.java需要做修改

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
public class MainActivity extends AppCompatActivity implements View.OnClickListener{

private boolean flag = true;

@Override
protected void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
setContentView(R.layout.activity_main);

Button btn = findViewById(R.id.changefragmentbtn);
btn.setOnClickListener(this);

}

@Override
public void onClick(View view) {

if (flag){
replaceFragment(new FragmentTwo());
flag = false;
} else {
replaceFragment(new FragmentOne());
flag = true;
}
}

//动态切换fragment
private void replaceFragment(Fragment fragment) {
//获取fragmentManager
FragmentManager supportFragmentManager = getSupportFragmentManager();
//获取transaction
FragmentTransaction fragmentTransaction = supportFragmentManager.beginTransaction();
//替换fragment,第一个参数为被替换的fragment所在的FrameLayout容器id,第二个参数是所要展示的fragment
fragmentTransaction.replace(R.id.framelayout, fragment);
//提交修改请求
fragmentTransaction.commit();
}

}

当然也可以不选择实现View.OnClickListener接口来实现点击事件处理方法,选择写成匿名函数也是可以。

2.3 Fragment回退栈

在2.2的例子中,如果我们点击back键,则会直接退出应用。如果我们要实现一层一层的退出 fragment 的话,需要使用到addToBackStack()方法。拿2.2的例子来讲,只需稍微修改replaceFragment()方法。

1
2
3
4
5
6
7
8
9
10
11
12
private void replaceFragment(Fragment fragment) {
//获取fragmentManager
FragmentManager supportFragmentManager = getSupportFragmentManager();
//获取transaction
FragmentTransaction fragmentTransaction = supportFragmentManager.beginTransaction();
//替换fragment,第一个参数为被替换的fragment所在的FrameLayout容器id,第二个参数是所要展示的fragment
fragmentTransaction.replace(R.id.framelayout, fragment);
//将被替换的fragment添加到栈中
fragmentTransaction.addToBackStack(null);
//提交修改请求
fragmentTransaction.commit();
}

这样当我们点击back键后,最上面的 fragment 事务会从堆栈中弹出。如果堆栈上没有 fragment 事务,则返回事件会向上传递到 Activity。

2.4 Fragment与Activity的交互

2.4.1 组件获取

  • Fragment通过getActivity().findViewById(R.id.list)获得Activity中的组件。
  • Activity通过getSupportFragmentManager().findFragmentByid获得Fragment中的组件(id和tag都行)。

2.4.2 数据传递

2.4.2.1 Fragment传递数据给Activity

步骤如下:

  1. 在Fragment定义一个接口,接口中定义抽象方法,你要传什么类型的数据参数就设置为什么类型
  2. 接着还有写一个调用接口中的抽象方法,把要传递的数据传过去
  3. 再接着就是Activity了,调用Fragment提供的那个方法,然后重写抽象方法的时候进行数据 的读取就可以了

(有点像UI开发笔记中的RecyclerView的item监听设置。)

案例还是使用2.2的代码,只进行一点点修改。

首先在fragment对应的类中,添加以下代码:

1
2
3
4
5
6
7
8
9
10
11
12
private FragmentToActivity fta;
//定义接口
public interface FragmentToActivity{
//例如发送字符串
void sentDataToActivity(String string);
}
//让Activity能够实现该接口的同时并调用方法
public void getDataFromFragment(FragmentToActivity fta) {
this.fta = fta;
String msg = "Hello! I'm from Fragment";
fta.sentDataToActivity(msg);
}

然后在MainActivity.java中的onClick方法中添加以下代码

1
2
3
4
5
6
fragmentOne.getDataFromFragment(new FragmentOne.FragmentToActivity() {
@Override
public void sentDataToActivity(String string) {
Toast.makeText(MainActivity.this, string, Toast.LENGTH_SHORT).show();
}
});

2.4.2.1 Activity传递数据给Fragment

步骤如下:

  1. 在Activity中创建Bundle数据包,将数据放入Bundle中。
  2. 调用Fragment实例的setArguments(bundle) 从而将Bundle数据包传给Fragment。
  3. 然后Fragment中调用getArguments获得 Bundle对象,,然后进行解析就可以了。

仍然以 2.2 的代码为例,我们来尝试修改fragment的内容。

在MainActivity.java中,需要稍微修改一下代码。

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
protected void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
setContentView(R.layout.activity_main);

Button btn = findViewById(R.id.changefragmentbtn);
btn.setOnClickListener(this);
//改为公共对象
fragmentOne = new FragmentOne();
fragmentTwo = new FragmentTwo();
//创建用于通信的bundle
bundleone = new Bundle();
bundletwo = new Bundle();
//设置消息的键值对
bundleone.putString("message","我是秦始皇,打钱!");
bundletwo.putString("message","封我做大将军嘞");
//将bundle传给fragment
fragmentOne.setArguments(bundleone);
fragmentTwo.setArguments(bundletwo);
}

主要改变的是onCreate方法,onClick方法就不需要在创建新的fragment对象,而是使用创建的公共对象。

补充!

不建议将new FragmentOne()出的对象作为公共对象作为fragmentTransaction.add()的参数,这样会导致应用切换出问题。但replace()不会。

然后只需要在fragment子类中的onCreateView方法中额外添加以下代码

1
2
3
4
5
6
textview = FragmentOne.findViewById(R.id.fragmentone_tv);
//获取传过来的bunlde
Bundle bunlde = this.getArguments();
//通过key获得传过来的字符串
message = bunlde.getString("message");
textview.setText(message);

2.4.2.1 Fragment传递数据给Fragment

如果 是一个Fragment 跳转到另一个Fragment,那么可以使用Bundle通信,因为涉及到Fragment的添加,所以还需要FragmentManager。示例代码如下(来自菜鸟教程):

1
2
3
4
5
6
7
8
9
10
FragmentManager fManager = getSupportFragmentManager( );
FragmentTransaction fTransaction = fManager.beginTransaction();
Fragmentthree t1 = new Fragmentthree();
Fragmenttwo t2 = new Fragmenttwo();
Bundle bundle = new Bundle();
bundle.putString("key",id);
t2.setArguments(bundle);
fTransaction.add(R.id.fragmentRoot, t2, "~~~");
fTransaction.addToBackStack(t1);
fTransaction.commit();

如果是两个Fragment需要即时传数据,而非跳转的话,就需要以Activity为媒介,即先在Activity获得fragment1传过来的数据,再传到fragment2中。

这个实现的话感觉是将 2.4.2.1 和 2.4.2.2 中的方法拼接一下。

三、Fragment生命周期

3.1 Fragment生命周期的方法

部分方法解释如下:

  • onAttach():因为Fragment必须依托Activity才能运行,所以该方法的功能是将Fragment与Activity绑定。
  • onCreate():创建Fragment。
  • onCreateView():因为Fragment是有UI界面的,所以该方法的功能是绘制Fragment的UI界面。
  • onActivityCreate():Fragment所在的Activity启动完成后才会被调用。
  • onDestroyView():销毁Fragment的UI视图
  • onDestroy() :销毁Fragment。
  • onDetach():Fragment与Activity解绑。

(来自菜鸟教程的图片)

由此可见,Fragment的运行必须在onAttach()和onDetach()之间,因为Fragment不能独立运行,必须依赖Activity。

3.2 体验Fragment的生命周期

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
public class FragmentOne extends Fragment{

private static final String TAG = "lll";

@Override
public void onAttach(@NonNull Context context) {
super.onAttach(context);
Log.d(TAG, "onAttach: ");
}

@Override
public void onCreate(@Nullable Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
Log.d(TAG, "onCreate: ");
}

@Nullable
@Override
public View onCreateView(@NonNull LayoutInflater inflater, @Nullable ViewGroup container, @Nullable Bundle savedInstanceState) {
//加载fragment
View FragmentOne = inflater.inflate(R.layout.fragmentone, container, false);
Log.d(TAG, "onCreateView: ");
return FragmentOne;

}

@Override
public void onActivityCreated(@Nullable Bundle savedInstanceState) {
super.onActivityCreated(savedInstanceState);
Log.d(TAG, "onActivityCreated: ");
}

@Override
public void onStart() {
super.onStart();
Log.d(TAG, "onStart: ");
}

@Override
public void onResume() {
super.onResume();
Log.d(TAG, "onResume: ");
}

@Override
public void onPause() {
super.onPause();
Log.d(TAG, "onPause: ");
}

@Override
public void onStop() {
super.onStop();
Log.d(TAG, "onStop: ");
}

@Override
public void onDestroyView() {
super.onDestroyView();
Log.d(TAG, "onDestroyView: ");
}

@Override
public void onDestroy() {
super.onDestroy();
Log.d(TAG, "onDestroy: ");
}

@Override
public void onDetach() {
super.onDetach();
Log.d(TAG, "onDetach: ");
}

}

通过观察Logcat中的信息,可以知道:

  1. 从无到有显示Fragment:onAttach() -> onCreate() -> onCreateView() -> onActivityCreated() -> onStart() -> onResume()
  2. 基于1,之后按下home键:onPause() -> onStop()
  3. 基于2,重新进入:onStart() -> onResume()
  4. 基于3,按回退键:onPause() -> onStop() -> onDestroyView() -> onDestroy() -> onDetach()
  5. 被另一个UI完全替换:onPause() -> onStop() -> onDestroyView()
  6. 基于5,直接退出应用:onDestroy() -> onDetach()
  7. 基于5,再次替换回来:onCreateView() -> onActivityCreated() -> onStart() -> onResume()

四、Fragment + ViewPager实现简单点的微信程序页面

实现页面滑动能够与底部导航栏进行同步。

当然,BottomNavigationView已经实现了这一功能,以后使用这个组件即可,就不需要那么麻烦了。

话不多说,开始实操!

首先编写activity_main.xml的内容:

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
<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"
tools:context=".MainActivity"
android:orientation="vertical">

<androidx.viewpager2.widget.ViewPager2
android:id="@+id/id_viewpager"
android:layout_width="match_parent"
android:layout_height="0dp"
android:layout_weight="1"/>

<LinearLayout
android:layout_width="match_parent"
android:layout_height="wrap_content"
android:orientation="horizontal"
android:gravity="center"
>
<!-- 第一个按钮-->
<LinearLayout
android:id="@+id/id_chatlayout"
android:layout_width="match_parent"
android:layout_height="match_parent"
android:layout_weight="1"
android:orientation="vertical"
android:gravity="center"
>
<ImageView
android:id="@+id/id_chatimage"
android:src="@drawable/baseline_message_24"
android:layout_width="wrap_content"
android:layout_height="wrap_content"
app:tint="@color/buttoncolorchange"/>
<TextView
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:text="微信"
android:textSize="24sp"
/>
</LinearLayout>

<!-- 第二个按钮-->
<LinearLayout
android:id="@+id/id_contactlayout"
android:layout_width="match_parent"
android:layout_height="match_parent"
android:layout_weight="1"
android:orientation="vertical"
android:gravity="center"
>
<ImageView
android:id="@+id/id_contactimage"
android:src="@drawable/baseline_contacts_24"
android:layout_width="wrap_content"
android:layout_height="wrap_content"
app:tint="@color/buttoncolorchange"/>
<TextView
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:text="联系人"
android:textSize="24sp"
/>
</LinearLayout>

<!-- 第三个按钮-->
<LinearLayout
android:id="@+id/id_findlayout"
android:layout_width="match_parent"
android:layout_height="match_parent"
android:layout_weight="1"
android:orientation="vertical"
android:gravity="center"
>
<ImageView
android:id="@+id/id_findimage"
android:src="@drawable/baseline_compass_calibration_24"
android:layout_width="wrap_content"
android:layout_height="wrap_content"
app:tint="@color/buttoncolorchange"/>
<TextView
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:text="发现"
android:textSize="24sp"
/>
</LinearLayout>

<!-- 第四个按钮-->
<LinearLayout
android:id="@+id/id_melayout"
android:layout_width="match_parent"
android:layout_height="match_parent"
android:layout_weight="1"
android:orientation="vertical"
android:gravity="center"
>
<ImageView
android:id="@+id/id_meimage"
android:src="@drawable/baseline_account_box_24"
android:layout_width="wrap_content"
android:layout_height="wrap_content"
app:tint="@color/buttoncolorchange"/>
<TextView
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:text="我"
android:textSize="24sp"
/>
</LinearLayout>

</LinearLayout>

</LinearLayout>

整体布局为:底部为导航栏,其余空间给viewpager2。导航栏分四个按钮(跟微信一样),其中ImageView的tint属性可以实现图片颜色的变化,这样就不需要用到两张图来切换了,buttoncolorchange.xml 的内容如下:

1
2
3
4
<selector xmlns:android="http://schemas.android.com/apk/res/android">
<item android:color="#5cd849" android:state_selected="true"/>
<item android:color="#ffffff"/>
</selector>

底部导航栏的四个按钮分别有对应的四个页面(fragment),它们通过FragmentAdapter以及Fragment来实现,对应的xml文件我写的比较简陋,就一个TextView。(这个文件通过创建Fragment类会自动生成,不需要自己再创建)

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
<FrameLayout xmlns:android="http://schemas.android.com/apk/res/android"
xmlns:tools="http://schemas.android.com/tools"
android:layout_width="match_parent"
android:layout_height="match_parent"
tools:context=".WechatFragment">

<TextView
android:id="@+id/id_textView"
android:layout_width="match_parent"
android:layout_height="match_parent"
android:textSize="32sp"
android:layout_gravity="center"
android:gravity="center"
android:textColor="#FFFF00"
/>

</FrameLayout>

既然使用了Viewpager2和Fragment,那么就要编写对应的FragmentAdapter和Fragment类。其中Viewpage的Adapter编写如下(需要注意继承的是FragmentStateAdapter):

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
public class WechatViewAdapter extends FragmentStateAdapter {
//用于存储四个页面(fragment)
private List<Fragment> fragmentList;

public WechatViewAdapter(@NonNull FragmentManager fragmentManager, @NonNull Lifecycle lifecycle, List<Fragment> fragmentList) {
super(fragmentManager, lifecycle);
this.fragmentList = fragmentList;
}

@NonNull
@Override
public Fragment createFragment(int position) {
return fragmentList.get(position);
}

@Override
public int getItemCount() {
return fragmentList == null ? 0 : fragmentList.size();
}
}

Fragment对应的Fragment类编写如下:

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
public class WechatFragment extends Fragment {

//bundle的key
private static final String ARG_PARAM1 = "key1";
//fragment对应的视图
private View rootView;
//通过key获取的消息
private String mParam1;

//创建fragment的实例对象
public static WechatFragment newInstance(String param1) {
WechatFragment fragment = new WechatFragment();
Bundle args = new Bundle();
args.putString(ARG_PARAM1, param1);
fragment.setArguments(args);
return fragment;
}

@Override
public void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
if (getArguments() != null) {
mParam1 = getArguments().getString(ARG_PARAM1);
}
}

@Override
public View onCreateView(LayoutInflater inflater, ViewGroup container,
Bundle savedInstanceState) {
if (rootView == null){
rootView = inflater.inflate(R.layout.fragment_wechat, container, false);
}
//对组件做一些初始化
initView();
return rootView;
}
//设置页面要展示的内容
private void initView() {

TextView textView = rootView.findViewById(R.id.id_textView);
textView.setText(mParam1);

}

}

当然,对于这个实战来讲,其实可以不用写那么复杂。

因为四个页面我使用的都是相同的fragment的xml文件,所以这里创建一个fragment类即可。

最主要的是MainActivity.java,代码如下:

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
public class MainActivity extends AppCompatActivity implements View.OnClickListener{
//存放四个页面对应的实例化对象
private List<Fragment> fragmentList;
//存放viewpager组件对应的实例化对象
private ViewPager2 viewpager;
//存放底部导航栏的四个"按钮"对应的实例化对象
private ArrayList<LinearLayout> linearLayoutArrayList;
//存放底部导航栏的四个"按钮"的图片的实例化对象
private ArrayList<ImageView> imageViewArrayList;
//存放当前页面对应的"按钮"的图片(当页面进行切换时,旧的当前页面对应的按钮图片的选中状态需要改变,通过这个对象来进行操作)。
private ImageView currentImageView;

@Override
protected void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
setContentView(R.layout.activity_main);
//进行viewpager的初始化,即四个fragment的初始化
initPager();
//进行底部导航栏的初始化
initBottomNavigation();

}

//初始化viewpager
private void initPager() {
//常规操作......
//找到viewpager控件,以便后续设置adapter
viewpager = findViewById(R.id.id_viewpager);
//实例化四个页面的fragment
fragmentList = new ArrayList<>();
fragmentList.add(WechatFragment.newInstance("聊天"));
fragmentList.add(WechatFragment.newInstance("通讯录"));
fragmentList.add(WechatFragment.newInstance("发现"));
fragmentList.add(WechatFragment.newInstance("我的"));

WechatViewAdapter wechatViewAdapter = new WechatViewAdapter(getSupportFragmentManager(), getLifecycle(), fragmentList);
viewpager.setAdapter(wechatViewAdapter);

//设置viewpager的滑动监听,以便在滑动页面的时候,底部导航栏的按钮颜色也能跟着改变
viewpager.registerOnPageChangeCallback(new ViewPager2.OnPageChangeCallback() {
@Override
//页面被选中,通过实现该方法来与导航栏关联
public void onPageSelected(int position) {
super.onPageSelected(position);
//告诉底部导航栏使用哪个page,然后对应item变色
chageBottomNavigationItem(position);
}

});

}
//初始化底部导航栏,即获取四个"按钮",然后设置监听,最后默认
private void initBottomNavigation() {
//获取四个"按钮"
linearLayoutArrayList = new ArrayList<>();

linearLayoutArrayList.add(findViewById(R.id.id_chatlayout));
linearLayoutArrayList.add(findViewById(R.id.id_contactlayout));
linearLayoutArrayList.add(findViewById(R.id.id_findlayout));
linearLayoutArrayList.add(findViewById(R.id.id_melayout));
//循环设置监听
for (LinearLayout each : linearLayoutArrayList) {
each.setOnClickListener(this);
}
//获取四个"按钮"的图片
imageViewArrayList = new ArrayList<>();

imageViewArrayList.add(findViewById(R.id.id_chatimage));
imageViewArrayList.add(findViewById(R.id.id_contactimage));
imageViewArrayList.add(findViewById(R.id.id_findimage));
imageViewArrayList.add(findViewById(R.id.id_meimage));

//ViewPager首先展示的是第一个页面,所以对应的"按钮"图片为选中状态
currentImageView = imageViewArrayList.get(0);
currentImageView.setSelected(true);

}

@Override
public void onClick(View view) {
//点击底部导航栏触发页面切换
chageBottomNavigationItem(view.getId());
}

//实现滑动和"按钮"点击带来的页面切换和"按钮"图片改变
private void chageBottomNavigationItem(int positon) {
//因为不能使用switch-case,所以if不太好写
currentImageView.setSelected(false);
if (positon == R.id.id_chatlayout) {//点击导航栏的item来切换页面
//真正进行页面切换
viewpager.setCurrentItem(0);
//对应的新页面的"按钮"图片设置为当前页面的"按钮"图片
currentImageView = imageViewArrayList.get(0);
} else if (positon == 0) {//通过滑动来切换页面
currentImageView = imageViewArrayList.get(0);
} else if (positon == R.id.id_contactlayout) {
viewpager.setCurrentItem(1);
currentImageView = imageViewArrayList.get(1);
} else if (positon == 1) {
currentImageView = imageViewArrayList.get(1);
} else if (positon == R.id.id_findlayout) {
viewpager.setCurrentItem(2);
currentImageView = imageViewArrayList.get(2);
} else if (positon == 2) {
currentImageView = imageViewArrayList.get(2);
} else if (positon == R.id.id_melayout) {
viewpager.setCurrentItem(3);
currentImageView = imageViewArrayList.get(3);
} else if (positon == 3) {
currentImageView = imageViewArrayList.get(3);
}
//新的页面对应的item的选中状态先设置为true
currentImageView.setSelected(true);

}

}

Android开发学习笔记(三) —— 探究Fragment
http://example.com/2023/08/12/Android安全/Android开发学习笔记(三) —— 探究Fragment/
作者
gla2xy
发布于
2023年8月12日
许可协议