Android TabLayout 使用进阶(含源码)

android:layout_height=“match_parent”

android:orientation=“vertical”

tools:context=“.mode2.ClassificationActivity”>

<com.google.android.material.tabs.TabLayout

android:id=“@+id/tab_layout”

android:layout_width=“match_parent”

android:layout_height=“wrap_content”

android:background=“#FFF”

app:tabIndicatorColor=“#00FF00”

app:tabIndicatorFullWidth=“false”

app:tabMode=“scrollable”

app:tabRippleColor=“#00000000”

app:tabSelectedTextColor=“#00FF00”

app:tabTextColor=“#000” />

<androidx.viewpager.widget.ViewPager

android:id=“@+id/view_pager”

android:layout_width=“match_parent”

android:layout_height=“match_parent”/>

还差Fragment了,假设当前的Activity是要做视频的分类,有类别如下:电视剧、电影、综艺、体育、新闻、国际这六项。那么我们就需要建6个Fragment,这个些fragment同样放在mode2包下。分别是

① 创建Fragment

TVSeriesFragment

public class TVSeriesFragment extends Fragment {

@Override

public View onCreateView(final LayoutInflater inflater,

ViewGroup container, Bundle savedInstanceState) {

final View view = inflater.inflate(R.layout.fragment_tv_series,

container, false);

return view;

}

}

MovieFragment

public class MovieFragment extends Fragment {

@Override

public View onCreateView(final LayoutInflater inflater,

ViewGroup container, Bundle savedInstanceState) {

final View view = inflater.inflate(R.layout.fragment_movie,

container, false);

return view;

}

}

VarietyShowFragment

public class VarietyShowFragment extends Fragment {

@Override

public View onCreateView(final LayoutInflater inflater,

ViewGroup container, Bundle savedInstanceState) {

final View view = inflater.inflate(R.layout.fragment_variety_show,

container, false);

return view;

}

}

SportsFragment

public class SportsFragment extends Fragment {

@Override

public View onCreateView(final LayoutInflater inflater,

ViewGroup container, Bundle savedInstanceState) {

final View view = inflater.inflate(R.layout.fragment_sports,

container, false);

return view;

}

}

NewsFragment

public class NewsFragment extends Fragment {

@Override

public View onCreateView(final LayoutInflater inflater,

ViewGroup container, Bundle savedInstanceState) {

final View view = inflater.inflate(R.layout.fragment_news,

container, false);

return view;

}

}

InternationalFragment。

public class InternationalFragment extends Fragment {

@Override

public View onCreateView(final LayoutInflater inflater,

ViewGroup container, Bundle savedInstanceState) {

final View view = inflater.inflate(R.layout.fragment_international,

container, false);

return view;

}

}

六个Fragment各自对应的xml如下:

fragment_tv_series.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:gravity=“center”

android:orientation=“vertical”>

<TextView

android:layout_width=“wrap_content”

android:layout_height=“wrap_content”

android:text=“电视剧”

android:textColor=“#000”

android:textSize=“24sp” />

fragment_movie.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:gravity=“center”

android:orientation=“vertical”>

<TextView

android:layout_width=“wrap_content”

android:layout_height=“wrap_content”

android:text=“电影”

android:textColor=“#000”

android:textSize=“24sp” />

fragment_variety_show.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:gravity=“center”

android:orientation=“vertical”>

<TextView

android:layout_width=“wrap_content”

android:layout_height=“wrap_content”

android:text=“综艺”

android:textColor=“#000”

android:textSize=“24sp” />

fragment_sports.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:gravity=“center”

android:orientation=“vertical”>

<TextView

android:layout_width=“wrap_content”

android:layout_height=“wrap_content”

android:text=“体育”

android:textColor=“#000”

android:textSize=“24sp” />

fragment_news.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:gravity=“center”

android:orientation=“vertical”>

<TextView

android:layout_width=“wrap_content”

android:layout_height=“wrap_content”

android:text=“新闻”

android:textColor=“#000”

android:textSize=“24sp” />

fragment_international.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:gravity=“center”

android:orientation=“vertical”>

<TextView

android:layout_width=“wrap_content”

android:layout_height=“wrap_content”

android:text=“国际”

android:textColor=“#000”

android:textSize=“24sp” />

我这么实在的博主现在可不多了,这么多余的代码我都给贴出来了。

② Fragment适配器

现在Fragment的就写好了。下面写一个适配器,在com.llw.tablayoutdemo下新建一个adapter包,该包下新建一个BasicFragmentAdapter,里面的代码如下:

package com.llw.tablayoutdemo.adapter;

import android.view.ViewGroup;

import androidx.annotation.NonNull;

import androidx.annotation.Nullable;

import androidx.fragment.app.Fragment;

import androidx.fragment.app.FragmentManager;

import androidx.fragment.app.FragmentPagerAdapter;

import java.util.List;

/**

  • Fragment适配器

  • @author llw

  • @date 2021/4/28 15:08

*/

public class BasicFragmentAdapter extends FragmentPagerAdapter {

String titleArr[];

List mFragmentList;

public BasicFragmentAdapter(FragmentManager fm, List list, String[] titleArr) {

super(fm);

mFragmentList = list;

this.titleArr = titleArr;

}

@Override

public Fragment getItem(int i) {

return mFragmentList.get(i);

}

@Override

public int getCount() {

return mFragmentList != null ? mFragmentList.size() : 0;

}

@Nullable

@Override

public CharSequence getPageTitle(int position) {

return titleArr[position];

}

@Override

public void destroyItem(@NonNull ViewGroup container, int position, @NonNull Object object) {

// super.destroyItem(container, position, object);

}

}

③ 编码运行

现在都具备了,回到ClassificationActivity中,修改代码如下:

package com.llw.tablayoutdemo.mode2;

import androidx.appcompat.app.AppCompatActivity;

import androidx.fragment.app.Fragment;

import androidx.viewpager.widget.ViewPager;

import android.os.Bundle;

import com.google.android.material.tabs.TabLayout;

import com.llw.tablayoutdemo.R;

import com.llw.tablayoutdemo.adapter.BasicFragmentAdapter;

