Android TabLayout 使用进阶(含源码)(下)

简介: Android TabLayout 使用进阶(含源码)(下)

③ 编码运行


现在都具备了,回到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<Fragment> 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)); }


现在可以运行了。


2021042815525548.gif


不过这个文字并没有放大,那么再来设置一下,这里通过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" />
</LinearLayout>


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


2021042816364640.png


运行一下:


20210428164258301.gif


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


三、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个图标。

20210429094209140.png

20210429094223336.png

20210429094209170.png

20210429094209171.png

20210429094209137.png

20210429094209139.png

20210429094209142.png

20210429094209148.png


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


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


app_home.xml

<?xml version="1.0" encoding="utf-8"?>
<selector xmlns:android="http://schemas.android.com/apk/res/android">
    <item android:drawable="@drawable/icon_home" android:state_selected="false"/>
    <item android:drawable="@drawable/icon_home_selected" android:state_selected="true"/>
</selector>


app_search.xml

<?xml version="1.0" encoding="utf-8"?>
<selector xmlns:android="http://schemas.android.com/apk/res/android">
    <item android:drawable="@drawable/icon_search" android:state_selected="false"/>
    <item android:drawable="@drawable/icon_search_selected" android:state_selected="true"/>
</selector>


app_find.xml

<?xml version="1.0" encoding="utf-8"?>
<selector xmlns:android="http://schemas.android.com/apk/res/android">
    <item android:drawable="@drawable/icon_find" android:state_selected="false"/>
    <item android:drawable="@drawable/icon_find_selected" android:state_selected="true"/>
</selector>


app_mine.xml

<?xml version="1.0" encoding="utf-8"?>
<selector xmlns:android="http://schemas.android.com/apk/res/android">
    <item android:drawable="@drawable/icon_mine" android:state_selected="false"/>
    <item android:drawable="@drawable/icon_mine_selected" android:state_selected="true"/>
</selector>


下面来写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>
</RelativeLayout>


这里对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" />
</LinearLayout>


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" />
</LinearLayout>


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" />
</LinearLayout>


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" />
</LinearLayout>


③ 编码运行


现在四个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<Fragment> 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));
    }


下面运行一下:


20210429100242595.gif


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


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


四、商品分类页面


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


image.gif


就像这种页面,你在日常的使用中应该见过。通常是在购物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">
    <!--纵向TabLayout-->
    <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" />
    <!--纵向ViewPager-->
    <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"/>
</RelativeLayout>


到这里我们思考一个问题,假设不知道商品的类别数量的情况下,怎么写,那么肯定不能写死这个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" />
</LinearLayout>


这里我只是放了一个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<Fragment> fragments;
    private ArrayList<String> tabName;
    public GoodsFragmentAdapter(FragmentManager fm, ArrayList<Fragment> fragments, ArrayList<String>
            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<String> 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<String> tabName = new ArrayList<>();
        final ArrayList<Fragment> 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,运行一下:


20210429114615801.gif


这还是不难的对吧。


五、个人主页面


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


首先准备一个头像图片


20210429143630890.jpg


越前龙马。


① 新建页面


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


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


  <!--个人页面主题风格-->
    <style name="PersonTheme" parent="Theme.MaterialComponents.Light.NoActionBar">
        <item name="colorPrimary">#1296db</item>
        <item name="colorPrimaryDark">#1296db</item>
        <item name="colorAccent">#1296db</item>
        <item name="android:statusBarColor">@android:color/transparent</item>
    </style>
    <!-- 圆形图片 -->
    <style name="circleImageStyle">
        <item name="cornerFamily">rounded</item>
        <item name="cornerSize">50%</item>
    </style>


然后在AndroidManifest.xml中使用。


2021042914404880.png


这样设置,你刚才的风格样式就只对这个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" />
            </RelativeLayout>
            <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" />
        </LinearLayout>
    </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" />
</LinearLayout>


而使用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" />
</LinearLayout>


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


  maven {url "https://jitpack.io"}

2021043009290051.png


然后打开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<String> 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<String> 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);
        appBarLayout = findViewById(R.id.appbar_layout);
        tabLayout = findViewById(R.id.tab_layout);
        viewPager = findViewById(R.id.view_pager);
        //拿到初始图
        Bitmap bmp= BitmapFactory.decodeResource(getResources(),R.drawable.logo);
        //处理得到模糊效果的图
        Bitmap blurBitmap = ImageFilter.blurBitmap(this, bmp, 25f);
        ivBg.setImageBitmap(blurBitmap);
        //伸缩偏移量监听
        appBarLayout.addOnOffsetChangedListener(new AppBarLayout.OnOffsetChangedListener() {
            boolean isShow = true;
            int scrollRange = -1;
            @Override
            public void onOffsetChanged(AppBarLayout appBarLayout, int verticalOffset) {
                if (scrollRange == -1) {
                    scrollRange = appBarLayout.getTotalScrollRange();
                }
                if (scrollRange + verticalOffset == 0) {//收缩时
                    collapsingToolbarLayout.setTitle("初学者-Study");
                    isShow = true;
                } else if (isShow) {//展开时
                    collapsingToolbarLayout.setTitle("");
                    isShow = false;
                }
            }
        });
        final ArrayList<Fragment> fragments = new ArrayList<>();
        final ArrayList<String> tabName = new ArrayList<>();
        String[] titleArray = {"动态","博客","分类专栏"};
        for (int i = 0; i < titleArray.length; i++) {
            fragments.add(new PersonTabFragment(titleArray[i]));
            tabName.add(titleArray[i]);
        }
        GoodsFragmentAdapter fragTabAdapter = new GoodsFragmentAdapter(getSupportFragmentManager(), fragments,
                tabName);
        viewPager.setAdapter(fragTabAdapter);
        tabLayout.setupWithViewPager(viewPager);
    }
}


