ViewPager、Fragment、Matrix综合使用实现Tab滑页效果
原文地址:http://www.cnblogs.com/kross/p/3372987.html
我们实现一个上面是一个可以左右滑动的页面,下面是三个可点击切换的tab按钮,tab按钮上还有一个激活条。效果如下图所示:
----------------我是分割线--------------------
--------------------------我是分割线,下面的图片表示往右滑动,白条中的小机器人往右滑动-------------------------
--------------------------我是分割线,切换到第二个页面,tab中的第二个被激活,字呈白色-----------------------
------------------我是分割线-------------------
OK,效果就是如上所示的效果。现在开始一步一步的介绍如何实现。
1.创建好基础的布局文件。
整个页面是一个LinearLayout,如果你用其他的布局也是可以的,在下只是图一个方便了。
根据最终效果,我们将整个布局分为三个部分:
第一部分是上面那一大块有颜色的区域,这是一个ViewPager,里面的内容是通过Fragment加载进来的。
第二部分是那个在白条中间的小机器人这一块,这个作为激活条(自己编的名词,就是表名当前的tab是被激活的),就是一个ImageView。
第三部分是最底下的三个tab,是一个水平的LinearLayout,里面每一个tab都是ImageView+TextView构成的。
注意这里tab这个布局是被重复使用的,因为有三个嘛,为了代码重用,我们可以使用<include>标签。
所以,我们先写好每个小tab的布局(/res/layout/tab.xml),代码如下:
<?xml version="1.0" encoding="utf-8"?>
<LinearLayout xmlns:android="http://schemas.android.com/apk/res/android"
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:orientation="vertical" >
<ImageView
android:id="@+id/tab_icon"
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:layout_gravity="center"
android:src="@drawable/ic_launcher"/>
<TextView
android:id="@+id/tab_text"
android:layout_width="match_parent"
android:layout_height="wrap_content"
android:text="@string/tab_text"
android:gravity="center"
android:textColor="#cccccc"/>
</LinearLayout>
为了方便,就直接使用启动图标的图片了,啊哈哈……啊哈哈哈……
接下来我们去写主体页面的布局(/res/layout/activity_main.xml),代码如下:
注意<include>标签的使用哦~
<LinearLayout xmlns:android="http://schemas.android.com/apk/res/android"
xmlns:tools="http://schemas.android.com/tools"
android:layout_width="match_parent"
android:layout_height="match_parent"
android:orientation="vertical"
tools:context=".MainActivity" >
<!-- ViewPager的使用必须是完整的名字哦 -->
<android.support.v4.view.ViewPager
android:id="@+id/viewpager"
android:layout_width="match_parent"
android:layout_height="0dip"
android:layout_weight="1"/>
<!-- 这是所谓的激活条,为了方便,也直接使用启动图标的图片了 -->
<ImageView
android:id="@+id/active_bar"
android:layout_width="match_parent"
android:layout_height="wrap_content"
android:scaleType="matrix"
android:src="@drawable/ic_launcher"
android:background="#ffffff"/>
<!-- 下面的线性布局是三个tab放置的区域 -->
<LinearLayout
android:layout_width="match_parent"
android:layout_height="wrap_content"
android:orientation="horizontal">
<!-- 使用include标签,可以直接重用xml,这是我在《Android UI 基础教程》中发现的~\(^o^)/~ -->
<include
android:id="@+id/tab1"
android:layout_width="0dip"
android:layout_height="wrap_content"
android:layout_weight="1"
layout="@layout/tab"/>
<include
android:id="@+id/tab2"
android:layout_weight="1"
android:layout_width="0dip"
android:layout_height="wrap_content"
layout="@layout/tab"/>
<include
android:id="@+id/tab3"
android:layout_weight="1"
android:layout_width="0dip"
android:layout_height="wrap_content"
layout="@layout/tab"/>
</LinearLayout>
</LinearLayout>
OK,这样我们整个页面的框架就有了。
2.给ViewPager添加页面
OKOK,在这一步呢,我们要做的是给ViewPager这个控件添加页面,我们从一开始就打算添加三个页面的,所以上面才有3个tab,如果你需要更多,都是一样的道理。
ViewPager这个控件使用起来是非常方便的,在给它添加好页面后,它自身可以实现左右滑动切换的效果,非常滴好用啊。
ViewPager最重要的是给它设置适配器(setAdapter),我们期望的结果是,每个页面里,都有自己的控件,操作这些控件的方法都可以分别写在各自的Fragment中,而不是全部都写在MainActivity中。所以,我们要让ViewPager里面装载的是Fragment,因此,我们需要去拓展(extends)一个FragmentPagerAdapter。
实现FragmentPagerAdapter又需要事先准备好三个Fragment,三个Fragment又需要三个独立的布局。
因此我们需要做的第一件事是准备三个我们期望的布局。
为了简单起见,我们准备layout1、layout2、layout3(/res/layout/layout*.xml)这样三个布局,这三个布局的背景颜色都是不一样的,里面都放了一个按钮,为了能够在后面实现每个页面独立的功能。
布局文件的代码如下:
<?xml version="1.0" encoding="utf-8"?>
<!-- 这是layout1.xml的布局代码,另外两个布局文件就是背景颜色和按钮的id,text改变了而已 -->
<LinearLayout xmlns:android="http://schemas.android.com/apk/res/android"
android:layout_width="match_parent"
android:layout_height="match_parent"
android:orientation="vertical"
android:background="#ff0000">
<Button
android:id="@+id/button1"
android:layout_width="match_parent"
android:layout_height="wrap_content"
android:text="button1"/>
</LinearLayout>
接下来,我们要拓展(extends)三个Fragment,分别是Fragment1.java、Fragment2.java、Fragment3.java(/src/fragment/Fragment*.java)。代码如下:
推荐不同功能的类,建立不同的包来进行分类管理。
public class Fragment1 extends Fragment { private View layout = null; @Override
public void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
} @Override
public View onCreateView(LayoutInflater inflater, ViewGroup container,
Bundle savedInstanceState) {
this.layout = inflater.inflate(R.layout.layout1, null); //从这里到return之间,你可以为这个Fragment添加其功能。
Button b = (Button)this.layout.findViewById(R.id.button1);
b.setOnClickListener(new ButtonListener()); return this.layout;
} public class ButtonListener implements OnClickListener { @Override
public void onClick(View v) { Toast.makeText(getActivity(), "button1", Toast.LENGTH_SHORT).show();
}
}
}
OKOK,三个Fragment也准备好了,接下来实现一个FragmentPagerAdapter(/src/adapter/FragmentAdapter.java),代码如下:
public class FragmentAdapter extends FragmentPagerAdapter{ //这个是存放三个Fragment的数组,待会从MainActivity中传过来就行了
private ArrayList<Fragment> fragmentArray; //自己添加一个构造函数从MainActivity中接收这个Fragment数组
public FragmentAdapter(FragmentManager fm, ArrayList<Fragment> fragmentArray) {
this(fm);
this.fragmentArray = fragmentArray;
} public FragmentAdapter(FragmentManager fm) {
super(fm);
} //这个函数的作用是当切换到第arg0个页面的时候调用。
@Override
public Fragment getItem(int arg0) {
return this.fragmentArray.get(arg0);
} @Override
public int getCount() {
return this.fragmentArray.size();
}
}
实现好Adapter后,我们就去MainActivity(src/com.kross.test/MainActivity.java)中配置一下。
在MainActivity中,我们需要做如下几件事情:
1.准备好Fragment,把它们添加进数组。
2.获取到ViewPager的实例,为其设置适配器。
3.设置ViewPager当前显示第一页。
因为在FragmentAdapter的构造函数中需要一个FragmentManager,所以,MainActivity应该继承FragmentActivity。
代码如下:
public class MainActivity extends FragmentActivity { private ViewPager viewPager = null; @Override
protected void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
setContentView(R.layout.activity_main);this.initViewPager(); } private void initViewPager() {
//获取到ViewPager的实例
this.viewPager = (ViewPager)findViewById(R.id.viewpager); //构造好存放Fragment的数组
ArrayList<Fragment> fragmentArray = new ArrayList<Fragment>();
fragmentArray.add(new Fragment1());
fragmentArray.add(new Fragment2());
fragmentArray.add(new Fragment3()); //为ViewPager设置适配器
this.viewPager.setAdapter(new FragmentAdapter(getSupportFragmentManager(), fragmentArray)); //设置当前显示的页面
this.viewPager.setCurrentItem(0);
}
}
3.为下面的三个tab添加点击事件,并设置好相应的激活效果。
完成上面两步,应该可以实现三个页面滑动的效果。但下面的三个Tab是没有被用上的。我们这步要做到的事情是:点击下面的tab,切换到相应的页面,并激活tab,滑动上面的页面,并激活tab。
这里需要使用到一个接口OnPageChangeListener。这个接口中有三个方法,都是在页面滑动的时候会被调用。我们需要使用这个接口,让页面滑动的时候激活相应的tab。
现在来实现该接口PagerListener(/src/listener/PagerListener.java),代码如下:
public class PagerListener implements OnPageChangeListener { private ArrayList<View> tabArray = null;private final static String TAG = "PagerListener"; public PagerListener(ArrayList<View> tabArray) {
this.tabArray = tabArray;
} @Override
//这个……
public void onPageScrollStateChanged(int arg0) {
Log.i(TAG, "onPageScrollStateChanged:" + Integer.toString(arg0));
} @Override
//这个方法是页面滚动的时候被调用,我们将在这个方法里完成对激活条的操作
public void onPageScrolled(int arg0, float arg1, int arg2) {
Log.i(TAG, "onPageScrolled");
} @Override
//这个方法是当页面切换完毕后被调用,
public void onPageSelected(int arg0) {
Log.i(TAG, "onPageSelected"); //先将所有的tab设置成灰色的
for (View item : this.tabArray) {
((TextView)item.findViewById(R.id.tab_text)).setTextColor(Color.rgb(20, 20, 20));
} //再将当前的tab设置成白色的,表示激活状态
((TextView)this.tabArray.get(arg0).findViewById(R.id.tab_text)).setTextColor(Color.WHITE);
}
}
接下来,我们需要实现一个OnClickListener。
TabListener(src/listener/TabListener.java),代码如下:
public class TabListener implements OnClickListener { private ViewPager viewPager = null; public TabListener(ViewPager v) {
this.viewPager = v;
} @Override
public void onClick(View arg0) {
switch (arg0.getId()) {
case R.id.tab1:
this.viewPager.setCurrentItem(0);
break;
case R.id.tab2:
this.viewPager.setCurrentItem(1);
break;
case R.id.tab3:
this.viewPager.setCurrentItem(2);
break;
}
}
}
OKOK,接下来,我们只需要在MainActivity中获取tab的实例,给tab设置监听器,给ViewPager设置监听器就OK了。
MainActivity的代码变成如下这样:
public class MainActivity extends FragmentActivity { private ViewPager viewPager = null; //三个tab
private View tab1 = null;
private View tab2 = null;
private View tab3 = null;//存放tab的数组
private ArrayList<View> tabArray = null; @Override
protected void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
setContentView(R.layout.activity_main);this.initViewPager();
this.initTab();
this.setListener(); }private void initTab() {
this.tab1 = findViewById(R.id.tab1);
this.tab2 = findViewById(R.id.tab2);
this.tab3 = findViewById(R.id.tab3); this.tabArray = new ArrayList<View>();
this.tabArray.add(tab1);
this.tabArray.add(tab2);
this.tabArray.add(tab3);
} private void initViewPager() {
//获取到ViewPager的实例
this.viewPager = (ViewPager)findViewById(R.id.viewpager); //构造好存放Fragment的数组
ArrayList<Fragment> fragmentArray = new ArrayList<Fragment>();
fragmentArray.add(new Fragment1());
fragmentArray.add(new Fragment2());
fragmentArray.add(new Fragment3()); //为ViewPager设置适配器
this.viewPager.setAdapter(new FragmentAdapter(getSupportFragmentManager(), fragmentArray)); //设置当前显示的页面
this.viewPager.setCurrentItem(0);
} private void setListener() {
TabListener tl = new TabListener(this.viewPager); this.tab1.setOnClickListener(tl);
this.tab2.setOnClickListener(tl);
this.tab3.setOnClickListener(tl); this.viewPager.setOnPageChangeListener(new PagerListener(this.tabArray);
}
}
完成上面的三步,就基本上实现了大部分的功能了。页面可以切换,tab也可以点,有激活效果。
4.使用Matrix让激活条随页面的滑动而滑动。
激活条的滑动,需要使用到OnPageChangeListener接口中的onPageScrolled方法,
该方法有会在页面被滑动的时候调用,将会获取到三个参数,第一个参数为当前页面的下标,第二个参数为滑动距离占屏幕宽度的百分比,第三个参数为实际滑动的像素。
假设我们当前处在0下标的页面,我们从右往左滑动,滑向1下标的页面,在滑动的时候,该方法会一直被调用。
在没有彻底切换到1下标的页面时,第一个参数一直是0,直到彻底切换到1下标的页面。
第二个参数是个[0,1)的浮点数,一滑动,该参数就开始变大 0.12313---->0.23321---->0.31233,当页面快完成彻底切换的时候,也就是该参数将无限逼近1,但不会是1,然后突然变成了0,完成的页面的切换。
第三个参数就很好理解了,我的屏幕宽度是720px,我滑到一般,它的值就是360。
知道了这些,我们需要获取激活条需要移动的长度,以及屏幕的宽度。
tab有三个,所以我们用屏幕宽度/3,这是每个tab的宽度,tab的宽度 - 图片的宽度,这是剩余的空间,剩余的空间 / 2,就是小图片的偏移量(offset)。
激活条图片默认会出现在所在控件位置的最左边,初始的时候,我们就需要将它的位置设置在一个offset之后。
因此MainActivity的代码变成如下这样:
public class MainActivity extends FragmentActivity { private ViewPager viewPager = null; //三个tab
private View tab1 = null;
private View tab2 = null;
private View tab3 = null; //偏移量
private int offset; //图片宽度
private int imageWidth; //存放tab的数组
private ArrayList<View> tabArray = null; private ImageView activeBar = null; @Override
protected void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
setContentView(R.layout.activity_main); //获取激活条控件
this.activeBar = (ImageView)findViewById(R.id.active_bar); //获取该激活条的宽度
this.imageWidth = BitmapFactory.decodeResource(getResources(), R.drawable.ic_launcher).getWidth(); //获取屏幕的宽度
DisplayMetrics dm = new DisplayMetrics();
getWindowManager().getDefaultDisplay().getMetrics(dm);
int screenWidth = dm.widthPixels; //计算出偏移量
this.offset = (screenWidth / 3 - imageWidth) / 2; this.initViewPager();
this.initTab();
this.setListener(); } @Override
public boolean onCreateOptionsMenu(Menu menu) {
// Inflate the menu; this adds items to the action bar if it is present.
getMenuInflater().inflate(R.menu.main, menu);
return true;
} private void initTab() {
this.tab1 = findViewById(R.id.tab1);
this.tab2 = findViewById(R.id.tab2);
this.tab3 = findViewById(R.id.tab3); this.tabArray = new ArrayList<View>();
this.tabArray.add(tab1);
this.tabArray.add(tab2);
this.tabArray.add(tab3);
} private void initViewPager() {
//获取到ViewPager的实例
this.viewPager = (ViewPager)findViewById(R.id.viewpager); //构造好存放Fragment的数组
ArrayList<Fragment> fragmentArray = new ArrayList<Fragment>();
fragmentArray.add(new Fragment1());
fragmentArray.add(new Fragment2());
fragmentArray.add(new Fragment3()); //为ViewPager设置适配器
this.viewPager.setAdapter(new FragmentAdapter(getSupportFragmentManager(), fragmentArray)); //设置当前显示的页面
this.viewPager.setCurrentItem(0);
} private void setListener() {
TabListener tl = new TabListener(this.viewPager); this.tab1.setOnClickListener(tl);
this.tab2.setOnClickListener(tl);
this.tab3.setOnClickListener(tl); //注意这里的构造函数
this.viewPager.setOnPageChangeListener(new PagerListener(this.tabArray, this.activeBar, this.offset, this.imageWidth));
}
}
需要注意给ViewPager设置监听器的时候,传入了激活条的句柄,偏移量以及图片的宽度。
接下来我们需要修改下PagerListener的代码:
public class PagerListener implements OnPageChangeListener { private ArrayList<View> tabArray = null;
private ImageView activeBar = null;
private int offset;
private int imageWidth; private final static String TAG = "PagerListener"; public PagerListener(ArrayList<View> tabArray, ImageView activeBar, int offset, int iw) {
this.tabArray = tabArray;
this.activeBar = activeBar;
this.offset = offset;
this.imageWidth = iw;
} @Override
//这个……
public void onPageScrollStateChanged(int arg0) {
Log.i(TAG, "onPageScrollStateChanged:" + Integer.toString(arg0));
} @Override
//这个方法是页面滚动的时候被调用,我们将在这个方法里完成对激活条的操作
public void onPageScrolled(int arg0, float arg1, int arg2) {
Log.i(TAG, "onPageScrolled"); //new一个矩阵
Matrix matrix = new Matrix(); //设置激活条的最终位置
switch (arg0) {
case 0:
//使用set直接设置到那个位置
matrix.setTranslate(this.offset, 0);
break;
case 1:
matrix.setTranslate(this.offset * 3 + this.imageWidth, 0);
break;
case 2:
matrix.setTranslate(this.offset * 5 + this.imageWidth * 2, 0);
break;
} //在滑动的过程中,计算出激活条应该要滑动的距离
float t = (this.offset * 2 + this.imageWidth) * arg1; //使用post追加数值
matrix.postTranslate(t, 0); this.activeBar.setImageMatrix(matrix);
} @Override
//这个方法是当页面切换完毕后被调用,
public void onPageSelected(int arg0) {
Log.i(TAG, "onPageSelected"); //先将所有的tab设置成灰色的
for (View item : this.tabArray) {
((TextView)item.findViewById(R.id.tab_text)).setTextColor(Color.rgb(20, 20, 20));
} //再将当前的tab设置成白色的,表示激活状态
((TextView)this.tabArray.get(arg0).findViewById(R.id.tab_text)).setTextColor(Color.WHITE);
}
}
OKOK,完成上面所有的代码,就OK了。这样就实现了所有的效果。真是辛苦啊……
如果还有疑惑的话,可以来微博上问我:http://weibo.com/KrossFord
原文地址:http://www.cnblogs.com/kross/p/3372987.html
ViewPager、Fragment、Matrix综合使用实现Tab滑页效果的更多相关文章
- Unity实现滑页效果(UGUI)
简介 项目需要...直接展示效果吧: 原理 使用UGUI提供的ScrollRect和ScrollBar组件实现基本滑动以及自己控制每次移动一页来达到滑页的效果. 实现过程 1.创建两个panel,上面 ...
- ViewPager+Fragment再探:和TAB滑动条一起三者结合
Fragment前篇: <Android Fragment初探:静态Fragment组成Activity> ViewPager前篇: <Android ViewPager初探:让页面 ...
- Android viewPager+fragment实现滑页效果
先上图,手指在手机向左或者向右滑就可以实现相应的页面切换. 先看activity_main.xml文件,非常简单,主要是三个标题TextView和viewpager <?xml version= ...
- Android 上实现像微信一样的用Fragment来实现的Tab切页效果 提供源码下载
网有不少的例子,但是要么是像微信一样可是没有使用Fragment实现,要么是只实现了一个很简单的切换,没有下面的菜单页.这个例子有实现了,我觉得暂时够我用了##实现类:+ MainTabFragmen ...
- 安卓开发之使用viewpager+fragment实现滚动tab页
闲着.用viewpager+fragment实现了个滚动tab..轻拍,以后会陆续发先小东西出来..爱分享,才快乐.demo见附件.. package com.example.demo; import ...
- Android两种为ViewPager+Fragment添加Tab的方式
在Android开发中ViewPager的使用是非常广泛的,而它不仅仅能够实现简单的开始引导页,还可以结合Fragment并添加Tab作为选项卡或为显示大批量页面实现强大的顺畅滑动 下面介绍两种为Vi ...
- 仿百度壁纸客户端(一)——主框架搭建,自定义Tab+ViewPager+Fragment
仿百度壁纸客户端(一)--主框架搭建,自定义Tab+ViewPager+Fragment 百度壁纸系列 仿百度壁纸客户端(一)--主框架搭建,自定义Tab + ViewPager + Fragment ...
- 使用ViewPager+Fragment实现选项卡切换效果
实现效果 本实例主要实现用ViewPage和Fragment实现选项卡切换效果,选项卡个数为3个,点击选项卡或滑动屏幕会切换Fragment并实现选项卡下方下边框条跟随移动效果. 本程序用androi ...
- ViewPager Fragment 懒加载 可见 总结 MD
Markdown版本笔记 我的GitHub首页 我的博客 我的微信 我的邮箱 MyAndroidBlogs baiqiantao baiqiantao bqt20094 baiqiantao@sina ...
随机推荐
- bmob关联表
var DDB_User = Bmob.Object.createWithoutData("DDB_User", "b2fd2fe68f"); // var T ...
- 快排(python)
用python写了个快排,第一次发现python居然可以这么简洁. def quicksort(arr): if len(arr) <= 1: return arr pivot = arr[le ...
- 【Hutool】Hutool工具类之日期时间工具——DateUtil
一.用于取代Date对象的DateTime对象 再也不用Date SimpleDateFormat Calendar之间倒腾来倒腾去了!日期创建-获取-操作一步到位! 如果JDK版本更新到了8及以上, ...
- Linux入门进阶第三天——软件安装管理(下)
一.yum在线安装 之前的rpm包各种依赖性太强!安装复杂,yum的好处就来了: // yum 在redhat是付费服务 1.yum源文件 先进入到yum目录: 我们打开默认生效的Base包 2.光盘 ...
- HDFS(0.20.2)运营中急救方案
这段时间折腾的都是hadoop和lucene,总结了hadoop在运营过程中出现问题时的解决方案,请大家指教! HDFS(0.20.2)运营中急救方案 1 Namenode 挂掉( ...
- [arc062E]Building Cubes with AtCoDeer
Description 传送门 Solution 这道题直接暴力就好..毕竟只要枚举了前后两个瓷砖的方向和编号,其他瓷砖的颜色就是确定的了. 然而场上我的去重除了问题qaq. 我们钦定在立方体最前面的 ...
- c++ 全局变量
一.全局变量 声明 全局变量的定义和一般变量定义相同,不同的就是它的位置.一般会放在所有共享函数的前边. 作用 在函数间共享数据. 二.全局变量的运用 三.作业: 写出代码运行结果: ; //0 in ...
- 【Unity3d】ScriptableObject的简单用法
ScriptableObject非常适合小数量的游戏数值. 使用ScriptableObject的时候需要注意,生成ScriptableObject数据文件需要自己写Editor代码实现. 大概的 ...
- [css 揭秘] :CSS揭秘 技巧(五):条纹背景
条纹背景 https://github.com/FannieGirl/ifannie/问题:条纹背景 在设觉设计中无处不在,我们真的可以用css 创建图案吗? 这一章相对还是比较复杂的哦!一起get. ...
- java 多路分发
1.概念 一个函数处理多种类型,其实和多态差不多. 但是要处理两种或者多种类型的数据时,就需要判断每种类型以及每种类型所对应的处理.(PS:我只是在走别人的老路,网上一搜这种概念,博客一大堆,我不知道 ...