③ 编码运行
现在都具备了,回到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)); }
现在可以运行了。
不过这个文字并没有放大,那么再来设置一下,这里通过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()方法。
运行一下:
嗯,这个效果还是阔以滴。
三、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"?> <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)); }
下面运行一下:
可以看到我点击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"> <!--纵向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,运行一下:
这还是不难的对吧。
五、个人主页面
有些App在个人的信息页面会展示较多的数据,这里利用TabLayout就可以更合理的展示,
首先准备一个头像图片
越前龙马。
① 新建页面
这是我们的第五个使用方式了,在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中使用。
这样设置,你刚才的风格样式就只对这个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"}
然后打开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); } }
下面运行一下:
那么本篇文章就到这里,感谢您的耐心阅读,希望没有浪费您的时间,我是初学者-Study,山高水长,后会有期~