下面运行一下:


20210430095308546.gif


那么本篇文章就到这里,感谢您的耐心阅读,希望没有浪费您的时间,我是初学者-Study,山高水长,后会有期~

相关文章
|
5月前
|
开发工具 Android开发 git
Windows下载android2.2完整源码(转)
Windows下载android2.2完整源码(转)
73 3
|
2月前
|
Ubuntu 开发工具 Android开发
Repo下载AOSP源码:基于ubuntu22.04 环境配置,android-12.0.0_r32
本文介绍了在基于Ubuntu 22.04的环境下配置Python 3.9、安装repo工具、下载和同步AOSP源码包以及处理repo同步错误的详细步骤。
134 0
Repo下载AOSP源码:基于ubuntu22.04 环境配置,android-12.0.0_r32
|
2月前
|
开发工具 git 索引
repo sync 更新源码 android-12.0.0_r34, fatal: 不能重置索引文件至版本 ‘v2.27^0‘。
本文描述了在更新AOSP 12源码时遇到的repo同步错误,并提供了通过手动git pull更新repo工具来解决这一问题的方法。
69 1
|
2月前
|
Android开发 Docker 容器
docker中编译android aosp源码,出现Build sandboxing disabled due to nsjail error
在使用Docker编译Android AOSP源码时,如果遇到"Build sandboxing disabled due to nsjail error"的错误,可以通过在docker run命令中添加`--privileged`参数来解决权限不足的问题。
247 1
|
2月前
|
开发工具 uml git
AOSP源码下载方法,解决repo sync错误:android-13.0.0_r82
本文分享了下载AOSP源码的方法,包括如何使用repo工具和处理常见的repo sync错误,以及配置Python环境以确保顺利同步特定版本的AOSP代码。
189 0
AOSP源码下载方法,解决repo sync错误:android-13.0.0_r82
|
2月前
|
Java Android开发 芯片
使用Android Studio导入Android源码:基于全志H713 AOSP,方便解决编译、编码问题
本文介绍了如何将基于全志H713芯片的AOSP Android源码导入Android Studio以解决编译和编码问题,通过操作步骤的详细说明,展示了在Android Studio中利用代码提示和补全功能快速定位并修复编译错误的方法。
52 0
使用Android Studio导入Android源码:基于全志H713 AOSP,方便解决编译、编码问题
|
2月前
|
Android开发
我的Android 进阶修炼(1): AOSP源码根目录结构
本文介绍了AOSP源码的根目录结构,提供了基于MTK9269 Android 9.0源码的目录说明,帮助读者了解AOSP源码的组织方式和各目录的功能。
91 0
我的Android 进阶修炼(1): AOSP源码根目录结构
|
2月前
|
API 开发工具 Android开发
Android源码下载
Android源码下载
234 0
|
2月前
|
开发工具 Android开发 git
全志H713 Android 11 :给AOSP源码,新增一个Product
本文介绍了在全志H713 Android 11平台上新增名为myboard的产品的步骤,包括创建新的device目录、编辑配置文件、新增内核配置、记录差异列表以及编译kernel和Android系统的详细过程。
46 0
|
2月前
|
Ubuntu 开发工具 Android开发
Repo下载、编译AOSP源码:基于Ubuntu 21.04,android-12.1.0_r27
文章记录了作者在Ubuntu 21.04服务器上配置环境、下载并编译基于Android 12.1.0_r27版本的AOSP源码的过程,包括解决编译过程中遇到的问题和错误处理方法。
84 0