Android零基础入门第70节(ViewPager轻松完成TabHost效果)

世事洞明皆学问,人情练达即文章。这篇文章主要讲述Android零基础入门第70节:ViewPager轻松完成TabHost效果相关的知识,希望能为你提供帮助。
    上一期学习了ViewPager的简单使用,本期一起来学习ViewPager的更多用法。

Android零基础入门第70节(ViewPager轻松完成TabHost效果)

文章图片

        相信很多同学都使用过今日头条APP吧,一打开主界面就可以看到顶部有很多Tab,然后通过左右滑动来切换,就可以通过ViewPager来完成。当然具体实现又会有很多方式,我们本期就先来学习最简单的Tab切换吧,有一点类似于之前了解的TabHost。
 
 
一、PagerTitleStrip与PagerTabStrip 
        在实际运用中,很多时候只有页面滑动是不够的,还需要有标题栏才够友好。首先来学习一下官方自带的,在android.support.v4包中的两个控件PagerTabStrip与PagerTitleStrip。
    上面提到的2个控件,其中PagerTitleStrip是普通文字,PagerTabStrip带有下划线。PagerTabStrip在效果上包含了PagerTitleStrip。
        如果只添加PagerTabStrip可以看到只有线,但是它占的布局是有一定高度的,而且默认是不显示标题的,如果要显示出来,需在适配器里重写getPageTitle(int position)方法。关于标题及这条线的颜色,和整个标识View的背景,都可以在代码里设置。
        还有一个区别就是,PagerTabStrip可以点击切换View,而PagerTitleStrip不能点击。
        接下来通过一个案例来学习PagerTabStrip的使用。
        继续再上一期的案例基础上来进行修改,首先修改viewpager_layout.xml文件,修改后的代码如下:
< ?xml version="1.0" encoding="utf-8"?> < LinearLayout xmlns:android="http://schemas.android.com/apk/res/android" android:orientation="vertical" android:layout_width="match_parent" android:layout_height="match_parent"> < android.support.v4.view.ViewPager android:id="@+id/view_pager" android:layout_width="match_parent" android:layout_height="wrap_content"> < android.support.v4.view.PagerTabStrip android:id="@+id/view_pager_tabstrip" android:layout_width="wrap_content" android:layout_height="wrap_content" /> < /android.support.v4.view.ViewPager> < /LinearLayout>

    然后几个页面布局文件不变,既然需要在顶部显示Tab和标题,那就需要我们通过适配器来设置,修改后的ViewPagerAdapter类代码如下:
