先上图:已售、已退、已废 为分类标题;预加载数的意思是:例,预加载 1,页,就是“已退”的标题的数据预加载了
思路:在fragment里,再放fragment,通过滑动事件就可以切换fragment里的fragment了。
以下为实现步骤
Step 1:首先准备好fragment
在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>
准备两个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:orientation="vertical"
android:layout_width="match_parent"
android:layout_height="match_parent">
</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="wrap_content"
android:layout_height="wrap_content"
android:text="我的"/>
</LinearLayout>
准备两个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) {
View view=inflater.inflate(R.layout.fragment_home,container,false);
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;
}
}
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>
fragment创建完成,开始使用fragment,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();
}
}
Step 2:fragment准备好后,引入依赖:
//列表
implementation 'androidx.recyclerview:recyclerview:1.1.0'
//下拉刷新,上拉加载
implementation 'com.scwang.smartrefresh:SmartRefreshLayout:1.1.1' //1.0.5及以前版本的老用户升级需谨慎,API改动过大
implementation 'com.scwang.smartrefresh:SmartRefreshHeader:1.1.1' //没有使用特殊Header,可以不加这行
// 滑动
implementation 'androidx.viewpager2:viewpager2:1.0.0'
//TableLayout
implementation "com.google.android.material:material:1.1.0"
Step 3 :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:background="@color/colorWhite"
xmlns:app="http://schemas.android.com/apk/res-auto"
android:orientation="vertical">
<!--头部fragment 分类切换-->
<com.google.android.material.tabs.TabLayout
android:id="@+id/tl_order_title"
android:layout_width="match_parent"
android:layout_height="50dp"
app:tabGravity="fill"
app:tabIndicatorColor="@color/colorPrimary"
app:tabMode="fixed"
app:tabSelectedTextColor="@color/colorPrimaryDark"
app:tabTextColor="@color/colorPrimary"/>
<!-- fragment 里的内容-->
<androidx.viewpager2.widget.ViewPager2
android:id="@+id/vp_order_container"
android:layout_width="match_parent"
android:layout_height="match_parent"
android:orientation="horizontal"/>
</LinearLayout>
Step 4:创建一个fragment,如 HomeListFragment,用于根据 HomeFragment 传过来的类型,返回相应的fragment 进而让 HomeFragment ,可以根据其传过来的frame数据类型,HomeFragment就变成相应的fragment, 所以,HomeListFragment 的准备和创建如下:
1.新建 item_test.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="wrap_content"
android:layout_marginRight="10dp"
android:layout_marginLeft="10dp"
android:layout_marginTop="10dp">
<LinearLayout
android:layout_width="match_parent"
android:layout_height="wrap_content"
android:orientation="horizontal">
<LinearLayout
android:layout_width="0dp"
android:layout_height="wrap_content"
android:layout_weight="1"
android:orientation="vertical">
<LinearLayout
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:orientation="horizontal">
<TextView
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:text="票号:"/>
<TextView
android:id="@+id/tv_qingkuang_piaohao"
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:text="xx"/>
</LinearLayout>
</LinearLayout>
<LinearLayout
android:layout_width="0dp"
android:layout_height="wrap_content"
android:layout_weight="1"
android:orientation="vertical">
<LinearLayout
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:layout_gravity="center"
android:orientation="horizontal">
<TextView
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:text="班次:"/>
<TextView
android:id="@+id/tv_qingkuang_banci"
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:text="xx"/>
</LinearLayout>
</LinearLayout>
<LinearLayout
android:layout_width="0dp"
android:layout_height="wrap_content"
android:layout_weight="1"
android:orientation="vertical">
<LinearLayout
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:layout_gravity="right"
android:orientation="horizontal">
<TextView
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:text="用户:"/>
<TextView
android:id="@+id/tv_qingkuang_yonghu"
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:text="xx"/>
</LinearLayout>
</LinearLayout>
</LinearLayout>
</LinearLayout>
2.新建 fragment_test_list.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">
<com.scwang.smartrefresh.layout.SmartRefreshLayout
android:id="@+id/srl_test_list"
android:layout_width="match_parent"
android:layout_height="match_parent">
<androidx.recyclerview.widget.RecyclerView
android:id="@+id/rv_test_list"
android:layout_width="match_parent"
android:layout_height="match_parent"
android:overScrollMode="never"
android:background="@color/colorWhite"/>
</com.scwang.smartrefresh.layout.SmartRefreshLayout>
</LinearLayout>
3.新建适配器:TestAdapter,代码如下:
//=========Step 2:继承 RecyclerView.Adapter,类型为刚才的内部类,
// 然后实现onCreateViewHolder、onBindViewHolder、getItemCount方法
public class TestAdapter extends RecyclerView.Adapter<TestAdapter.ViewHolder> {
//要加载的数据,ShouPiaoQingKuangVo为 bean类,存放服务端的一条数据的,请根据自己服务端的类型写bean类
private List<ShouPiaoQingKuangVo> list=new ArrayList<>();
//创建ViewHolder
@NonNull
@Override
public ViewHolder onCreateViewHolder(@NonNull ViewGroup parent, int viewType) {
View view= LayoutInflater.from(parent.getContext()).inflate(R.layout.item_test,parent,false);
return new ViewHolder(view);
}
//绑定数据
@Override
public void onBindViewHolder(@NonNull ViewHolder holder, int position) {
ShouPiaoQingKuangVo vo=list.get(position);
if(vo!=null){
holder.tvPiaohao.setText(vo.getNote());
holder.tvBanCi.setText(vo.getClassesnumber());
holder.tvYongHu.setText(vo.getName());
}
}
//告诉RecyclerView有多少条数据
@Override
public int getItemCount() {
return list.size();
}
//=====对外方法,用于分页添加数据
public void addItem(List<ShouPiaoQingKuangVo> listAdd, int loadPage,Integer type){
if(loadPage==1){
//如果加载第一页,需要先清空数据列表
this.list.clear();
//添加数据
if (listAdd != null) {
this.list.addAll(listAdd);
}
//通知RecyclerView进行改变--整体
notifyDataSetChanged();
}else{
//不是第一页
//添加数据
int newCount=this.list.size();
if (listAdd!=null){
this.list.addAll(listAdd);
}
//通知RecycleView进行改变---局部刷新
notifyItemRangeChanged(newCount,list.size());
}
}
//=====Step 1:创建内部类,获取item_test里的 id(获取需要存放数据的)
static class ViewHolder extends RecyclerView.ViewHolder{
private final TextView tvPiaohao;
private final TextView tvBanCi;
private final TextView tvYongHu;
public ViewHolder(@NonNull View itemView) {
super(itemView);
tvPiaohao = itemView.findViewById(R.id.tv_qingkuang_piaohao);
tvBanCi = itemView.findViewById(R.id.tv_qingkuang_banci);
tvYongHu = itemView.findViewById(R.id.tv_qingkuang_yonghu);
}
}
}
4.因需要发送网络请求服务器,所以需要引入依赖 和 相关配置
具体步骤 请看自己的笔记:OkHttp3 发送网络请求服务器
或 打开网址:https://blog.csdn.net/weixin_44619313/article/details/107637920
5.准备工作完成,接下来 HomeListFragment 代码为如下:
public class HomeListFragment extends Fragment {
private Activity activity;
private int type;
private SmartRefreshLayout srlTestList;//下拉加载,上拉刷新控件
private int pageSize = 7;//分页大小
private int currentPage = 1;//当前页数
private TestAdapter testAdapter;
@Override
public void onAttach(@NonNull Context context) {
super.onAttach(context);
this.activity=(Activity) context;
}
@Nullable
@Override
public View onCreateView(@NonNull LayoutInflater inflater, @Nullable ViewGroup container, @Nullable Bundle savedInstanceState) {
View view=inflater.inflate(R.layout.fragment_test_list,container,false);
Bundle bundle=getArguments();
if (bundle!=null){
//获取HomeFragment 过来的值
type = bundle.getInt("type");
srlTestList=view.findViewById(R.id.srl_test_list);//上拉刷新,下拉加载控件
RecyclerView recyclerView=view.findViewById(R.id.rv_test_list);//列表
//==recyclerView 设置布局管理器
LinearLayoutManager layoutManager=new LinearLayoutManager(activity);
layoutManager.setOrientation(LinearLayoutManager.VERTICAL);
recyclerView.setLayoutManager(layoutManager);
//==recyclerView 设置适配器
testAdapter = new TestAdapter();
recyclerView.setAdapter(testAdapter);
recyclerView.setItemAnimator(new DefaultItemAnimator());//设置增加或删除条目的动画
loadListData(true);
//======SmartRefreshLayout 事件监听
//SmartRefreshLayout 下拉刷新监听
srlTestList.setOnRefreshListener(new OnRefreshListener() {
@Override
public void onRefresh(@NonNull RefreshLayout refreshLayout) {
loadListData(true);
}
});
//SmartRefreshLayout 上拉加载监听
srlTestList.setOnLoadMoreListener(new OnLoadMoreListener() {
@Override
public void onLoadMore(@NonNull RefreshLayout refreshLayout) {
loadListData(false);
}
});
}
return view;
}
private void loadListData(final boolean isRefresh) {
if (isRefresh){
currentPage=1;
}else {
//下一页
currentPage++;
}
//==发送网络请求 请求分页数据,关于以下方法,请查看自己的笔记:OkHttp3 发送网络请求服务器
//或 查看网址:https://blog.csdn.net/weixin_44619313/article/details/107637920
// 查看 笔记或网址的 使用方法
String url="http://192.168.43.9:8080/CarTaketing/TicketsController/selectPiaoShu.do";//也可以在这拼接参数
Map<String, Object> map = new HashMap<>();
map.put("startNumber", 1001);
map.put("endNumber", 1050);
map.put("type", type);
map.put("startIndex", currentPage);
map.put("pageSize", pageSize);
OkHttpTool.httpPost(url, map, new OkHttpTool.ResponseCallback() {
@Override
public void onResponse(final boolean isSuccess, final int responseCode, final String response, Exception exception) {
activity.runOnUiThread(new Runnable() {
@Override
public void run() {
if (isSuccess && responseCode==200) {
Bsgrid<ShouPiaoQingKuangVo> bsgrid= JSON.parseObject(response,new TypeReference<Bsgrid<ShouPiaoQingKuangVo>>(){});
if (bsgrid != null) {
List<ShouPiaoQingKuangVo> shouPiaoQingKuangVos = bsgrid.getData();
testAdapter.addItem(shouPiaoQingKuangVos, currentPage,type);
if (isRefresh) {
srlTestList.finishRefresh();//刷新完成
} else {
srlTestList.finishLoadMore();//加载更多完成
}
int totalPage = bsgrid.getTotalPage(pageSize);
if (currentPage == totalPage) {
srlTestList.finishLoadMoreWithNoMoreData();
}
} else {
//加载失败
if (isRefresh) {
srlTestList.finishRefresh(false);//刷新失败
} else {
srlTestList.finishLoadMore(false);//加载更多失败
}
}
} else {
//加载失败
if (isRefresh) {
srlTestList.finishRefresh(false);//刷新失败
} else {
srlTestList.finishLoadMore(false);//加载更多失败
}
}
}
});
}
});
}
}
Step 5:HomeFragment 加入新代码 ,加入代码后如下:
//==Step 1 :继承 Fragment
public class HomeFragment extends Fragment {
private String[] title = {"已售", "已退", "已废"};//头部分类标题(即有多少个fragment)
private int[] orderStateIdTitle = {2, 4, 5};//头部分类标题对应的id,根据该id查询某类标题的数据
//==获取context
private FragmentActivity context;
@Override
public void onAttach(@NonNull Context context) {
super.onAttach(context);
this.context= (FragmentActivity) context;
}
//==Step 2 :重写onCreateView
@Nullable
@Override
public View onCreateView(@NonNull LayoutInflater inflater, @Nullable ViewGroup container, @Nullable Bundle savedInstanceState) {
View view=inflater.inflate(R.layout.fragment_home,container,false);
//======Step 4:
//获取控件
TabLayout tabLayout=view.findViewById(R.id.tl_order_title);//头部
ViewPager2 viewPager=view.findViewById(R.id.vp_order_container);//滑动
//viewPager设置适配器
MyFragmentStateAdapter myFragmentStateAdapter=new MyFragmentStateAdapter(context);
viewPager.setAdapter(myFragmentStateAdapter);
//给ViewPager2的预加载数(加载头部标题的数据),设置 1 为预加载 1页,2为预加载 2页,不设置不加载
viewPager.setOffscreenPageLimit(1);
//TabLayout与ViewPager2关联
new TabLayoutMediator(tabLayout, viewPager, new TabLayoutMediator.TabConfigurationStrategy() {
@Override
public void onConfigureTab(@NonNull TabLayout.Tab tab, int position) {
tab.setText(title[position]);
}
}).attach();
return view;
}
//=====Step 3:新建内部类适配器,并写如下3个方法
class MyFragmentStateAdapter extends FragmentStateAdapter{
//存放 fragment
Fragment[] fragments;
public MyFragmentStateAdapter(@NonNull FragmentActivity fragmentActivity) {
super(fragmentActivity);
fragments=new Fragment[title.length];
}
@NonNull
@Override
public Fragment createFragment(int position) {
if (fragments[position]==null){
//==设置需要传递的参数,根据参数的不同切换不同的标题
Bundle bundle=new Bundle();
bundle.putInt("type",orderStateIdTitle[position]);
HomeListFragment homeListFragment=new HomeListFragment();
homeListFragment.setArguments(bundle);//homeListFragment为要接受的参数的fragment
fragments[position]=homeListFragment;
}
//返回所在标题的fragment
return fragments[position];
}
//共有多少个fragment标题
@Override
public int getItemCount() {
return fragments.length;
}
}
}
Ps:如果想要更改 下拉刷新,上拉加载更多的样式,步骤如下:
1.新建 MyApplication 继承 Application ,代码如下:
public class MyApplication extends Application {
//========更改上拉刷新下拉加载更多的完成的提示样式 static 代码段可以防止内存泄露
static {
//设置全局的Header构建器
SmartRefreshLayout.setDefaultRefreshHeaderCreator(new DefaultRefreshHeaderCreator() {
@Override
public RefreshHeader createRefreshHeader(Context context, RefreshLayout layout) {
layout.setPrimaryColorsId(R.color.colorPrimary, android.R.color.white);//全局设置主题颜色
//return new ClassicsHeader(context);//.setTimeFormat(new DynamicTimeFormat("更新于 %s"));//指定为经典Header,默认是 贝塞尔雷达Header
return new MaterialHeader(context);
}
});
//设置全局的Footer构建器
SmartRefreshLayout.setDefaultRefreshFooterCreator(new DefaultRefreshFooterCreator() {
@Override
public RefreshFooter createRefreshFooter(Context context, RefreshLayout layout) {
//指定为经典Footer,默认是 BallPulseFooter
return new ClassicsFooter(context).setDrawableSize(20);
}
});
}
}
2.在AndroidManifest.xml 的 application 的结点加入如下代码:
<application
android:name=".MyApplication"