前言:

关于使用ViewPageIndicator和ViewPager实现Tab导航,在开发社区里已经有一堆的博客对其进行了介绍,如果我还在这里写如何去实现,那简直就是老生常谈,毫无新鲜感,而且,我也不认为自己对ViewPageIndicator的理解会比别人好,毕竟我也是看着大神的帖子,在学习实践着。

那我还写这个有啥意义呢?其实么,就是想在这里记录下,在使用ViewPageIndicator和ViewPager实现Tab导航时,大家有可能会遇到的坑。这个坑,需要我们开发时尽量去避免的。

啥?你问我为啥子知道有这些坑?

因为我刚刚遇到过,刚刚解决了,所以来此分享经验啦!

一、推荐博客

在介绍具体实现的代码之前,我先介绍两篇博客呗,毕竟我就是根据他们写的来学习的。第一篇《Android 开源框架ViewPageIndicator 和 ViewPager 仿网易新闻客户端Tab标签》这篇博客对如何实现tab已经介绍的非常详细了,包括如何去自定义tab样式,请学习膜拜吧。。。如果你学习能力较差,那好吧,在慕课网航有个教学视频,这可是鸿翔大神录制的哦,4-1 ViewPagerIndicator与ViewPager实现Tab,如果你看了视频还不会,那我,呵呵呵。。。

二、如何在Android Studio中导入ViewPageIndicator

看过之前我推荐博客和视频的人会问,在Eclipse中,我们直接引入ViewPageIndicator项目,再把就好了android-support-v4.jar 包进行下处理就好了。 那,如何在Android Studio中导入ViewPageIndicator项目呢?

好,我来告诉大家,请看下图:

看到了吧,我们仅需要在此处搜索com.inkapplications.viewpageindicator,选中,点击OK,gradle会自动帮我把改工程加载进来的。

让我们看下子导入后,源码在哪了:

当你需要修改资源文件的时候,可以直接在res目录下的资源文件中进行修改,是不是很方便!!!

此刻有一点要记住,因为你改项目中已经引入了android-support-v4,所以你无需再引入其它的v4包,切记切记!!!

三、实现Tab导航

3.1 主页面布局

<LinearLayout xmlns:android="http://schemas.android.com/apk/res/android"android:layout_width="fill_parent"android:layout_height="fill_parent"android:orientation="vertical"><com.viewpagerindicator.TabPageIndicatorandroid:id="@+id/tab_page_indicator"android:layout_width="fill_parent"android:layout_height="60dp" /><android.support.v4.view.ViewPagerandroid:id="@+id/study_viewpager"android:layout_width="fill_parent"android:layout_height="fill_parent" /></LinearLayout>

3.2 定义ViewPager要显示的Fragment

import android.os.Bundle;
import android.support.v4.app.Fragment;
import android.view.LayoutInflater;
import android.view.View;
import android.view.ViewGroup;import com.lidroid.xutils.ViewUtils;public class FragmentStudy extends Fragment {private View view = null;@Overridepublic View onCreateView(LayoutInflater inflater, ViewGroup container, Bundle savedInstanceState) {if(view==null){view = inflater.inflate(R.layout.fragment_study, container, false);}ViewUtils.inject(this, view);return view;}
}

fragment_study.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"><TextViewandroid:id="@+id/text_name"android:layout_width="fill_parent"android:layout_height="fill_parent"android:gravity="center"android:text="无缘"android:textSize="25sp" /></LinearLayout>

3.3 定义ViewPager的Adapter

public class ProjectPagerAdapter extends FragmentPagerAdapter {private static String[] titles = {"全部", "计划中", "进行中", "已完成"};public ProjectPagerAdapter(FragmentManager fm) {super(fm);}@Overridepublic Fragment getItem(int position) {Fragment fragment = null;Bundle bundle = null;switch (position) {case 0:fragment = new FragmentStudy();bundle = new Bundle();bundle.putInt("pos", 0);fragment.setArguments(bundle);break;case 1:fragment = new FragmentStudy();bundle = new Bundle();bundle.putInt("pos", 1);fragment.setArguments(bundle);break;case 2:fragment = new FragmentStudy();bundle = new Bundle();bundle.putInt("pos", 2);fragment.setArguments(bundle);break;case 3:fragment = new FragmentStudy();bundle = new Bundle();bundle.putInt("pos", 3);fragment.setArguments(bundle);break;}return fragment;}@Overridepublic int getCount() {return titles.length;}@Overridepublic CharSequence getPageTitle(int position) {return titles[position];}
}