package com.jinyu.cqkxzsxy.android.advancedviewsample.adapter; import android.support.v4.view.PagerAdapter; import android.view.View; import android.view.ViewGroup; import java.util.ArrayList; /** * @创建者 鑫鱻 * @描述 Android零基础入门到精通系列教程 * 首发微信公众号分享达人秀(ShareExpert) */ public class ViewPagerAdapter extends PagerAdapter { private ArrayList< View> mPageLists = null; private ArrayList< String> mTitleLists = null; public ViewPagerAdapter(ArrayList< View> pageLists, ArrayList< String> titleLists) { this.mPageLists = pageLists; this.mTitleLists = titleLists; }@Override public int getCount() { return (null == mPageLists) ? 0 :mPageLists.size(); }@Override public boolean isViewFromObject(View view, Object object) { return view == object; }@Override public Object instantiateItem(ViewGroup container, int position) { View pageView = mPageLists.get(position); container.addView(pageView); return pageView; }@Override public void destroyItem(ViewGroup container, int position, Object object) { // 将当前位置的View移除 container.removeView(mPageLists.get(position)); }@Override public CharSequence getPageTitle(int position) { return (null == mTitleLists & & position < mTitleLists.size()) ? null : mTitleLists.get(position); } }

    接着修改ViewPagerActivity,修改的代码如下:
package com.jinyu.cqkxzsxy.android.advancedviewsample; import android.graphics.Color; import android.os.Bundle; import android.support.v4.view.PagerTabStrip; import android.support.v4.view.ViewPager; import android.support.v7.app.AppCompatActivity; import android.view.LayoutInflater; import android.view.View; import android.widget.Toast; import com.jinyu.cqkxzsxy.android.advancedviewsample.adapter.ViewPagerAdapter; import java.util.ArrayList; /** * @创建者 鑫鱻 * @描述 Android零基础入门到精通系列教程,欢迎关注微信公众号ShareExpert */ public class ViewPagerActivity extends AppCompatActivity implements ViewPager.OnPageChangeListener { private ViewPager mViewPager = null; private PagerTabStrip mPagerTabStrip = null; private ViewPagerAdapter mAdapter = null; private ArrayList< View> mPageLists = null; private ArrayList< String> mTitleLists = null; @Override protected void onCreate(Bundle savedInstanceState) { super.onCreate(savedInstanceState); setContentView(R.layout.viewpager_layout); mViewPager = (ViewPager) findViewById(R.id.view_pager); mPagerTabStrip = (PagerTabStrip) findViewById(R.id.view_pager_tabstrip); // 装入分页显示hi的View视图 mPageLists = new ArrayList< > (); LayoutInflater inflater = getLayoutInflater(); mPageLists.add(inflater.inflate(R.layout.viewpager_page1, null, false)); mPageLists.add(inflater.inflate(R.layout.viewpager_page2, null, false)); mPageLists.add(inflater.inflate(R.layout.viewpager_page3, null, false)); mPageLists.add(inflater.inflate(R.layout.viewpager_page4, null, false)); // 装入每个页面的Title mTitleLists = new ArrayList< > (); mTitleLists.add("第一页"); mTitleLists.add("第二页"); mTitleLists.add("第三页"); mTitleLists.add("第四页"); mAdapter = new ViewPagerAdapter(mPageLists, mTitleLists); mViewPager.setAdapter(mAdapter); // 更改下划线颜色 mPagerTabStrip.setTabIndicatorColor(Color.BLUE); mViewPager.addOnPageChangeListener(this); }@Override public void onPageScrolled(int position, float positionOffset, int positionOffsetPixels) {}@Override public void onPageSelected(int position) { Toast.makeText(this, "第" + (position + 1) + "页", Toast.LENGTH_SHORT).show(); }@Override public void onPageScrollStateChanged(int state) {} }

    重新运行程序,可以看到界面中已经出现了久违的Tab和标题,左右滑动页面也可以看到Tab处的线条跟随改变,如下图所示:
Android零基础入门第70节(ViewPager轻松完成TabHost效果)

文章图片

        从上面的案例可以发现,PagerTabStrip是ViewPager的一个关于当前页面、上一个页面和下一个页面的一个可交互的指示器。其默认显示在顶部,还可以通过android:layout_gravity 属性设置为TOP或BOTTOM将它显示在ViewPager的顶部或底部。
        关于PagerTitleStrip的使用,和PagerTabStrip基本差不多,只是布局文件中ViewPager包含的控件不同而已,这里就不再详细说明了,建议自己动手练习,如果有问题,欢迎进Android入门讨论群一起探讨。
 
 
二、自定义实现 
        上面我们使用了系统自带的控件来完成Tab显示,可能有的同学已经发现其与TabHost还是有一定的差别的,上面的Tab只显示3个,而且也不能完全满足实际需求,就需要我们自定义来实现了。
        接下来依然通过一个案例来学习如何自定义ViewPager的Tab标签。
        继续使用WidgetSample工程的advancedviewsample模块,在src/main/res/layout/目录下创建viewpager_custom_layout.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:orientation="vertical"> < LinearLayout android:layout_width="match_parent" android:layout_height="48dp" android:background="#FFFFFF"> < TextView android:id="@+id/viewpager_tv_one" android:layout_width="match_parent" android:layout_height="match_parent" android:layout_weight="1.0" android:gravity="center" android:text="第一页" android:textColor="#000000" /> < TextView android:id="@+id/viewpager_tv_two" android:layout_width="match_parent" android:layout_height="match_parent" android:layout_weight="1.0" android:gravity="center" android:text="第二页" android:textColor="#000000" /> < TextView android:id="@+id/viewpager_tv_three" android:layout_width="match_parent" android:layout_height="match_parent" android:layout_weight="1.0" android:gravity="center" android:text="第三页" android:textColor="#000000" /> < /LinearLayout> < ImageView android:id="@+id/cursor_img" android:layout_width="match_parent" android:layout_height="wrap_content" android:scaleType="matrix" android:src="https://www.songbingjia.com/android/@drawable/line" /> < android.support.v4.view.ViewPager android:id="@+id/view_pager" android:layout_width="match_parent" android:layout_height="wrap_content" android:layout_gravity="center" android:flipInterval="30" android:persistentDrawingCache="animation" /> < /LinearLayout>

    在页面顶部有一个线性布局,里面包含3个TextView,也就是ViewPager顶部的3个Tab标签。然后下面紧跟一个ImageView,主要用于指示当前是哪一个Tab标签对应的页面,也就是常说的滑块。最后在最底下是一个ViewPager,其中android:flipInterval属性设置了动画的时间间隔,android:persistentDrawingCache属性指控件的绘制缓存策略,一共有4个可选值,或者选择2个进行组合,分别如下:
  • none:不在内存中保存绘图缓存。
  • animation:只保存动画绘图缓存。
  • scrolling:只保存滚动效果绘图缓存。
  • all:所有的绘图缓存都应该保存在内存中。
        然后新建几个页面文件,这里继续使用上一期ViewPager快速实现引导页里面的页面文件,同样使用相同的适配器ViewPagerAdapter。
        最后新建ViewPagerCustomActivity.java文件,加载上面新建的布局文件,具体代码如下:
package com.jinyu.cqkxzsxy.android.advancedviewsample; import android.graphics.BitmapFactory; import android.graphics.Matrix; import android.os.Bundle; import android.support.v4.view.ViewPager; import android.support.v7.app.AppCompatActivity; import android.util.DisplayMetrics; import android.view.LayoutInflater; import android.view.View; import android.view.animation.Animation; import android.view.animation.TranslateAnimation; import android.widget.ImageView; import android.widget.TextView; import com.jinyu.cqkxzsxy.android.advancedviewsample.adapter.ViewPagerAdapter; import java.util.ArrayList; /** * @创建者 鑫鱻 * @描述 Android零基础入门到精通系列教程,欢迎关注微信公众号ShareExpert */ public class ViewPagerCustomActivity extends AppCompatActivity implements ViewPager.OnPageChangeListener, View.OnClickListener { private ViewPager mViewPager = null; private ImageView mCursorImg = null; private TextView mOneTv = null; private TextView mTwoTv = null; private TextView mThreeTv = null; private ViewPagerAdapter mAdapter = null; private ArrayList< View> mPageList = null; private int mOffset = 0; // 移动条图片的偏移量 private int mCurrIndex = 0; // 当前页面的编号 private int mOneDis = 0; // 移动条滑动一页的距离 private int mTwoDis = 0; // 滑动条移动两页的距离@Override protected void onCreate(Bundle savedInstanceState) { super.onCreate(savedInstanceState); setContentView(R.layout.viewpager_custom_layout); // 获取界面组件 mViewPager = (ViewPager) findViewById(R.id.view_pager); mCursorImg = (ImageView) findViewById(R.id.cursor_img); mOneTv = (TextView) findViewById(R.id.viewpager_tv_one); mTwoTv = (TextView) findViewById(R.id.viewpager_tv_two); mThreeTv = (TextView) findViewById(R.id.viewpager_tv_three); // 初始化指示器位置 initCursorPosition(); mPageList = new ArrayList< > (); LayoutInflater inflater = getLayoutInflater(); mPageList.add(inflater.inflate(R.layout.viewpager_page1, null, false)); mPageList.add(inflater.inflate(R.layout.viewpager_page2, null, false)); mPageList.add(inflater.inflate(R.layout.viewpager_page3, null, false)); // 设置适配器 mAdapter = new ViewPagerAdapter(mPageList); mViewPager.setAdapter(mAdapter); // 文本框点击监听器 mOneTv.setOnClickListener(this); mTwoTv.setOnClickListener(this); mThreeTv.setOnClickListener(this); // 页面改变监听器 mViewPager.addOnPageChangeListener(this); // 初始默认第一页 mViewPager.setCurrentItem(0); }private void initCursorPosition() { // 获取指示器图片宽度 int cursorWidth = BitmapFactory.decodeResource(getResources(), R.drawable.line).getWidth(); // 获取分辨率宽度 DisplayMetrics dm = new DisplayMetrics(); getWindowManager().getDefaultDisplay().getMetrics(dm); int screenWidth = dm.widthPixels; // 计算偏移量 mOffset = (screenWidth / 3 - cursorWidth) / 2; // 设置动画初始位置 Matrix matrix = new Matrix(); matrix.postTranslate(mOffset, 0); mCursorImg.setImageMatrix(matrix); // 计算指示器图片的移动距离 mOneDis = mOffset * 2 + cursorWidth; // 页卡1 -> 页卡2 偏移量 mTwoDis = mOneDis * 2; // 页卡1 -> 页卡3 偏移量 }@Override public void onClick(View v) { switch (v.getId()) { case R.id.viewpager_tv_one: mViewPager.setCurrentItem(0); break; case R.id.viewpager_tv_two: mViewPager.setCurrentItem(1); break; case R.id.viewpager_tv_three: mViewPager.setCurrentItem(2); break; } }@Override public void onPageScrolled(int position, float positionOffset, int positionOffsetPixels) {}@Override public void onPageSelected(int position) { // 指示器图片动画设置 Animation animation = null; switch (position) { case 0: if (1 == mCurrIndex) { animation = new TranslateAnimation(mOneDis, 0, 0, 0); } else if (2 == mCurrIndex) { animation = new TranslateAnimation(mTwoDis, 0, 0, 0); } break; case 1: if (0 == mCurrIndex) { animation = new TranslateAnimation(mOffset, mOneDis, 0, 0); } else if (2 == mCurrIndex) { animation = new TranslateAnimation(mTwoDis, mOneDis, 0, 0); } break; case 2: if (0 == mCurrIndex) { animation = new TranslateAnimation(mOffset, mTwoDis, 0, 0); } else if (1 == mCurrIndex) { animation = new TranslateAnimation(mOneDis, mTwoDis, 0, 0); } break; default: break; } mCurrIndex = position; animation.setFillAfter(true); // True:图片停在动画结束位置 animation.setDuration(300); mCursorImg.startAnimation(animation); }@Override public void onPageScrollStateChanged(int state) {} }

    可以发现这里的代码和上期大致相同,只是在其中增加了滑块的位置及动画设置,为3个Tab标签监听了点击事件。其中initCursorPosition()方法主要初始化指示器图标的位置,需要根据屏幕宽度来计算游标显示位置。然后同样设置了页面监听器,主要根据滑动到的页面把游标滑动找指定位置。关于动画的这一块代码,可能有很多新人不太懂,不要太介意这个了,后续会专门进行学习,这里只需要知道可以这样使用就行。
        修改程序启动的Activity,运行程序,然后左右滑动屏幕或点击Tab标签,可以看到下图所示界面效果。
Android零基础入门第70节(ViewPager轻松完成TabHost效果)

文章图片

        通过上面的学习,是不是发现开发一个这样的漂亮界面其实非常简单。除了系统自带的和上面的自定义方法,在实际开发中常会结合Fragment来一起开发,建议后期学完Fragment后再来进一步学习。
        除了学习的PagerAdapter适配器,还有另外2个FragmentPagerAdapter和FragmentStatePagerAdapter,主要也是结合Fragment一起使用的,这里先不做过多学习。
 
        今天就先到这里,如果有问题欢迎留言一起探讨,也欢迎加入Android零基础入门技术讨论微信群,共同成长!
    此文章版权为微信公众号分享达人秀(ShareExpert)——鑫鱻所有,若需转载请联系作者授权,特此声明!
 
往期总结分享:
Android零基础入门第1节:Android的前世今生
Android零基础入门第2节:Android 系统架构和应用组件那些事
Android零基础入门第3节:带你一起来聊一聊Android开发环境
Android零基础入门第4节:正确安装和配置JDK, 高富帅养成第一招
Android零基础入门第5节:善用ADT Bundle, 轻松邂逅女神
Android零基础入门第6节:配置优化SDK Manager, 正式约会女神
Android零基础入门第7节:搞定Android模拟器,开启甜蜜之旅
Android零基础入门第8节:HelloWorld,我的第一趟旅程出发点
Android零基础入门第9节:Android应用实战,不懂代码也可以开发
Android零基础入门第10节:开发IDE大升级,终于迎来了Android Studio
Android零基础入门第11节:简单几步带你飞,运行Android Studio工程
Android零基础入门第12节:熟悉Android Studio界面,开始装逼卖萌
Android零基础入门第13节:Android Studio个性化配置,打造开发利器
Android零基础入门第14节:使用高速Genymotion,跨入火箭时代
Android零基础入门第15节:掌握Android Studio项目结构,扬帆起航
Android零基础入门第16节:Android用户界面开发概述
Android零基础入门第17节:文本框TextView
Android零基础入门第18节:输入框EditText
Android零基础入门第19节:按钮Button
Android零基础入门第20节:复选框CheckBox和单选按钮RadioButton
Android零基础入门第21节:开关组件ToggleButton和Switch
Android零基础入门第22节:图像视图ImageView
Android零基础入门第23节:图像按钮ImageButton和缩放按钮ZoomButton
Android零基础入门第24节:自定义View简单使用,打造属于你的控件
Android零基础入门第25节:简单且最常用的LinearLayout线性布局
Android零基础入门第26节:两种对齐方式,layout_gravity和gravity大不同
Android零基础入门第27节:正确使用padding和margin
Android零基础入门第28节:轻松掌握RelativeLayout相对布局
Android零基础入门第29节:善用TableLayout表格布局
Android零基础入门第30节:两分钟掌握FrameLayout帧布局
Android零基础入门第31节:少用的AbsoluteLayout绝对布局
Android零基础入门第32节:新推出的GridLayout网格布局
Android零基础入门第33节:Android事件处理概述
Android零基础入门第34节:Android中基于监听的事件处理
Android零基础入门第35节:Android中基于回调的事件处理
Android零基础入门第36节:Android系统事件的处理
Android零基础入门第37节:初识ListView
Android零基础入门第38节:初识Adapter
Android零基础入门第39节:ListActivity和自定义列表项
Android零基础入门第40节:自定义ArrayAdapter
Android零基础入门第41节:使用SimpleAdapter
Android零基础入门第42节:自定义BaseAdapter
Android零基础入门第43节:ListView优化和列表首尾使用
Android零基础入门第44节:ListView数据动态更新
Android零基础入门第45节:网格视图GridView
Android零基础入门第46节:列表选项框Spinner
Android零基础入门第47节:自动完成文本框AutoCompleteTextView
Android零基础入门第48节:可折叠列表ExpandableListView
Android零基础入门第49节:AdapterViewFlipper图片轮播
Android零基础入门第50节:StackView卡片堆叠
Android零基础入门第51节:进度条ProgressBar
Android零基础入门第52节:自定义ProgressBar炫酷进度条
Android零基础入门第53节:拖动条SeekBar和星级评分条RatingBar
Android零基础入门第54节:视图切换组件ViewSwitcher
Android零基础入门第55节:ImageSwitcher和TextSwitcher
Android零基础入门第56节:翻转视图ViewFlipper
Android零基础入门第57节:DatePicker和TimePicker选择器
Android零基础入门第58节:数值选择器NumberPicker
Android零基础入门第59节:常用三大Clock时钟组件
Android零基础入门第60节:日历视图CalendarView和定时器Chronometer
Android零基础入门第61节:滚动视图ScrollView
Android零基础入门第62节:搜索框组件SearchView
Android零基础入门第63节:值得借鉴学习的选项卡TabHost
Android零基础入门第64节:揭开RecyclerView庐山真面目
Android零基础入门第65节:RecyclerView分割线开发技巧
Android零基础入门第66节:RecyclerView点击事件处理
Android零基础入门第67节:RecyclerView数据动态更新
Android零基础入门第68节:RecyclerView添加首尾视图
Android零基础入门第69节:ViewPager快速实现引导页
Android零基础入门第70节(ViewPager轻松完成TabHost效果)

文章图片

【Android零基础入门第70节(ViewPager轻松完成TabHost效果)】
Android零基础入门第70节(ViewPager轻松完成TabHost效果)

文章图片


    推荐阅读