import java.util.ArrayList;

import java.util.List;

/**

  • 分类页面 ;TabLayout + ViewPager + Fragment

  • @author llw

*/

public class ClassificationActivity extends AppCompatActivity {

private TabLayout tabLayout;

private ViewPager viewPager;

String[] titleArray = new String[]{“电视剧”, “电影”, “综艺”, “体育”, “新闻”, “国际”};

@Override

protected void onCreate(Bundle savedInstanceState) {

super.onCreate(savedInstanceState);

setContentView(R.layout.activity_classification);

tabLayout = findViewById(R.id.tab_layout);

viewPager = findViewById(R.id.view_pager);

List fragmentList = new ArrayList<>();

fragmentList.add(new TVSeriesFragment());

fragmentList.add(new MovieFragment());

fragmentList.add(new VarietyShowFragment());

fragmentList.add(new SportsFragment());

fragmentList.add(new NewsFragment());

fragmentList.add(new InternationalFragment());

BasicFragmentAdapter adapter = new BasicFragmentAdapter(getSupportFragmentManager(), fragmentList, titleArray);

viewPager.setAdapter(adapter);

tabLayout.setupWithViewPager(viewPager);

}

}

可以看到代码不多,下面运行一下吧。对了,还缺少一个页面入口,修改activity_main.xml,在里面增加一个按钮。

<Button

android:text=“分类页面:TabLayout + ViewPager + Fragment”

android:onClick=“mode2”

android:textAllCaps=“false”

android:layout_width=“match_parent”

android:layout_height=“50dp”/>

然后在MainActivity中增加一个方法。

/**

  • 组合使用 分类页面 ;TabLayout + ViewPager + Fragment

  • @param view

*/

public void mode2(View view) { startActivity(new Intent(this, ClassificationActivity.class)); }

现在可以运行了。

在这里插入图片描述

不过这个文字并没有放大,那么再来设置一下,这里通过TextView来实现,在layout下新建一个tab_item.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:orientation=“vertical”>

<TextView

android:id=“@+id/tv_title”

android:layout_width=“wrap_content”

android:layout_height=“wrap_content”

android:layout_gravity=“center”

android:gravity=“center”

android:textColor=“#333333”

android:textSize=“14sp” />

然后在ClassificationActivity中增加如下方法。

/**

  • 初始化TabLayout

*/

private void initTabLayout() {

for (int i = 0; i < tabLayout.getTabCount(); i++) {

TabLayout.Tab tab = tabLayout.getTabAt(i);

if (tab != null) {

//设置标签视图 为 TextView

tab.setCustomView(getTabView(i));

}

}

updateTabText(tabLayout.getTabAt(tabLayout.getSelectedTabPosition()), true);

tabLayout.addOnTabSelectedListener(new TabLayout.OnTabSelectedListener() {

@Override

public void onTabSelected(TabLayout.Tab tab) {

updateTabText(tab,true);

}

@Override

public void onTabUnselected(TabLayout.Tab tab) {

updateTabText(tab,false);

}

@Override

public void onTabReselected(TabLayout.Tab tab) {

}

});

}

/**

  • 获取TabView

  • @param currentPosition

  • @return

*/

private View getTabView(int currentPosition) {

View view = LayoutInflater.from(this).inflate(R.layout.tab_item, null);

TextView textView = view.findViewById(R.id.tv_title);

textView.setText(titleArray[currentPosition]);

return view;

}

/**

  • 更新标签文字

  • @param tab

  • @param isSelect

*/

