1. Fragment
使用Fragment的目标:根据列表动态显示内容,更简洁显示界面、查找界面
eg. 使用新闻列表动态显示新闻
1.1 Fragment的特性
- 具备生命周期 —— 可以动态地移除一些Fragment
- 必须委托在Activity中使用
- 可以在Activity中进行复用
1.2 Fragment的基本使用步骤
- 在包中添加一个空的Fragment板块(生成一个java文件和一个xml文件)
- 设置(Fragment)xml文件布局
<?xml version="1.0" encoding="utf-8"?>
<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"
android:orientation="vertical"
tools:context=".BlankFragment1">
<!-- TODO: Update blank fragment layout -->
<TextView
android:id="@+id/fragment1_textview"
android:layout_width="match_parent"
android:layout_height="40dp"
android:text="@string/hello_blank_fragment" />
<Button
android:id="@+id/fragment1_button"
android:layout_width="match_parent"
android:text="how are you"
android:layout_height="40dp"/>
</FrameLayout>
- 在java文件中设计相关逻辑处理
package com.example.byfragmenttestmyself;
import android.graphics.Color;
import android.os.Bundle;
import androidx.fragment.app.Fragment;
import android.view.Gravity;
import android.view.LayoutInflater;
import android.view.View;
import android.view.ViewGroup;
import android.widget.Button;
import android.widget.TextView;
import android.widget.Toast;
// 这个类继承自(拓展于) Fragment
public class BlankFragment1 extends Fragment {
private View root = null;
private TextView fragment1_textview = null;
private Button fragment1_button = null;
// 生命周期函数 创建时调用
@Override
public void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
}
// 渲染布局文件函数 创建时调用 有返回值
@Override
public View onCreateView(LayoutInflater inflater, ViewGroup container,
Bundle savedInstanceState) {
// 基本渲染判断
if(root == null){
root = inflater.inflate(R.layout.fragment_blank1,container,false);
}
// 获取xml 控件资源
fragment1_textview = root.findViewById(R.id.fragment1_textview);
fragment1_button = root.findViewById(R.id.fragment1_button);
fragment1_button.setOnClickListener(new View.OnClickListener() {
@Override
public void onClick(View v) {
// 使用Toast显示点击后显示的内容
Toast.makeText(getContext(),"I am fine,and you?",Toast.LENGTH_SHORT).show();
}
});
return root;
}
}
- 在需要添加Fragment的Activity文件中添加对应名字的fragment标签(必须添加name和id属性)
<?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组件必须要有的元素有name、id、宽和高-->
<fragment
android:name="com.example.byfragmenttestmyself.BlankFragment1"
android:layout_width="match_parent"
android:layout_height="match_parent"
android:layout_weight="1"
android:id="@+id/main_fragment1" />
<fragment
android:name="com.example.byfragmenttestmyself.BlankFragment2"
android:layout_width="match_parent"
android:layout_height="match_parent"
android:layout_weight="1"
android:id="@+id/main_fragment2" />
</LinearLayout>
1.3 动态添加Fragment基本步骤
- 在主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">
<!--这里可以使用android.widget.Button(不携带背景)-->
<Button
android:background="#00ff00"
android:layout_width="match_parent"
android:layout_height="wrap_content"
android:id="@+id/btn_1"
android:text="@string/change"/>
<Button
android:background="#00ff00"
android:layout_width="match_parent"
android:layout_height="wrap_content"
android:id="@+id/btn_2"
android:text="@string/replace"/>
<FrameLayout
android:background="#3FE8CE"
android:id="@+id/fragment_layout"
android:layout_width="match_parent"
android:layout_height="match_parent">
</FrameLayout>
</LinearLayout>
-
创建两个Fragment
- 我使用的是一个BlackFragment和一个ListFragmen
-
在MainActivity中设置相关的逻辑
- 创建一个待处理的fragment
- 获取FragmentManager,一般都是通过getSupportFragmentManager()
- 开启一个事物transaction,一般调用FragmentManager的beginTransaction()
- 使用transaction进行fagment的替换
- 提交事物
package com.example.fragment2;
import androidx.appcompat.app.AppCompatActivity;
import androidx.fragment.app.Fragment;
import androidx.fragment.app.FragmentManager;
import androidx.fragment.app.FragmentTransaction;
import android.os.Bundle;
import android.view.View;
import android.widget.Button;
public class MainActivity extends AppCompatActivity implements View.OnClickListener {
@Override
protected void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
setContentView(R.layout.activity_main);
{
// 可以将这段代码写进一个initView()函数中
Button button1 = findViewById(R.id.btn_1);
Button button2 = findViewById(R.id.btn_2);
button1.setOnClickListener(this);
button2.setOnClickListener(this);
}
}
@Override
public void onClick(View v) {
if(v.getId() == R.id.btn_1){
replaceFragment(new BlankFragment1());
}else if(v.getId() == R.id.btn_2){
replaceFragment(new ItemFragment());
}
}
// 动态切换fragment
private void replaceFragment(Fragment fragment) {
// 获取默认的fragment管理类,用于管理fragment
FragmentManager fragmentManager = getSupportFragmentManager();
// 获取一个transaction,完成fragment的替换动作
FragmentTransaction transaction = fragmentManager.beginTransaction();
// 替换fragment
transaction.replace(R.id.fragment_layout,fragment);
// 设置一个fragment栈来存储所有添加的fragment
// 在栈内存在fragment的时候,响应由fragment栈来承担,如果栈内没有了fragment,响应由Activity承担
transaction.addToBackStack(null);
// 以上都是事物的处理过程,最后需要提交事物
transaction.commit();
}
}
1.4 Fragment与Activity的通信
原生方案:Bundle类
在上面代码(1.3动态添加Fragment)进行修改
过程
- 修改MainActivity.java文件
@Override
public void onClick(View v) {
if(v.getId() == R.id.btn_1){
// 新建一个Bundle对象
Bundle bundle = new Bundle();
// 向Bundle中传入string数据
bundle.putString("message","我喜欢小学课堂");
// 利用bundle将数据传入Fragment中
BlankFragment1 bf = new BlankFragment1();
bf.setArguments(bundle);
replaceFragment(bf);
}else if(v.getId() == R.id.btn_2){
replaceFragment(new ItemFragment());
}
}
- 修改BlackFragment1文件接收传过来的Bundle数据
@Override
public void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
// 在Fragment中的任意地方接收相应数据
Bundle bundle = this.getArguments();
// 创建一个String作为日志打印输出
String string = null;
if (bundle != null) {
bundle.getString("message");
string = "我好喜欢学习呀。";
Log.d(TAG,"onCreate:" + string);
}
if (getArguments() != null) {
mParam1 = getArguments().getString(ARG_PARAM1);
mParam2 = getArguments().getString(ARG_PARAM2);
}
}
效果
可以在点击Button的时候,在日志中输出一段文字。说明了这段代码实现了数据在Activity和Fragment之间的传递。
深入方案:java类与类通信的方案:接口
Activity从Fragment获取消息
- 定义一个接口
package com.example.fragment2;
public interface IFragmentCallback {
public void sendMsgToActivity(String msg);
public String getMsgFromActivity(String msg);
}
- 在Fragment中写一个接口的实现
private View rootView = null;
// 为MainActivity提供接口,用于创建对象
private IFragmentCallback fragmentCallback;
public void setFragmentCallback(IFragmentCallback callback){
fragmentCallback = callback;
}
@Override
public View onCreateView(LayoutInflater inflater, ViewGroup container,
Bundle savedInstanceState) {
// Inflate the layout for this fragment
// 防止被解析多次,定义成一个全局变量
if(rootView == null){
rootView = inflater.inflate(R.layout.fragment_blank1,container,false);
}
Button btn = rootView.findViewById(R.id.btn_3);
btn.setOnClickListener(new View.OnClickListener() {
@Override
public void onClick(View v) {
// 调用方法传递数值
fragmentCallback.sendMsgToActivity("hello,I am from Fragment");
}
});
return rootView;
}
- 在MainActivity中实现前面定义的接口(在点击事件处理中),等待后面Fragment中的调用
public void onClick(View v) {
if(v.getId() == R.id.btn_1){
// 新建一个Bundle对象
Bundle bundle = new Bundle();
// 向Bundle中传入string数据
bundle.putString("message","我喜欢小学课堂");
// 利用bundle将数据传入Fragment中
BlankFragment1 bf = new BlankFragment1();
bf.setFragmentCallback(new IFragmentCallback() {
@Override
public void sendMsgToActivity(String msg) {
Toast.makeText(MainActivity.this,msg,Toast.LENGTH_SHORT).show();
}
@Override
public String getMsgFromActivity(String msg) {
return null;
}
});
bf.setArguments(bundle);
replaceFragment(bf);
}else if(v.getId() == R.id.btn_2){
replaceFragment(new ItemFragment());
}
}
Fragment从Activity获取消息
从上面代码修改:
- 修改Fragment点击事件
@Override
public void onClick(View v) {
// fragmentCallback.sendMsgToActivity("hello,I am from Fragment");
String msg = fragmentCallback.getMsgFromActivity("null");
Toast.makeText(getContext(),msg,Toast.LENGTH_SHORT).show();
}
- 修改MainActivity的接口方法重写
bf.setFragmentCallback(new IFragmentCallback() {
@Override
public void sendMsgToActivity(String msg) {
Toast.makeText(MainActivity.this,msg,Toast.LENGTH_SHORT).show();
}
@Override
public String getMsgFromActivity(String msg) {
return "hello,I am from Activity";
}
});
比较巧妙的是:函数的返回值为数据的发送和接受实现了不同的逻辑处理,体现了代码的高内聚
其他方案:enventBus、LiveData
使用的设计模式:发布订阅模式、观察者模式
Fragment可以观察Activity,Fragment可以选择地使用。
1.5 Fragment的生命周期
上面有一个onAttach
方法没有被官方文档显示(我也不知道为啥)于是我在文心一言上问了一下,得到了一下的结果:
onAttach(Activity activity)
: 这是较旧的方法,但在较新的 Android 版本中仍然可用。当您使用这种方法时,您需要确保在代码中适当地处理它,因为Activity
参数可能是null
(尽管这在正常情况下不应该发生)。onAttach(Context context)
: 这是较新的方法,它允许您接收一个Context
对象,该对象可以是Activity
或其他类型的上下文(尽管在Fragment
的情况下,它通常是一个Activity
)。这种方法提供了更灵活的方式来处理与宿主Activity
的关联,并且不需要担心Activity
参数为null
的情况。
总而言之,onAttach的作用就是绑定与之对应的父类。
注意:
当我们以后在
Fragment
中获取Activity
,返回值为空的时候就是因为我们没有将所有的周期函数写在Activity
中
详情请点击链接
操作Fragment时生命周期的运行情况
打开界面
onCreate() -> onCreateView() -> onActivityCreated() -> onStart() -> onResume()
按下主屏键
onPause() -> onStop()
重新打开界面
onStart() -> onResume()
按后退键
onPause() -> onStop() -> onDestroyView() -> onDestroy() -> onDetach()
1.6 Fragment与ViewPager2联合使用
优势:减少用户的操作;
ViewPager2与ViewPager2的优势:
ViewPager1是以GridLayout作为底层来生成的;ViewPager2是以ListLayout为底层逻辑生成的。ViewPager2具有懒加载的特性
ViewPager2简单使用的步骤
- 定义一个ViewPager2
<!--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">
<androidx.viewpager2.widget.ViewPager2
android:layout_width="match_parent"
android:layout_height="match_parent"
android:id="@+id/viewPager"
android:background="@color/blue">
</androidx.viewpager2.widget.ViewPager2>
</LinearLayout>
<!--item_pager.xml-->
<?xml version="1.0" encoding="utf-8"?>
<RelativeLayout xmlns:android="http://schemas.android.com/apk/res/android"
android:layout_width="match_parent"
android:id="@+id/container__"
android:layout_height="match_parent">
<TextView
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:id="@+id/tvTitle"
android:layout_centerInParent="true"
android:textColor="#ff4532"
android:textSize="32sp"
android:text="hello"/>
</RelativeLayout>
<!--color.xml-->
<?xml version="1.0" encoding="utf-8"?>
<resources>
<color name="black">#FF000000</color>
<color name="white">#FFFFFFFF</color>
<color name="blue">#0000FF</color>
<color name="red">#FF0000</color>
<color name="yellow">#FFFF00</color>
</resources>
// MainActivity.java
package com.example.viewpager;
import androidx.appcompat.app.AppCompatActivity;
import androidx.viewpager2.widget.ViewPager2;
import android.os.Bundle;
import android.view.View;
public class MainActivity extends AppCompatActivity {
@Override
protected void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
setContentView(R.layout.activity_main);
ViewPager2 viewPager = findViewById(R.id.viewPager);
ViewPagerAdapter viewPagerAdapter = new ViewPagerAdapter();
viewPager.setAdapter(viewPagerAdapter);
}
}
- 为ViewPager2构建Adapter
// ViewPagerAdapter.java
package com.example.viewpager;
import android.view.LayoutInflater;
import android.view.View;
import android.view.ViewGroup;
import android.widget.RelativeLayout;
import android.widget.TextView;
import androidx.annotation.NonNull;
import androidx.recyclerview.widget.RecyclerView;
import java.util.ArrayList;
import java.util.List;
// 下面的拓展RecyclerView.Adapter可以通过前面的调用自动生成
public class ViewPagerAdapter extends RecyclerView.Adapter<ViewPagerAdapter.ViewPagerViewHolder> {
private List<String> title = new ArrayList<>();
private List<Integer> colors = new ArrayList<>();
// 根据下面的页面数量适配相应数量的数据
public ViewPagerAdapter(){
title.add("hello");
title.add("520");
title.add("我爱你");
title.add("6.1快乐");
colors.add(R.color.yellow);
colors.add(R.color.blue);
colors.add(R.color.red);
colors.add(R.color.white);
}
@NonNull
// ViewPager的适配界面
@Override
public ViewPagerViewHolder onCreateViewHolder(@NonNull ViewGroup parent, int viewType) {
return new ViewPagerViewHolder(LayoutInflater.from(parent.getContext()).
inflate(R.layout.item_pager,parent,false));
}
// 对列表中的数据进行绑定
@Override/*position 显示当前滑动的是哪一个item*/
public void onBindViewHolder(@NonNull ViewPagerViewHolder holder, int position) {
holder.mTextView.setText(title.get(position));
// 上面做链表的时候传入的是一个资源的id,所以这里的方法需要用setBackgroundResource()
// 如果需要设置的是一个color,可以添加#000000~#FFFFFF
holder.mContainer.setBackgroundResource(colors.get(position));
}
// 返回页面的数量
@Override
public int getItemCount() {
return 4;
}
// 定义一个内部类专门用于RecyclerView的封装
class ViewPagerViewHolder extends RecyclerView.ViewHolder{
TextView mTextView = null;
RelativeLayout mContainer = null;
public ViewPagerViewHolder(@NonNull View itemView) {
super(itemView);
// 参数 View 就是item_pager.xml布局文件
mContainer = itemView.findViewById(R.id.container__);
mTextView = itemView.findViewById(R.id.tvTitle);
}
}
}
ViewPager2 + Fragment形成翻页效果
activity作为宿主,Fragment附庸在宿主上显示
<!--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:orientation="vertical"
android:layout_height="match_parent"
tools:context=".MainActivity">
<!-- 高度设置为0dp可以实现适应性填充-->
<androidx.viewpager2.widget.ViewPager2
android:layout_width="match_parent"
android:layout_height="0dp"
android:layout_weight="1"
android:id="@+id/viewpager"/>
</LinearLayout>
// MainActivity.java
package com.example.wechatpage;
import androidx.appcompat.app.AppCompatActivity;
import androidx.fragment.app.Fragment;
import androidx.viewpager2.widget.ViewPager2;
import android.os.Bundle;
import java.util.ArrayList;
public class MainActivity extends AppCompatActivity {
ViewPager2 viewPager = null;
@Override
protected void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
setContentView(R.layout.activity_main);
initPager();
}
private void initPager() {
viewPager = findViewById(R.id.viewpager);
ArrayList<Fragment> fragments = new ArrayList<>();
fragments.add(BlankFragment.newInstance("微信聊天"));
fragments.add(BlankFragment.newInstance("通讯录"));
fragments.add(BlankFragment.newInstance("发现"));
fragments.add(BlankFragment.newInstance("我"));
MyFragmentPagerAdapter pagerAdapter = new MyFragmentPagerAdapter(getSupportFragmentManager(),
// 第二个参数使用了jetpack控件 现在的版本主要使用 vm 和 mv 模式中调用
getLifecycle(),fragments);
viewPager.setAdapter(pagerAdapter);
}
}
<!--fragment_blank.xml-->
<?xml version="1.0" encoding="utf-8"?>
<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"
android:orientation="vertical"
tools:context=".BlankFragment">
<!-- TODO: Update blank fragment layout -->
<TextView
android:layout_width="match_parent"
android:layout_height="match_parent"
android:gravity="center"
android:textSize="36sp"
android:id="@+id/text_word"
android:text="@string/hello_blank_fragment" />
</FrameLayout>
// BlackFragment.java
package com.example.wechatpage;
import android.os.Bundle;
import androidx.fragment.app.Fragment;
import android.view.LayoutInflater;
import android.view.View;
import android.view.ViewGroup;
import android.widget.TextView;
public class BlankFragment extends Fragment {
View rootView = null;
private static final String ARG_TEXT = "param1";
private String mTextString;
public BlankFragment() {
// Required empty public constructor
}
// 将参数传入Bundle对象
public static BlankFragment newInstance(String param1) {
BlankFragment fragment = new BlankFragment();
Bundle args = new Bundle();
args.putString(ARG_TEXT, param1);
fragment.setArguments(args);
return fragment;
}
@Override
public void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
if (getArguments() != null) {
// 通过获取Bundle的方式获取参数的值
mTextString = getArguments().getString(ARG_TEXT);
}
}
@Override
public View onCreateView(LayoutInflater inflater, ViewGroup container,
Bundle savedInstanceState) {
// 防止重复解析xml造成的资源浪费
if(rootView == null){
rootView = inflater.inflate(R.layout.fragment_blank, container, false);
}
initView();
return rootView;
}
private void initView() {
TextView textView = rootView.findViewById(R.id.text_word);
textView.setText(mTextString);
}
}
// MyFragmentPagerAdapter.java
package com.example.wechatpage;
import androidx.annotation.NonNull;
import androidx.fragment.app.Fragment;
import androidx.fragment.app.FragmentManager;
import androidx.lifecycle.Lifecycle;
import androidx.viewpager2.adapter.FragmentStateAdapter;
import java.util.ArrayList;
import java.util.List;
public class MyFragmentPagerAdapter extends FragmentStateAdapter {
List<Fragment> fragments = new ArrayList<>();
public MyFragmentPagerAdapter(@NonNull FragmentManager fragmentManager, @NonNull Lifecycle lifecycle,List<Fragment> fragmentList) {
super(fragmentManager, lifecycle);
fragments = fragmentList;
}
@NonNull
@Override
public Fragment createFragment(int position) {
return fragments.get(position);
}
@Override
public int getItemCount() {
return fragments.size();
}
}
实现效果:翻页中间屏幕显示相应文字
ViewPager2 + Fragment模拟微信翻页界面
程序中所用到的图片链接如下
https://img.picui.cn/free/2024/06/02/665bd7676b127.png
https://img.picui.cn/free/2024/06/02/665bd7677abd5.png
https://img.picui.cn/free/2024/06/02/665bd7679745d.png
https://img.picui.cn/free/2024/06/02/665bd7676583f.png
https://img.picui.cn/free/2024/06/02/665bd76784bce.png
https://img.picui.cn/free/2024/06/02/665bd768c1583.png
https://img.picui.cn/free/2024/06/02/665bd7693a984.png
https://img.picui.cn/free/2024/06/02/665bd76a323ce.png
颜色资源
<?xml version="1.0" encoding="utf-8"?>
<resources>
<color name="black">#FF000000</color>
<color name="white">#FFFFFFFF</color>
<color name="blue">#5656FF</color>
<color name="green">#00FF00</color>
</resources>
drawable资源
<!--tab_contact.xml-->
<?xml version="1.0" encoding="utf-8"?>
<selector xmlns:android="http://schemas.android.com/apk/res/android">
<item android:drawable="@drawable/contacts_pressed" android:state_selected="true"/>
<item android:drawable="@drawable/contacts_normal"/>
</selector>
<!--tab_me.xml-->
<?xml version="1.0" encoding="utf-8"?>
<selector xmlns:android="http://schemas.android.com/apk/res/android">
<item android:drawable="@drawable/me_pressed" android:state_selected="true"/>
<item android:drawable="@drawable/me_normal"/>
</selector>
<!--tab_search.xml-->
<?xml version="1.0" encoding="utf-8"?>
<selector xmlns:android="http://schemas.android.com/apk/res/android">
<item android:drawable="@drawable/search_pressed" android:state_selected="true"/>
<item android:drawable="@drawable/search_normal"/>
</selector>
<!--tab_weixin.xml-->
<?xml version="1.0" encoding="utf-8"?>
<selector xmlns:android="http://schemas.android.com/apk/res/android">
<item android:drawable="@drawable/weixin_pressed" android:state_selected="true"/>
<item android:drawable="@drawable/weixin_normal"/>
</selector>
fragment布局设计(可后续修改)
<?xml version="1.0" encoding="utf-8"?>
<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"
android:orientation="vertical"
tools:context=".BlankFragment">
<!-- TODO: Update blank fragment layout -->
<TextView
android:layout_width="match_parent"
android:layout_height="match_parent"
android:gravity="center"
android:textSize="36sp"
android:id="@+id/text_word"
android:text="@string/hello_blank_fragment" />
</FrameLayout>
底边栏布局设计(可后续修改)
<?xml version="1.0" encoding="utf-8"?>
<LinearLayout xmlns:android="http://schemas.android.com/apk/res/android"
android:layout_width="match_parent"
android:orientation="horizontal"
android:layout_height="55dp"
android:background="@color/blue">
<LinearLayout
android:gravity="center_horizontal"
android:layout_width="0dp"
android:layout_height="match_parent"
android:layout_weight="1"
android:layout_gravity="center"
android:orientation="vertical"
android:id="@+id/tab_weixin">
<ImageView
android:layout_width="32dp"
android:layout_height="32dp"
android:id="@+id/tb_image_weixin"
android:background="@drawable/tab_weixin"/>
<TextView
android:layout_width="32dp"
android:layout_height="32dp"
android:id="@+id/text_weixin"
android:gravity="center"
android:text="微信"
android:textColor="@color/green"/>
</LinearLayout>
<LinearLayout
android:gravity="center_horizontal"
android:layout_width="0dp"
android:layout_height="match_parent"
android:layout_weight="1"
android:layout_gravity="center"
android:orientation="vertical"
android:id="@+id/tab_contact">
<ImageView
android:layout_width="32dp"
android:layout_height="32dp"
android:id="@+id/tb_image_contact"
android:background="@drawable/tab_contact"/>
<TextView
android:layout_marginTop="5dp"
android:layout_width="32dp"
android:layout_height="32dp"
android:id="@+id/text_contact"
android:gravity="center"
android:text="通讯录"
android:textColor="@color/green"/>
</LinearLayout>
<LinearLayout
android:gravity="center_horizontal"
android:layout_width="0dp"
android:layout_height="match_parent"
android:layout_weight="1"
android:layout_gravity="center"
android:orientation="vertical"
android:id="@+id/tab_search">
<ImageView
android:layout_marginTop="4dp"
android:layout_width="25dp"
android:layout_height="25dp"
android:id="@+id/tb_image_search"
android:background="@drawable/tab_search"/>
<TextView
android:layout_marginTop="3dp"
android:layout_width="32dp"
android:layout_height="32dp"
android:id="@+id/text_search"
android:gravity="center"
android:text="发现"
android:textColor="@color/green"/>
</LinearLayout>
<LinearLayout
android:gravity="center_horizontal"
android:layout_width="0dp"
android:layout_height="match_parent"
android:layout_weight="1"
android:layout_gravity="center"
android:orientation="vertical"
android:id="@+id/tab_me">
<ImageView
android:layout_width="32dp"
android:layout_height="32dp"
android:id="@+id/tb_image_me"
android:background="@drawable/tab_me"/>
<TextView
android:layout_width="32dp"
android:layout_height="32dp"
android:id="@+id/text_me"
android:gravity="center"
android:text="我的"
android:textColor="@color/green"/>
</LinearLayout>
</LinearLayout>
主界面布局文件设计——需要使用include引用前面的底边栏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:orientation="vertical"
android:layout_height="match_parent"
tools:context=".MainActivity">
<!-- 高度设置为0dp可以实现适应性填充-->
<androidx.viewpager2.widget.ViewPager2
android:layout_width="match_parent"
android:layout_height="0dp"
android:layout_weight="1"
android:id="@+id/viewpager"/>
<!-- 通过include将其他的Activity加入到主Activity中-->
<include layout="@layout/bottom_layout"/>
</LinearLayout>
Fragment.java文件初始化fragment.xml布局文件
package com.example.wechatpage;
import android.os.Bundle;
import androidx.fragment.app.Fragment;
import android.view.LayoutInflater;
import android.view.View;
import android.view.ViewGroup;
import android.widget.TextView;
/**
* A simple {@link Fragment} subclass.
* Use the {@link BlankFragment#newInstance} factory method to
* create an instance of this fragment.
*/
public class BlankFragment extends Fragment {
View rootView = null;
private static final String ARG_TEXT = "param1";
private String mTextString;
public BlankFragment() {
// Required empty public constructor
}
/**
* Use this factory method to create a new instance of
* this fragment using the provided parameters.
*
* @param param1 Parameter 1.
* @return A new instance of fragment BlankFragment.
*/
// TODO: Rename and change types and number of parameters
// 将参数传入Bundle对象
public static BlankFragment newInstance(String param1) {
BlankFragment fragment = new BlankFragment();
Bundle args = new Bundle();
args.putString(ARG_TEXT, param1);
fragment.setArguments(args);
return fragment;
}
@Override
public void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
if (getArguments() != null) {
// 通过获取Bundle的方式获取参数的值
mTextString = getArguments().getString(ARG_TEXT);
}
}
@Override
public View onCreateView(LayoutInflater inflater, ViewGroup container,
Bundle savedInstanceState) {
// 防止重复解析xml造成的资源浪费
if(rootView == null){
rootView = inflater.inflate(R.layout.fragment_blank, container, false);
}
initView();
return rootView;
}
private void initView() {
TextView textView = rootView.findViewById(R.id.text_word);
textView.setText(mTextString);
}
}
适配器匹配ViewPager和Fragment
package com.example.wechatpage;
import androidx.annotation.NonNull;
import androidx.fragment.app.Fragment;
import androidx.fragment.app.FragmentManager;
import androidx.lifecycle.Lifecycle;
import androidx.viewpager2.adapter.FragmentStateAdapter;
import java.util.ArrayList;
import java.util.List;
public class MyFragmentPagerAdapter extends FragmentStateAdapter {
List<Fragment> fragments = new ArrayList<>();
public MyFragmentPagerAdapter(@NonNull FragmentManager fragmentManager, @NonNull Lifecycle lifecycle,List<Fragment> fragmentList) {
super(fragmentManager, lifecycle);
fragments = fragmentList;
}
@NonNull
@Override
public Fragment createFragment(int position) {
return fragments.get(position);
}
@Override
public int getItemCount() {
return fragments.size();
}
}
主要逻辑处理(模板)
package com.example.wechatpage;
import androidx.appcompat.app.AppCompatActivity;
import androidx.fragment.app.Fragment;
import androidx.viewpager2.widget.ViewPager2;
import android.os.Bundle;
import android.view.View;
import android.widget.ImageView;
import android.widget.LinearLayout;
import java.util.ArrayList;
public class MainActivity extends AppCompatActivity implements View.OnClickListener {
ViewPager2 viewPager = null;
private LinearLayout llChat = null;
private LinearLayout llContacts = null;
private LinearLayout llSearch = null;
private LinearLayout llMe = null;
private ImageView ivChat = null;
private ImageView ivContacts = null;
private ImageView ivSearch = null;
private ImageView ivMe = null;
private ImageView ivCurrent = null;
@Override
protected void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
setContentView(R.layout.activity_main);
initPager();
initTableView();
}
private void initTableView() {
llChat = findViewById(R.id.tab_weixin);
llContacts = findViewById(R.id.tab_contact);
llSearch = findViewById(R.id.tab_search);
llMe = findViewById(R.id.tab_me);
ivChat = findViewById(R.id.tb_image_weixin);
ivContacts = findViewById(R.id.tb_image_contact);
ivSearch = findViewById(R.id.tb_image_search);
ivMe = findViewById(R.id.tb_image_me);
llChat.setOnClickListener(this);
llContacts.setOnClickListener(this);
llSearch.setOnClickListener(this);
llMe.setOnClickListener(this);
// 设置缓存按钮,用于后来复位
ivChat.setSelected(true);
ivCurrent = ivChat;
}
private void initPager() {
viewPager = findViewById(R.id.viewpager);
ArrayList<Fragment> fragments = new ArrayList<>();
fragments.add(BlankFragment.newInstance("微信聊天"));
fragments.add(BlankFragment.newInstance("通讯录"));
fragments.add(BlankFragment.newInstance("发现"));
fragments.add(BlankFragment.newInstance("我"));
MyFragmentPagerAdapter pagerAdapter = new MyFragmentPagerAdapter(getSupportFragmentManager(),
// 第二个参数使用了jetpack控件 现在的版本主要使用 vm 和 mv 模式中调用
getLifecycle(),fragments);
// 设置viewPager的内容
viewPager.setAdapter(pagerAdapter);
// 设置viewPager的滑动监听接口
viewPager.registerOnPageChangeCallback(new ViewPager2.OnPageChangeCallback() {
@Override// 此方法可以为viewPager添加滚动动画效果
public void onPageScrolled(int position, float positionOffset, int positionOffsetPixels) {
super.onPageScrolled(position, positionOffset, positionOffsetPixels);
}
@Override// 改变按钮的选择位置
public void onPageSelected(int position) {
super.onPageSelected(position);
changeTable(position);
}
@Override//
public void onPageScrollStateChanged(int state) {
super.onPageScrollStateChanged(state);
}
});
}
private void changeTable(int position) {
ivCurrent.setSelected(false);
if(position == 0){
ivChat.setSelected(true);
ivCurrent = ivChat;
}else if(position == 1){
ivContacts.setSelected(true);
ivCurrent = ivContacts;
}else if(position == 2){
ivSearch.setSelected(true);
ivCurrent = ivSearch;
}else if(position == 3){
ivMe.setSelected(true);
ivCurrent = ivMe;
}
}
@Override
public void onClick(View v) {
ivCurrent.setSelected(false);
if(v.getId() == R.id.tab_weixin){
ivChat.setSelected(true);
ivCurrent = ivChat;
viewPager.setCurrentItem(0);
}else if(v.getId() == R.id.tab_contact){
ivContacts.setSelected(true);
ivCurrent = ivContacts;
viewPager.setCurrentItem(1);
}else if(v.getId() == R.id.tab_search){
ivSearch.setSelected(true);
ivCurrent = ivSearch;
viewPager.setCurrentItem(2);
}else if(v.getId() == R.id.tab_me){
ivMe.setSelected(true);
ivCurrent = ivMe;
viewPager.setCurrentItem(3);
}
}
}
虽然很想写一下fragment和ViewPager的底层逻辑,但是时间有点不够了,要找资料,敲代码,写markdown……总而言之太麻烦了!,所以等有空的时候再补上吧画饼!