前言:

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

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

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

由于我刚刚遇到过,刚刚攻克了。所以来此分享经验啦!

一、推荐博客

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

二、怎样在Android Studio中导入ViewPageIndicator

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

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

看到了吧,我们仅须要在此处搜索com.inkapplications.viewpageindicator,选中。点击OK。gradle会自己主动帮我把改project载入进来的。

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

当你须要改动资源文件的时候。能够直接在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.TabPageIndicator
android:id="@+id/tab_page_indicator"
android:layout_width="fill_parent"
android:layout_height="60dp" /> <android.support.v4.view.ViewPager
android: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; @Override
public 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"> <TextView
android: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);
} @Override
public 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;
} @Override
public int getCount() {
return titles.length;
}
@Override
public 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; @Override
protected 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就可以:

 <activity
android: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; @Override
public void onCreate(Bundle savedInstanceState) {
// TODO Auto-generated method stub
super.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);
} @Override
public 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是否可见来推断是否是当前页面,然后运行网络载入数据
    @Override
    public 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

Android开源框架ViewPageIndicator和ViewPager实现Tab导航的更多相关文章

  1. 类似掌盟的Tab页 Android 开源框架ViewPageIndicator 和 ViewPager 仿网易新闻客户端Tab标签 (转)

    原博客地址  :http://blog.csdn.net/xiaanming/article/details/10766053 本文转载,记录学习用,如有需要,请到原作者网站查看(上面这个网址) 之前 ...

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

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

  3. Android 开源框架ViewPageIndicator 和 ViewPager 仿网易新闻clientTab标签

    之前用JakeWharton的开源框架ActionBarSherlock和ViewPager实现了对网易新闻clientTab标签的功能,ActionBarSherlock是在3.0下面的机器支持Ac ...

  4. Android tab导航的几种方法:ActionBar tab +fragment,Viewpager+pagerTitleStrip,开源框架ViewPageIndicator 和 ViewPager

    action来实现tab标签 并跟fragment结合 因为要写新闻客户端这个tab导航是必须的 这里我写几个小练习,希望大家融会贯通. 1actionbar设置tab +fragment 布局是个l ...

  5. Android 开源框架ActionBarSherlock 和 ViewPager 仿网易新闻客户端

    转载请注明出处:http://blog.csdn.net/xiaanming/article/details/9971721 大家都知道Android的ActionBar是在3.0以上才有的,那么在3 ...

  6. Android进阶笔记13:RoboBinding(实现了数据绑定 Presentation Model(MVVM) 模式的Android开源框架)

    1.RoboBinding RoboBinding是一个实现了数据绑定 Presentation Model(MVVM) 模式的Android开源框架.从简单的角度看,他移除了如addXXListen ...

  7. [转]Android开源框架ImageLoader的完美例子

    Android开源框架ImageLoader的完美例子 2013年8月19日开源框架之Universal_Image_Loader学习 很多人都在讨论如何让图片能在异步加载更加流畅,可以显示大量图片, ...

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

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

  9. Android 开源框架Universal-Image-Loader完全解析(三)---源代码解读

    转载请注明本文出自xiaanming的博客(http://blog.csdn.net/xiaanming/article/details/39057201),请尊重他人的辛勤劳动成果,谢谢! 本篇文章 ...

随机推荐

  1. HDU_6016_(Bestcoder round #92 1002)_(dfs)(暴力)

    题目链接:http://acm.hdu.edu.cn/showproblem.php?pid=6016 题意:给定男羊和女羊的朋友关系,即给定一个图,问从任意一只羊开始连续数四只不相同的羊的方法数. ...

  2. CSS 类名的问题

    以下以数字开头的 CSS 类名不会生效: .1st{ color: red; } 一个合法的 CSS 类名必需以下面其中之一作为开头: 下划线 _ 短横线 - 字母 a-z 然后紧跟其他 _,- 数字 ...

  3. clock_gettime 用法

    #include <stdio.h> #include <stdlib.h> #include <sys/types.h> #include <sys/sta ...

  4. iOS中NSAttributedString的使用--对关键字着色,以及处理html实例

    1,最近项目中用到了一个功能,一个很好的功能.就是用户在搜索的时候,搜索结果出来后对你输入的关键字进行红色标记.这样用户就很请楚的看到自己输入什么后会出现什么样子的结果.还有一个功能是,现在有一段文字 ...

  5. 洛谷——P4071 [SDOI2016]排列计数(错排+组合数学)

    P4071 [SDOI2016]排列计数 求有多少种长度为 n 的序列 A,满足以下条件: 1 ~ n 这 n 个数在序列中各出现了一次 若第 i 个数 A[i] 的值为 i,则称 i 是稳定的.序列 ...

  6. 洛谷——P1176 路径计数2

    P1176 路径计数2 题目描述 一个N \times NN×N的网格,你一开始在(1,1)(1,1),即左上角.每次只能移动到下方相邻的格子或者右方相邻的格子,问到达(N,N)(N,N),即右下角有 ...

  7. ConcurrentHashMap笔记

    概览: 内部存储的数据结构为:数组+链表+红黑树,图示: 重要的属性(内部类): //存放元素的数组 transient volatile Node<K,V>[] table; //数组中 ...

  8. 每日命令:(1)ls

    ls命令是linux下最常用的命令.ls命令就是list的缩写缺省下ls用来打印出当前目录的清单如果ls指定其他目录那么就会显示指定目录里的文件及文件夹清单. 通过ls 命令不仅可以查看linu ...

  9. Python面向对象类的特殊成员方法

    类的特殊成员方法:1.__doc__ : 打印类下面的注释 2.__module__和__class__:from lib.aa import C输出类被导出的模块名lib.aa,输出类的模块名和类名 ...

  10. 三 , lnmp 一键包安装使用

    安装打包环境  #https://lnmp.org/----------------------------------------------------#安装wget -c http://soft ...