private void updateTabText(TabLayout.Tab tab, boolean isSelect) {

if (isSelect) {

//选中文字加大加粗

TextView tabSelect = tab.getCustomView().findViewById(R.id.tv_title);

tabSelect.setTextSize(22);

tabSelect.setTextColor(Color.parseColor(“#00FF00”));

tabSelect.setTypeface(Typeface.defaultFromStyle(Typeface.BOLD));

tabSelect.setText(tab.getText());

} else {

TextView tabUnSelect = tab.getCustomView().findViewById(R.id.tv_title);

tabUnSelect.setTextSize(14);

tabUnSelect.setTextColor(Color.BLACK);

tabUnSelect.setTypeface(Typeface.defaultFromStyle(Typeface.NORMAL));

tabUnSelect.setText(tab.getText());

}

}

最后调用在onCreate方法中调用initTabLayout()方法。

在这里插入图片描述

运行一下:

在这里插入图片描述

嗯,这个效果还是阔以滴。

三、App主页面 (TabLayout + TabItem + ViewPager + Fragment)


现在常规的App主页面都是底部有几个菜单,4个或者5个。通讯类的基本上是4个,如果QQ、微信。购物类的基本上是5个,如果淘宝、天猫、京东等。至于有几个我们不管,主要是怎么去实现这个主页面的菜单切换。这里的实现方式其实有很多,而文本以TabLayout为主,那么自然是以TabLayout来现实了,就如我标题上说的一样,用到了,TabLayout + TabItem + ViewPager + Fragment。

① 选中图标

下面就来看看具体怎么去做吧。

这里是第三个使用方式了,那么在com.llw.tablayoutdemo包下新建一个mode3包,这个包下新建一个HomeActivity,用来作为App的主页面,然后它的布局activity_home.xml是有一点点麻烦的。里面会用到8个图标。

在这里插入图片描述

在这里插入图片描述

在这里插入图片描述

在这里插入图片描述

在这里插入图片描述

在这里插入图片描述

在这里插入图片描述

在这里插入图片描述

将图标放到layout下的drawable文件夹中。

然后在这个文件夹下新建四个xml文件,分别是:

app_home.xml

<?xml version="1.0" encoding="utf-8"?>

app_search.xml

<?xml version="1.0" encoding="utf-8"?>

app_find.xml

<?xml version="1.0" encoding="utf-8"?>

app_mine.xml

<?xml version="1.0" encoding="utf-8"?>

下面来写activity_home.xml,里面的代码如下:

<?xml version="1.0" encoding="utf-8"?>

<RelativeLayout 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=“.mode3.HomeActivity”>

<androidx.viewpager.widget.ViewPager

android:id=“@+id/view_pager”

android:layout_width=“match_parent”

android:layout_height=“match_parent”

android:layout_above=“@+id/tab_layout” />

<com.google.android.material.tabs.TabLayout

android:id=“@+id/tab_layout”

android:layout_width=“match_parent”

android:layout_height=“wrap_content”

android:layout_alignParentBottom=“true”

android:background=“#FFF”

android:minHeight=“?attr/actionBarSize”

app:tabIndicatorColor=“#00000000”

app:tabRippleColor=“#00000000”

app:tabSelectedTextColor=“#1296DB”

app:tabTextColor=“#929299”>

<com.google.android.material.tabs.TabItem

android:id=“@+id/item_home”

android:layout_width=“wrap_content”

android:layout_height=“wrap_content”

android:icon=“@drawable/app_home”

android:text=“主页” />

<com.google.android.material.tabs.TabItem

android:id=“@+id/item_search”

android:layout_width=“wrap_content”

android:layout_height=“wrap_content”

android:icon=“@drawable/app_search”

android:text=“搜索” />

<com.google.android.material.tabs.TabItem

android:id=“@+id/item_find”

android:layout_width=“wrap_content”

android:layout_height=“wrap_content”

android:icon=“@drawable/app_find”

android:text=“发现” />

<com.google.android.material.tabs.TabItem

android:id=“@+id/item_mine”

android:layout_width=“wrap_content”

android:layout_height=“wrap_content”

android:icon=“@drawable/app_mine”

android:text=“我的” />

</com.google.android.material.tabs.TabLayout>

这里对TabLayout控件做了一些修改,设置点击的水波纹为透明、下划线为透明,选中的文字颜色为蓝色,默认是灰色,和刚才创建的四个图标样式文件类似,选中时切换蓝色图片,未选中时灰色图片。

② 创建Fragment

这里tabItem就是用来控制菜单图片的。现在布局已经写好了,下面来写代码。

我们的主页面自然也需要显示多个Fragment,通过ViewPager来进行切换。

而这些Fragment都放在mode3包下,下面一个一个的来创建

HomeFragment

public class HomeFragment extends Fragment {

@Override

public View onCreateView(final LayoutInflater inflater,

ViewGroup container, Bundle savedInstanceState) {

final View view = inflater.inflate(R.layout.fragment_home,

container, false);

return view;

}

}

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:gravity=“center”

android:orientation=“vertical”>

<TextView

android:layout_width=“wrap_content”

android:layout_height=“wrap_content”

android:text=“Home”

android:textColor=“#000”

android:textSize=“24sp” />

SearchFragment

public class SearchFragment extends Fragment {

@Override

public View onCreateView(final LayoutInflater inflater,

ViewGroup container, Bundle savedInstanceState) {

final View view = inflater.inflate(R.layout.fragment_search,

container, false);

return view;

}

}

fragment_search.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:gravity=“center”

android:orientation=“vertical”>

<TextView

android:layout_width=“wrap_content”

android:layout_height=“wrap_content”

android:text=“Search”

android:textColor=“#000”

android:textSize=“24sp” />

FindFragment

public class FindFragment extends Fragment {

@Override

public View onCreateView(final LayoutInflater inflater,

ViewGroup container, Bundle savedInstanceState) {

final View view = inflater.inflate(R.layout.fragment_find,

container, false);

return view;

}

}

fragment_find.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:gravity=“center”

android:orientation=“vertical”>

<TextView

android:layout_width=“wrap_content”

android:layout_height=“wrap_content”

android:text=“Find”

android:textColor=“#000”

android:textSize=“24sp” />

MineFragment

public class MineFragment extends Fragment {

@Override

public View onCreateView(final LayoutInflater inflater,

ViewGroup container, Bundle savedInstanceState) {

final View view = inflater.inflate(R.layout.fragment_mine,

container, false);

return view;

}

}

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:gravity=“center”

android:orientation=“vertical”>

<TextView

android:layout_width=“wrap_content”

android:layout_height=“wrap_content”

android:text=“Mine”

android:textColor=“#000”

android:textSize=“24sp” />

③ 编码运行

现在四个Fragment和它们的布局都写好了,下面回到HomeActivity中,修改代码如下:

package com.llw.tablayoutdemo.mode3;

import androidx.appcompat.app.AppCompatActivity;

import androidx.fragment.app.Fragment;

import androidx.viewpager.widget.ViewPager;

import android.os.Bundle;

import com.google.android.material.tabs.TabLayout;

import com.llw.tablayoutdemo.R;

import com.llw.tablayoutdemo.adapter.BasicFragmentAdapter;

import java.util.ArrayList;

import java.util.List;

/**

  • 组合使用 主页面 ;TabLayout + TabItem + ViewPager + Fragment

  • @author llw

*/

public class HomeActivity extends AppCompatActivity {

private TabLayout tabLayout;

private ViewPager viewPager;

final String[] titleArray = new String[]{“首页”, “搜索”, “发现”, “我的”};

@Override

protected void onCreate(Bundle savedInstanceState) {

super.onCreate(savedInstanceState);

setContentView(R.layout.activity_home);

init();

}

private void init() {

tabLayout = findViewById(R.id.tab_layout);

viewPager = findViewById(R.id.view_pager);

List fragmentList = new ArrayList<>();

fragmentList.add(new HomeFragment());

fragmentList.add(new SearchFragment());

fragmentList.add(new FindFragment());

fragmentList.add(new MineFragment());

BasicFragmentAdapter adapter = new BasicFragmentAdapter(getSupportFragmentManager(), fragmentList, titleArray);

viewPager.setAdapter(adapter);

tabLayout.addOnTabSelectedListener(new TabLayout.OnTabSelectedListener() {

@Override

public void onTabSelected(TabLayout.Tab tab) {

viewPager.setCurrentItem(tab.getPosition());

}

@Override

public void onTabUnselected(TabLayout.Tab tab) {

}

@Override

public void onTabReselected(TabLayout.Tab tab) {

}

});

viewPager.addOnPageChangeListener(new ViewPager.OnPageChangeListener() {

@Override

public void onPageScrolled(int position, float positionOffset, int positionOffsetPixels) {

tabLayout.setScrollPosition(position,positionOffset,true);

}

@Override

public void onPageSelected(int position) {

}

@Override

public void onPageScrollStateChanged(int state) {

}

});

}

}

那么这里就是切换Tab的时候改变ViewPager,ViewPager改变的时候切换Tab选中。现在还不能运行的,因为缺少一个入口,这个入口依然在MainActivity中,

在activity_main.xml中添加一个按钮:

<Button

android:text=“主页面:TabLayout + TabItem + ViewPager + Fragment”

android:onClick=“mode3”

android:textAllCaps=“false”

android:layout_width=“match_parent”

android:layout_height=“wrap_content”/>

在MainActivity中添加一个方法:

/**

  • 组合使用 主页面 ;TabLayout + TabItem + ViewPager + Fragment

  • @param view

*/

public void mode3(View view) {

startActivity(new Intent(this, HomeActivity.class));

}

下面运行一下:

在这里插入图片描述

可以看到我点击TabLayout,ViewPager就会切换,滑动ViewPager,TabLayout就会选中相应的TabItem。

这样就类似于现在的App主页面了。

四、商品分类页面


什么是商品分类页面呢?如下图

在这里插入图片描述

就像这种页面,你在日常的使用中应该见过。通常是在购物APP里面居多。但这个也是一个使用场景之一。那么这个页面要怎么做呢?

我们来分析一下啊,首先左边不出意外是一个列表,它的表现形式可以有多种,你可以使用RecyclerView,也可以使用TabLayout,毫无疑问我要使用TabLayout,而右边的就是一个ViewPager,可以上下滑动切换的ViewPager,里面放Fragment或者RecyclerView。我目前先这么自以为是的猜测一下。

那么下面就来实践一下吧。

① 添加第三方依赖库

首先在app下的build.gradle的dependencies{}闭包中添加如下依赖:

//纵向TabLayout

implementation ‘q.rorbin:VerticalTabLayout:1.2.5’

//可以纵向滑动的ViewPager

implementation ‘cn.youngkaaa:yviewpager:0.4’

然后Sync Now。

② 创建页面

那么现在是使用的第四个方式了,在com.llw.tablayoutdemo包下新建mode4包,这个包下新建一个GoodsActivity,布局activity_goods.xml代码如下:

<?xml version="1.0" encoding="utf-8"?>

<RelativeLayout 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=“.mode4.GoodsActivity”>

<q.rorbin.verticaltablayout.VerticalTabLayout

android:id=“@+id/tab_layout”

android:layout_width=“80dp”

android:layout_height=“match_parent”

android:background=“#EDEDED”

app:indicator_color=“#FFFFFF”

app:indicator_gravity=“fill”

app:tab_height=“50dp”

app:tab_mode=“scrollable” />

<cn.youngkaaa.yviewpager.YViewPager

android:id=“@+id/view_pager”

android:background=“#FFF”

android:layout_width=“match_parent”

android:layout_height=“match_parent”

android:layout_toEndOf=“@id/tab_layout”

app:orientation=“vertical”/>

到这里我们思考一个问题,假设不知道商品的类别数量的情况下,怎么写,那么肯定不能写死这个Fragment,不能像之前一样创建,那样明显太笨重了不是吗?像这种商品分类页面里面的布局都是一样的,不同的只是数据而已,而这个数据也是可以变化的,因此你不能写死数据和Fragment,因此就需要动态来生成。下面在mode4包下新建一个GoodsTabFragment,它的布局是fragment_goods_tab.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:gravity=“center”

android:orientation=“vertical”>

<TextView

android:id=“@+id/tv_content”

android:layout_width=“wrap_content”

android:layout_height=“wrap_content”

android:text=“内容”

android:textColor=“#000”

android:textSize=“24sp” />

这里我只是放了一个TextView,用来显示当前是哪一个商品所对应的Fragment。而GoodsTabFragment的代码也是很简单的,如下:

public class GoodsTabFragment extends Fragment {

private TextView tvContent;

private String content;

public GoodsTabFragment(String content) {

this.content = content;

}

@Override

public View onCreateView(final LayoutInflater inflater,

ViewGroup container, Bundle savedInstanceState) {

final View view = inflater.inflate(R.layout.fragment_goods_tab,

container, false);

tvContent = view.findViewById(R.id.tv_content);

return view;

}

@Override

public void onViewCreated(@NonNull View view, @Nullable Bundle savedInstanceState) {

super.onViewCreated(view, savedInstanceState);

tvContent.setText(content);

}

}

③ 创建适配器

下面还需要一个适配器,在adapter包下新建一个GoodsFragmentAdapter,里面的代码如下:

public class GoodsFragmentAdapter extends FragmentPagerAdapter {

private ArrayList fragments;

private ArrayList tabName;

public GoodsFragmentAdapter(FragmentManager fm, ArrayList fragments, ArrayList

tabName) {

super(fm);

this.fragments = fragments;

this.tabName = tabName;

}

@Override

public Fragment getItem(int i) {

return fragments.get(i);

}

@Override

public int getCount() {

return fragments.size();

}

@Nullable

@Override

public CharSequence getPageTitle(int position) {

return tabName.get(position);

}

}

④ 编码运行

然后回到GoodsActivity中,编写代码如下:

/**

  • 商品分类页面 : VerticalTabLayout + YViewPager + Fragment

  • @author llw

*/

public class GoodsActivity extends AppCompatActivity {

private VerticalTabLayout tabLayout;

private YViewPager viewPager;

private List titleList = new ArrayList<>();

@Override

protected void onCreate(Bundle savedInstanceState) {

super.onCreate(savedInstanceState);

setContentView(R.layout.activity_goods);

tabLayout = findViewById(R.id.tab_layout);

viewPager = findViewById(R.id.view_pager);

final ArrayList tabName = new ArrayList<>();

final ArrayList fragments = new ArrayList<>();

int num = new Random().nextInt(50);

Toast.makeText(this, num + “个商品”, Toast.LENGTH_SHORT).show();

for (int i = 0; i < num; i++) {

titleList.add(“商品” + i);

}

for (int i = 0; i < titleList.size(); i++) {

fragments.add(new GoodsTabFragment(titleList.get(i)));

tabName.add(titleList.get(i));

}

GoodsFragmentAdapter fragTabAdapter = new GoodsFragmentAdapter(getSupportFragmentManager(), fragments,

tabName);

viewPager.setAdapter(fragTabAdapter);

tabLayout.setupWithViewPager(viewPager);

}

}

设置一个50以内的随机数,然后设置菜单和Fragment,运行一下:

在这里插入图片描述

这还是不难的对吧。

五、个人主页面


有些App在个人的信息页面会展示较多的数据,这里利用TabLayout就可以更合理的展示,

首先准备一个头像图片

在这里插入图片描述

越前龙马。

① 新建页面

这是我们的第五个使用方式了,在com.llw.tablayoutdemo下新建一个mode5包,包下新建一个PersonActivity,布局是activity_person.xml。

下面还需要添加一个这个页面的主题风格,在styles.xml中添加如下代码:

然后在AndroidManifest.xml中使用。

在这里插入图片描述

这样设置,你刚才的风格样式就只对这个PersonActivity生效,不会影响到其他的Activity。

由于这个步骤会比较的多,所以运行的次数比较多,我们提前写入口,打开activity_main.xml,添加一个按钮。

<Button

android:layout_width=“match_parent”

android:layout_height=“wrap_content”

android:onClick=“mode5”

android:text=“个人页面 : CoordinatorLayout + TabLayout + ViewPager + Fragment”

android:textAllCaps=“false” />

在MainActivity中添加如下方法:

/**

  • 组合使用 个人主页面 : CoordinatorLayout + TabLayout + ViewPager + Fragment

  • @param view

*/

public void mode5(View view) {

startActivity(new Intent(this, PersonActivity.class));

}

下面来看看这个布局文件activity_person.xml,里面的代码比较的多:

<?xml version="1.0" encoding="utf-8"?>

<androidx.coordinatorlayout.widget.CoordinatorLayout 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=“#EEEEEE”

android:fitsSystemWindows=“true”

android:orientation=“vertical”

tools:context=“.mode5.PersonActivity”>

<com.google.android.material.appbar.AppBarLayout

android:id=“@+id/appbar_layout”

android:layout_width=“match_parent”

android:layout_height=“280dp”

android:fitsSystemWindows=“true”

android:theme=“@style/ThemeOverlay.AppCompat.Dark.ActionBar”>

<com.google.android.material.appbar.CollapsingToolbarLayout

android:id=“@+id/toolbar_layout”

android:layout_width=“match_parent”

android:layout_height=“match_parent”

android:fitsSystemWindows=“true”

app:collapsedTitleGravity=“center”

app:contentScrim=“#1296db”

app:layout_scrollFlags=“scroll|exitUntilCollapsed”

app:title=“初学者-Study”

app:toolbarId=“@+id/toolbar”>

<RelativeLayout

android:layout_width=“match_parent”

android:layout_height=“match_parent”

android:fitsSystemWindows=“true”

app:layout_collapseMode=“parallax”

app:layout_collapseParallaxMultiplier=“1”>

<ImageView

android:id=“@+id/iv_bg”

android:layout_width=“match_parent”

android:layout_height=“match_parent”

android:scaleType=“centerCrop”

app:layout_collapseMode=“pin”

app:layout_scrollFlags=“scroll|snap” />

<View

android:layout_width=“match_parent”

android:layout_height=“match_parent”

android:layout_marginTop=“140dp”

android:background=“#FFF” />

<com.google.android.material.imageview.ShapeableImageView

android:id=“@+id/iv_user”

android:layout_width=“100dp”

android:layout_height=“100dp”

android:layout_centerInParent=“true”

android:padding=“1dp”

android:src=“@drawable/logo”

app:shapeAppearanceOverlay=“@style/circleImageStyle”

app:strokeColor=“#FFF”

app:strokeWidth=“2dp” />

<com.google.android.material.imageview.ShapeableImageView

android:id=“@+id/iv_sex_bg”

android:layout_width=“30dp”

android:layout_height=“30dp”

android:layout_alignEnd=“@+id/iv_user”

android:layout_alignBottom=“@+id/iv_user”

android:background=“#1296db”

android:padding=“1dp”

app:shapeAppearanceOverlay=“@style/circleImageStyle”

app:strokeColor=“#FFF”

app:strokeWidth=“1dp” />

<com.google.android.material.imageview.ShapeableImageView

android:layout_width=“20dp”

android:layout_height=“20dp”

android:layout_marginEnd=“5dp”

android:layout_marginBottom=“5dp”

android:layout_alignEnd=“@+id/iv_user”

android:layout_alignBottom=“@+id/iv_user”

android:src=“@drawable/icon_man” />

<TextView

android:id=“@+id/tv_nickname”

android:layout_width=“wrap_content”

android:layout_height=“wrap_content”

android:layout_below=“@+id/iv_user”

android:layout_centerHorizontal=“true”

android:layout_marginTop=“12dp”

android:text=“初学者-Study”

android:textColor=“#000”

android:textSize=“20sp” />

<TextView

android:id=“@+id/tv_note”

android:layout_width=“wrap_content”

android:layout_height=“wrap_content”

android:layout_below=“@+id/tv_nickname”

android:layout_centerHorizontal=“true”

android:layout_marginTop=“8dp”

android:text=“兴趣:Android、Java、Kotlin”

android:textColor=“#000”

android:textSize=“16sp” />

<androidx.appcompat.widget.Toolbar

android:id=“@+id/toolbar”

android:layout_width=“match_parent”

android:layout_height=“?attr/actionBarSize”

app:contentInsetStart=“0dp”

app:layout_collapseMode=“pin”

app:layout_scrollFlags=“scroll|snap” />

</com.google.android.material.appbar.CollapsingToolbarLayout>

</com.google.android.material.appbar.AppBarLayout>

<androidx.core.widget.NestedScrollView

android:layout_width=“match_parent”

android:layout_height=“match_parent”

android:layout_marginTop=“4dp”

android:fillViewport=“true”

android:orientation=“vertical”

android:overScrollMode=“never”

app:layout_behavior=“@string/appbar_scrolling_view_behavior”>

<LinearLayout

android:layout_width=“match_parent”

android:layout_height=“wrap_content”

android:orientation=“vertical”>

<com.google.android.material.tabs.TabLayout

android:id=“@+id/tab_layout”

android:layout_width=“match_parent”

android:layout_height=“wrap_content”

android:background=“#FFF”

app:tabIndicatorFullWidth=“false”

app:tabRippleColor=“#00000000” />

<androidx.viewpager.widget.ViewPager

android:id=“@+id/view_pager”

android:layout_width=“match_parent”

android:layout_height=“match_parent”

android:layout_marginTop=“1dp” />

</androidx.core.widget.NestedScrollView>

</androidx.coordinatorlayout.widget.CoordinatorLayout>

根布局是CoordinatorLayout(协调布局),该布局主要是两个部分,AppBarLayout和NestedScrollView,通过协调布局可以让里面的子布局形成联动效果。你现在对这个可能还不了解,但是在你看到效果图之后你就会知道是怎么回事了。

这里面有一个icon_man图标是白色的,我贴了你也看不见,所以你可以自己找一个图标,或者从我的源码里去拿。

② 创建Fragment

这里的Fragment我们依然采用动态生成的方式,不同的是Fragment里面现在放的是RecyclerView,在mode5包下新建一个PersonTabFragment,布局是fragment_person_tab.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:gravity=“center”

android:orientation=“vertical”>

<androidx.recyclerview.widget.RecyclerView

android:id=“@+id/rv”

android:layout_width=“match_parent”

android:layout_height=“match_parent”

android:overScrollMode=“never” />

而使用RecyclerView自然要准备适配器,那么也就需要列表的item布局了,先在layout下创建item_person_type_rv.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_marginBottom=“1dp”

android:orientation=“vertical”

android:background=“#FFF”

android:padding=“16dp”>

<TextView

android:id=“@+id/tv_title”

android:layout_width=“wrap_content”

android:layout_height=“wrap_content”

android:text=“内容”

android:textColor=“#000”

android:textSize=“16sp”

android:textStyle=“bold” />

<TextView

android:id=“@+id/tv_content”

android:layout_width=“wrap_content”

android:layout_height=“wrap_content”

android:layout_marginTop=“8dp”

android:text=“内容”

android:textColor=“#000”

android:textSize=“14sp” />

然后在adapter包下新建一个PersonTypeAdapter,再写里面的代码之前,先添加一个依赖库,打开项目的build.gradle,在allprojects{}的repositories{}中添加如下依赖库。

maven {url “https://jitpack.io”}

在这里插入图片描述

然后打开app下的build.gradle,在下dependencies{}闭包下添加如下依赖:

//RecyclerView最好的适配器,让你的适配器一目了然,告别代码冗余

implementation ‘com.github.CymChad:BaseRecyclerViewAdapterHelper:2.9.30’

然后Sync Now。

下面来写PersonTypeAdapter的代码:

package com.llw.tablayoutdemo.adapter;

import androidx.annotation.Nullable;

import com.chad.library.adapter.base.BaseQuickAdapter;

import com.chad.library.adapter.base.BaseViewHolder;

import com.llw.tablayoutdemo.R;

import java.util.List;

public class PersonTypeAdapter extends BaseQuickAdapter<String, BaseViewHolder> {

public PersonTypeAdapter(int layoutResId, @Nullable List data) {

super(layoutResId, data);

}

@Override

protected void convert(BaseViewHolder helper, String item) {

helper.setText(R.id.tv_title,item)

.setText(R.id.tv_content,item+“内容”);

}

}

再回来PersonTabFragment中,修改里面的代码后如下:

public class PersonTabFragment extends Fragment {

private String content;

private RecyclerView rv;

private List typeList = new ArrayList<>();

public PersonTabFragment(String content) {

this.content = content;

}

@Override

public View onCreateView(final LayoutInflater inflater,

ViewGroup container, Bundle savedInstanceState) {

final View view = inflater.inflate(R.layout.fragment_person_tab,

container, false);

rv = view.findViewById(R.id.rv);

return view;

}

@Override

public void onViewCreated(@NonNull View view, @Nullable Bundle savedInstanceState) {

super.onViewCreated(view, savedInstanceState);

int num = new Random().nextInt(30);

typeList.clear();

for (int i = 0; i < num; i++) {

typeList.add(content + i);

}

LinearLayoutManager layoutManager = new LinearLayoutManager(this.getActivity());

PersonTypeAdapter personTypeAdapter = new PersonTypeAdapter(R.layout.item_person_type_rv, typeList);

rv.setLayoutManager(layoutManager);

rv.setAdapter(personTypeAdapter);

}

}

③ 图片模糊

由于个人主页面的背景图我希望是模糊的,所以需要用到一个工具类,在mode5下新建一个ImageFilter,里面的代码如下:

/**

  • 图片模糊

*/

public class ImageFilter {

//图片缩放比例

private static final float BITMAP_SCALE = 0.4f;

/**

  • 模糊图片的具体方法

  • @param context 上下文对象

  • @param image 需要模糊的图片

  • @return 模糊处理后的图片

*/

public static Bitmap blurBitmap(Context context, Bitmap image, float blurRadius) {

// 计算图片缩小后的长宽

int width = Math.round(image.getWidth() * BITMAP_SCALE);

int height = Math.round(image.getHeight() * BITMAP_SCALE);

// 将缩小后的图片做为预渲染的图片

Bitmap inputBitmap = Bitmap.createScaledBitmap(image, width, height, false);

// 创建一张渲染后的输出图片

Bitmap outputBitmap = Bitmap.createBitmap(inputBitmap);

// 创建RenderScript内核对象

RenderScript rs = RenderScript.create(context);

// 创建一个模糊效果的RenderScript的工具对象

ScriptIntrinsicBlur blurScript = ScriptIntrinsicBlur.create(rs, Element.U8_4(rs));

// 由于RenderScript并没有使用VM来分配内存,所以需要使用Allocation类来创建和分配内存空间

// 创建Allocation对象的时候其实内存是空的,需要使用copyTo()将数据填充进去

Allocation tmpIn = Allocation.createFromBitmap(rs, inputBitmap);

Allocation tmpOut = Allocation.createFromBitmap(rs, outputBitmap);

// 设置渲染的模糊程度, 25f是最大模糊度

blurScript.setRadius(blurRadius);

// 设置blurScript对象的输入内存

blurScript.setInput(tmpIn);

// 将输出数据保存到输出内存中

blurScript.forEach(tmpOut);

// 将数据填充到Allocation中

tmpOut.copyTo(outputBitmap);

return outputBitmap;

}

public static Bitmap blurBitmap(Context context, Bitmap bitmap) {

//用需要创建高斯模糊bitmap创建一个空的bitmap

Bitmap outBitmap = Bitmap.createBitmap(bitmap.getWidth(), bitmap.getHeight(), Bitmap.Config.ARGB_8888);

// 初始化Renderscript,该类提供了RenderScript context,创建其他RS类之前必须先创建这个类,其控制RenderScript的初始化,资源管理及释放

RenderScript rs = RenderScript.create(context);

// 创建高斯模糊对象

ScriptIntrinsicBlur blurScript = ScriptIntrinsicBlur.create(rs, Element.U8_4(rs));

// 创建Allocations,此类是将数据传递给RenderScript内核的主要方 法,并制定一个后备类型存储给定类型

Allocation allIn = Allocation.createFromBitmap(rs, bitmap);

Allocation allOut = Allocation.createFromBitmap(rs, outBitmap);

//设定模糊度(注:Radius最大只能设置25.f)

blurScript.setRadius(15.f);

// Perform the Renderscript

blurScript.setInput(allIn);

blurScript.forEach(allOut);

// Copy the final bitmap created by the out Allocation to the outBitmap

allOut.copyTo(outBitmap);

// recycle the original bitmap

// bitmap.recycle();

// After finishing everything, we destroy the Renderscript.

rs.destroy();

return outBitmap;

}

}

这个工具类的代码我也是从网络上找的。

④ 编码运行

下面回到之前的PersonActivity,里面的代码如下:

package com.llw.tablayoutdemo.mode5;

import androidx.appcompat.app.AppCompatActivity;

import androidx.fragment.app.Fragment;

import androidx.viewpager.widget.ViewPager;

import android.graphics.Bitmap;

import android.graphics.BitmapFactory;

import android.graphics.Color;

import android.os.Bundle;

import android.widget.ImageView;

import android.widget.LinearLayout;

import android.widget.Toast;

import com.google.android.material.appbar.AppBarLayout;

import com.google.android.material.appbar.CollapsingToolbarLayout;

import com.google.android.material.tabs.TabLayout;

import com.llw.tablayoutdemo.R;

import com.llw.tablayoutdemo.adapter.GoodsFragmentAdapter;

import com.llw.tablayoutdemo.mode4.GoodsTabFragment;

import java.util.ArrayList;

import java.util.Random;

/**

  • 个人主页面 :CoordinatorLayout + NestedScrollView + TabLayout + ViewPager + Fragment + RecyclerView

  • @author llw

*/

public class PersonActivity extends AppCompatActivity {

private ImageView ivBg;

private CollapsingToolbarLayout collapsingToolbarLayout;

private AppBarLayout appBarLayout;

private TabLayout tabLayout;

private ViewPager viewPager;

@Override

protected void onCreate(Bundle savedInstanceState) {

super.onCreate(savedInstanceState);

setContentView(R.layout.activity_person);

ivBg = findViewById(R.id.iv_bg);

collapsingToolbarLayout = findViewById(R.id.toolbar_layout);

本文来自互联网用户投稿,该文观点仅代表作者本人,不代表本站立场。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如若转载,请注明出处:/a/965661.html

如若内容造成侵权/违法违规/事实不符,请联系我们进行投诉反馈qq邮箱809451989@qq.com,一经查实,立即删除!

相关文章

【算法应用】Alpha进化算法求解二维栅格路径规划问题

目录 1.算法原理2.二维路径规划数学模型3.结果展示4.参考文献5.代码获取 1.算法原理 Alpha进化&#xff1a;一种具有进化路径自适应和矩阵生成的高效进化算法 2.二维路径规划数学模型 栅格法模型最早由 W.E. Howden 于 1968 年提出&#xff0c;障碍物的栅格用黑色表示&#…

机器学习--1.KNN机器学习入门

1、机器学习概述 1.1、什么是机器学习 机器学习&#xff08;Machine Learning&#xff09;是人工智能&#xff08;Artificial Intelligence&#xff09;领域的一个子集&#xff0c;它主要关注如何让计算机系统通过经验学习&#xff08;数据&#xff09;并自动改进性能。机器学…

【Ubuntu】ARM交叉编译开发环境解决“没有那个文件或目录”问题

【Ubuntu】ARM交叉编译开发环境解决“没有那个文件或目录”问题 零、起因 最近在使用Ubuntu虚拟机编译ARM程序&#xff0c;解压ARM的GCC后想要启动&#xff0c;报“没有那个文件或目录”&#xff0c;但是文件确实存在&#xff0c;环境配置也检查过了没问题&#xff0c;本文记…

解决whisper 本地运行时GPU 利用率不高的问题

我在windows 环境下本地运行whisper 模型&#xff0c;使用的是nivdia RTX4070 显卡&#xff0c;结果发现GPU 的利用率只有2% 。使用 import torch print(torch.cuda.is_available()) 返回TRUE。表示我的cuda 是可用的。 最后在github 的下列网页上找到了问题 极低的 GPU 利…

【Uniapp-Vue3】z-paging插件组件实现触底和下拉加载数据

一、下载z-paing插件 注意下载下载量最多的这个 进入Hbuilder以后点击“确定” 插件的官方文档地址&#xff1a; https://z-paging.zxlee.cn 二、z-paging插件的使用 在文档中向下滑动&#xff0c;会有使用方法。 使用z-paging标签将所有的内容包起来 配置标签中的属性 在s…

android 适配 api 35(android 15) 遇到的问题

首先升级 targetSdkVersion 和 compileSdkVersion 到 35&#xff0c;升级后发生的报错 一、 解决方案: 升级 gradle 和 gradle 插件版本 com.android.tools.build:gradle -> 8.3.0-alpha02 gradle-wrapper.properties : distributionUrl -> gradle-8.6-bin.zip htt…

HTML 复习

文章目录 路径问题标题标签段落标签换行标签列表标签<ol> 有序列表<ul> 无序标签标签嵌套 超链接标签多媒体标签<img> 图片标签<audio> 音频标签<video> 视频标签 表格标签<colspan> 跨行<rowspan> 跨列组合使用 表单标签基本表单标…

RabbitMQ介绍以及基本使用

文章目录 一、什么是消息队列&#xff1f; 二、消息队列的作用&#xff08;优点&#xff09; 1、解耦 2、流量削峰 3、异步 4、顺序性 三、RabbitMQ基本结构 四、RabbitMQ队列模式 1、简单队列模式 2、工作队列模式 3、发布/订阅模式 4、路由模式 5、主题模式 6、…

用Python获取股票数据并实现未来收盘价的预测

获取数据 先用下面这段代码获取上证指数的历史数据&#xff0c;得到的csv文件数据&#xff0c;为后面训练模型用的 import akshare as ak import pandas as pd# 获取上证指数历史数据 df ak.stock_zh_index_daily(symbol"sh000001")# 将数据保存到本地CSV文件 df.…

用NeuralProphet预测股价:AI金融新利器(附源码)

作者&#xff1a;老余捞鱼 原创不易&#xff0c;转载请标明出处及原作者。 写在前面的话&#xff1a;我用NeuralProphet模型预测了股票价格&#xff0c;发现其通过结合时间序列分析和神经网络算法&#xff0c;确实能提供比传统Last Value方法更精准的预测。经过一系列超参数调优…

现场流不稳定,EasyCVR视频融合平台如何解决RTSP拉流不能播放的问题?

视频汇聚EasyCVR安防监控视频系统采用先进的网络传输技术&#xff0c;支持高清视频的接入和传输&#xff0c;能够满足大规模、高并发的远程监控需求。平台灵活性强&#xff0c;支持国标GB/T 28181协议、部标JT808、GA/T 1400协议、RTMP、RTSP/Onvif协议、海康Ehome、海康SDK、大…

html转PDF文件最完美的方案(wkhtmltopdf)

目录 需求 一、方案调研 二、wkhtmltopdf使用 如何使用 文档简要说明 三、后端服务 四、前端服务 往期回顾 需求 最近在做报表类的统计项目&#xff0c;其中有很多指标需要汇总&#xff0c;网页内容有大量的echart图表&#xff0c;做成一个网页去浏览&#xff0c;同时…

记录 | WPF创建和基本的页面布局

目录 前言一、创建新项目注意注意点1注意点2 解决方案名称和项目名称 二、布局2.1 Grid2.1.1 RowDefinitions 行分割2.1.2 Row & Column 行列定位区分 2.1.3 ColumnDefinitions 列分割 2.2 StackPanel2.2.1 Orientation 修改方向 三、模板水平布局【Grid中套StackPanel】中…

电脑开机提示按f1原因分析及终极解决方法来了

经常有网友问到一个问题&#xff0c;我电脑开机后提示按f1怎么解决&#xff1f;不管理是台式电脑&#xff0c;还是笔记本&#xff0c;都有可能会遇到开机需要按F1&#xff0c;才能进入系统的问题&#xff0c;引起这个问题的原因比较多&#xff0c;今天小编在这里给大家列举了比…

【数据结构】(6) LinkedList 链表

一、什么是链表 1、链表与顺序表对比 不同点LinkedListArrayList物理存储上不连续连续随机访问效率O(N)O(1&#xff09;插入、删除效率O(1)O(N) 3、链表的分类 链表根据结构分类&#xff0c;可分为单向/双向、无头结点/有头节点、非循环/循环链表&#xff0c;这三组每组各取…

Mac电脑上好用的压缩软件

在Mac电脑上&#xff0c;有许多优秀的压缩软件可供选择&#xff0c;这些软件不仅支持多种压缩格式&#xff0c;还提供了便捷的操作体验和强大的功能。以下是几款被广泛推荐的压缩软件&#xff1a; BetterZip 功能特点&#xff1a;BetterZip 是一款功能强大的压缩和解压缩工具&a…

VUE 集成企微机器人通知

message-robot 便于线上异常问题及时发现处理&#xff0c;项目中集成企微机器人通知&#xff0c;及时接收问题并处理 企微机器人通知工具类 export class MessageRobotUtil {constructor() {}/*** 发送 markdown 消息* param robotKey 机器人 ID* param title 消息标题* param…

通信易懂唠唠SOME/IP——SOME/IP-SD服务发现阶段和应答行为

一 SOME/IP-SD服务发现阶划分 服务发现应该包含3个阶段 1.1 Initial Wait Phase初始等待阶段 初始等待阶段的作用 初始等待阶段是服务发现过程中的一个阶段。在这个阶段&#xff0c;服务发现模块等待服务实例的相关条件满足&#xff0c;以便继续后续的发现和注册过程。 对…

Day 30 卡玛笔记

这是基于代码随想录的每日打卡 93. 复原 IP 地址 有效 IP 地址 正好由四个整数&#xff08;每个整数位于 0 到 255 之间组成&#xff0c;且不能含有前导 0&#xff09;&#xff0c;整数之间用 . 分隔。 例如&#xff1a;"0.1.2.201" 和 "192.168.1.1" …

【中间件】 Kafka

1.先导知识&#xff1a; 消息队列MQ(Message Queue): 将需要传输的数据临时(设置有效期)存放在队列中,进行存取消息消息队列中间件&#xff1a; 用来存储消息的中间件(组件) 2.消息队列的应用场景 异步处理 为什么要使用消息队列&#xff1f; 比较耗时的操作放在其他系统中…