3.4 设置ViewPageIndicator和ViewPager

import android.os.Bundle;
import android.support.v4.app.FragmentActivity;
import android.support.v4.view.ViewPager;import com.lidroid.xutils.ViewUtils;
import com.lidroid.xutils.view.annotation.ViewInject;
import com.viewpagerindicator.TabPageIndicator;public class MainActivity extends FragmentActivity {@ViewInject(R.id.tab_page_indicator)private TabPageIndicator tabPageIndicator;@ViewInject(R.id.study_viewpager)private ViewPager studyViewpager;private ProjectPagerAdapter mAdatpter;@Overrideprotected void onCreate(Bundle savedInstanceState) {super.onCreate(savedInstanceState);setContentView(R.layout.activity_main);ViewUtils.inject(this);mAdatpter = new ProjectPagerAdapter(getSupportFragmentManager());// 此处,如果不是继承的FragmentActivity,而是继承的Fragment,则参数应该传入getChildFragmentManager()studyViewpager.setAdapter(mAdatpter);tabPageIndicator.setViewPager(studyViewpager);}
}

这样,一个基本的顶部导航Tab就出来了,接下来,我们还可以定义tab的样式,在style.xml文件中,我们添加:

<!-- 去掉tab顶部的黑边 --><style name="no_title" parent="@android:style/Theme.Light.NoTitleBar"><item name="android:windowContentOverlay">@null</item></style><style name="MyTheme" parent="no_title"><item name="vpiTabPageIndicatorStyle">@style/MyWidget.TabPageIndicator</item><item name="android:windowNoTitle">true</item><item name="android:animationDuration">5000</item><item name="android:windowContentOverlay">@null</item></style><style name="MyWidget.TabPageIndicator" parent="Widget"><item name="android:gravity">center</item><item name="android:background">@drawable/vpi__tab_indicator</item><item name="android:paddingLeft">22dip</item><item name="android:paddingRight">22dip</item><item name="android:paddingTop">1dp</item><item name="android:paddingBottom">1dp</item><item name="android:textAppearance">@style/MyTextAppearance.TabPageIndicator</item><item name="android:textSize">14sp</item><item name="android:maxLines">1</item></style><style name="MyTextAppearance.TabPageIndicator" parent="Widget"><item name="android:textStyle">bold</item><item name="android:textColor">#2c3e50</item></style>

样式定义好之后,只需要为Activity配置该theme即可:

 <activityandroid:name=".MainActivity"android:label="@string/app_name"android:theme="@style/MyTheme"><intent-filter><action android:name="android.intent.action.MAIN" /><category android:name="android.intent.category.LAUNCHER" /></intent-filter>
</activity>

好了,快来看下效果:

怎么样?开心了吧,你想要的tab终于出来了,你满足了么?

请千万不要满足,因为这个Tab还不稳定,它还有漏洞,下面我们来看下。

四、Tab导航中的坑和解决方案

4.1 Fragment二次加载onCreateView方法时会报异常:java.lang.IllegalStateException

对于之前实现的tab导航,当我们来回切换tab时,会发现,系统会崩溃:

错误意思是,当切换tab回到已经加载过的Fragment时,系统不允许之前的Fragment在还未移除的情况下,再次加载该View,一个View只能有一个父控件。请仔细看我们FragmentStudy的代码:

if(view==null){view = inflater.inflate(R.layout.fragment_study, container, false);
}

我们为了保证只有一个实例,才会只对其进行是否为null的判断,只进行了一次初始化。

那该如何解决呢?

有人说好办啊,把判断view==null直接去掉不就好了。。。额,确实好了,但是你有没有考虑每次都会创建新的view,浪费资源性能呢?

那如何是好呢?别急,有办法,让我们修改下代码:

import android.os.Bundle;
import android.support.v4.app.Fragment;
import android.view.LayoutInflater;
import android.view.View;
import android.view.ViewGroup;import com.lidroid.xutils.ViewUtils;public class FragmentStudy extends Fragment {private View view = null;@Overridepublic void onCreate(Bundle savedInstanceState) {// TODO Auto-generated method stubsuper.onCreate(savedInstanceState);//        pos = getArguments().getInt("pos");
//        System.out.println(pos);LayoutInflater inflater = getActivity().getLayoutInflater();view = inflater.inflate(R.layout.fragment_study, (ViewGroup) getActivity().findViewById(R.id.study_viewpager), false);}@Overridepublic View onCreateView(LayoutInflater inflater, ViewGroup container, Bundle savedInstanceState) {//        if(view==null){
//            view = inflater.inflate(R.layout.fragment_study, container, false);
//        }// 这句话必须加ViewGroup p = (ViewGroup) view.getParent();if (p != null) {p.removeAllViewsInLayout();}ViewUtils.inject(this, view);return view;}
}

有没有发现啥? 没错,我们把加载布局文件创建View的过程,放在了onCreate()方法中,即只在第一次创建该Fragment时加载布局,之后切换时,都不会再加载布局了。

美哉啊!!!

在运行下该项目,发现是不是不会再崩溃了?!

4.2 ViewPager预加载Fragment造成的重复请求问题

不知道大家知不知道,ViewPager有个功能,也被称为ViewPager的一个好处,就是它可以预加载Fragment。可是如果我在每个Fragment中都有网络请求,岂不是加载一个Fragment发送了多个请求?这种体验可是不好的。有没有办法改呢?

有人说,那不简单啊,设置ViewPager不去预加载不就好了!

对,就这么简单,ViewPager确实提供了相应的方法,去设置预加载Fragment的数量:

通过ViewPager的setOffscreenPageLimit(int pagenum)来设置,默认情况下参数是1,比如viewPager.setOffscreenPageLimit(2)会预加载2个页面,viewPager.setOffscreenPageLimit(0)会不预加载页面。

可是,尼玛,操蛋的事来了,我尝试了,viewPager.setOffscreenPageLimit(0)这个方法根本没有用啊,真让我抓狂。

该咋办?

google了一下,还真让我找到了方法,重写Fragment的setUserVisibleHint方法:

// 使用fragment+viewpage时会发现设置setOffscreenPageLimit(0)不预加载页面不管用,
// 可以用下边的方法代替,下边的方法是在子页面(也就是fragment中)复写下边的方法,根据fragment是否可见来判断是否是当前页面,然后执行网络加载数据@Overridepublic void setUserVisibleHint(boolean isVisibleToUser) {super.setUserVisibleHint(isVisibleToUser);if (isVisibleToUser) {//fragment可见时执行加载数据或者进度条等qryDataFromServer();} else {//不可见时不执行操作}}private void qryDataFromServer() {System.out.println("第"+pos + "个Fragment is qryDataFromServer");}

来,我们运行下项目,切换Tab,看下输出:

I/System.out﹕ 第0个Fragment is qryDataFromServer
I/System.out﹕ 第1个Fragment is qryDataFromServer
I/System.out﹕ 第2个Fragment is qryDataFromServer
I/System.out﹕ 第3个Fragment is qryDataFromServer
I/System.out﹕ 第2个Fragment is qryDataFromServer
I/System.out﹕ 第1个Fragment is qryDataFromServer
I/System.out﹕ 第0个Fragment is qryDataFromServer

这就对了,切换到哪个Fragment,才去进行网络请求,而不是一次预加载多个网络请求。

总结:

相信看到这里,大家已经能够掌握如何使用TabPageIndicator和ViewPager开发一个比较完美的顶部导航栏了,其实,TabPageIndicator使用并不难,最重要的还是去避免上文中提到的几个坑,这样才会有较快的开发效率!

源码下载地址(免费): http://download.csdn.net/detail/zuiwuyuan/9039533

转载于:https://www.cnblogs.com/hehe520/p/6329981.html

Android开源框架ViewPageIndicator和ViewPager实现Tab导航相关推荐

  1. Android 开源框架ViewPageIndicator 和 ViewPager 仿网易新闻客户端Tab标签

     转载请注明出处:http://blog.csdn.net/xiaanming/article/details/10766053 之前用JakeWharton的开源框架ActionBarSherl ...

  2. 2019年 Android 开源框架 排行榜 TOP 60

    2019年 Android 开源框架 排行榜 TOP 50 1.Retrofit 一句话介绍:Retrofit是一款类型安全的网络框架,基于HTTP协议,服务于Android和java语言 上榜理由: ...

  3. android 动画开源框架,图文简介非常炫酷的Android开源框架之UI框架

    架构,其又名软件架构,是关于软件整体结构与组件的抽象描述,用于指导大型软件系统各个方面的设计.而软件架构(software architecture)是一系列相关的抽象模式,其是用来指导大型软件系统各 ...

  4. Android开源框架【集合】

    Android开源框架[集合] 图解一览 Square& JakeWharton 框架名称 功能描述 Picasso 一个强大的图片下载与缓存的库 OkHttp Square出品,一个Http ...

  5. Android开源框架——图表MPAndroidChart

    开源官网:https://github.com/PhilJay/MPAndroidChart Android开源框架--图表MPAndroidChart 特点 配置 图表类型 Demo MPAndro ...

  6. Android——开源框架Universal-Image-Loader + Fragment使用+轮播广告

    原文地址: Android 开源框架Universal-Image-Loader完全解析(一)--- 基本介绍及使用 Android 开源框架Universal-Image-Loader完全解析(二) ...

  7. Android开源框架源码鉴赏:Fresco

    文章目录 一 图片加载流程 1.1 初始化Fresco 1.2 获取DataSource 1.3 绑定DraweeController与DraweeHierarchy 1.4 从内存缓存/磁盘缓存/网 ...

  8. Android开源框架源码鉴赏:Okhttp

    文章目录 一 请求与响应流程 1.1 请求的封装 1.2 请求的发送 1.3 请求的调度 二 拦截器 2.1 RetryAndFollowUpInterceptor 2.2 BridgeInterce ...

  9. Android开源框架源码鉴赏:VirtualAPK

    文章目录 一 VirtualAPK的初始化流程 二 VirtualAPK的的加载流程 三 VirtualAPK启动组件的流程 3.1 Activity 3.2 Service 3.3 Broadcas ...

  10. Android 开源框架Universal-Image-Loader学习

    Android 开源框架Universal-Image-Loader完全解析(一)--- 基本介绍及使用 Android 开源框架Universal-Image-Loader完全解析(二)--- 图片 ...

最新文章

  1. centos6.4安装nagios—4.0.8
  2. 机器学习知识点(三十三)机器学习入门的数学基础
  3. Solr配置IK分词器
  4. linux日志中显示skipping,linux推荐使用logrotate自动管理日志文件
  5. python全栈开发要学些什么_如何迅速学习Python 全栈开发?
  6. imx6的Linux默认颜色,MY-IMX6 Linux-3.14 测试手册(1)
  7. 构建自己的简单微服务架构(开源)
  8. 面试官:你说说互斥锁、自旋锁、读写锁、悲观锁、乐观锁的应用场景?
  9. flash动画制作常用代码
  10. Python爬虫系列:使用selenium+Edge查询指定城市天气情况
  11. 蓝桥杯 ALGO-129 算法训练 特殊的数字四十
  12. 物联网专用卡的优势有哪些
  13. PostgreSQL学习手册(PL/pgSQL过程语言)
  14. 云服务器安装 jdk
  15. android脚本精灵miui,脚本精灵安卓apk下载
  16. ORACLE数据库无法执行UPDATE
  17. Android Bugs——Error:java.lang.RuntimeException: Some file crunching failed, see logs for details
  18. Nvidia Graphics Card Drive Download 英伟达显卡驱动花屏问题解决处理方式
  19. wps linux版公式编辑器,linux下的公式编辑器
  20. springmvc mvn搭建

热门文章

  1. applet demo
  2. ./configure: error: the HTTP rewrite module requires the PCRE library.
  3. Java8 Stream + +很不错的文章集合
  4. 没想到Sharding-Jdbc竟然这么牛逼!一键实现读写分离、分库分表~
  5. GitHub出现大量重复代码:JavaScript最严重
  6. iPhone 12 要来了,手机是时候换到 11 了
  7. 给创业者们推荐一个好的工具
  8. Google Instant Apps VS 微信小程序
  9. 【题解】 bzoj4004: [JLOI2015]装备购买 (线性基)
  10. UITableView的cell重用优化