Android UI 之 Tab类型界面总结
Android 程序中实现Tab类型界面很常见,本人在做项目的时候也经常用到,所以想在这里总结一下,实现tab类型界面的几种方式,供大家参考。如有不对之处,欢迎大家指正!
一、TabActivity + TabWidget + TabHost.
实现TAB类型界面,首先想到的就是这种方式。但是在API level 13之后官方就不建议使用它了。不过还是在这里简单说一下它的使用吧。
使用它的关键就是布局文件了。需要在布局中添
加<TabHost>、<TabWidget>、<FrameLayout>这三个控件,id分别是系统提供
的:@android:id/tabhost 、@android:id/tabs 、@android:id/tabcontent 。
- <?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" >
- <TabHost
- android:id="@android:id/tabhost"
- android:layout_width="match_parent"
- android:layout_height="match_parent" >
- <RelativeLayout
- android:layout_width="match_parent"
- android:layout_height="match_parent"
- android:orientation="vertical" >
- <!-- 可以指定tabwidget的位置 android:layout_alignParentBottom="true" -->
- <TabWidget
- android:id="@android:id/tabs"
- android:layout_width="match_parent"
- android:layout_height="wrap_content"
- android:layout_alignParentBottom="false" >
- </TabWidget>
- <FrameLayout
- android:id="@android:id/tabcontent"
- android:layout_width="match_parent"
- android:layout_height="match_parent"
- android:layout_below="@android:id/tabs" >
- <LinearLayout
- android:id="@+id/tab1"
- android:layout_width="match_parent"
- android:layout_height="match_parent"
- android:background="#DEB887"
- android:orientation="vertical" >
- </LinearLayout>
- <LinearLayout
- android:id="@+id/tab2"
- android:layout_width="match_parent"
- android:layout_height="match_parent"
- android:background="#BCEE68"
- android:orientation="vertical" >
- </LinearLayout>
- <LinearLayout
- android:id="@+id/tab3"
- android:layout_width="match_parent"
- android:layout_height="match_parent"
- android:background="#7D9EC0"
- android:orientation="vertical" >
- </LinearLayout>
- </FrameLayout>
- </RelativeLayout>
- </TabHost>
- </LinearLayout>
一个linearlayout对应一个tab页面的布局。
- tabHost = getTabHost();
- tabHost.addTab(tabHost
- .newTabSpec("111")
- .setIndicator("", getResources().getDrawable(R.drawable.wuyong))
- .setContent(R.id.tab1));
- tabHost.addTab(tabHost
- .newTabSpec("222")
- .setIndicator("",
- getResources().getDrawable(R.drawable.gongsunsheng))
- .setContent(R.id.tab2));
- tabHost.addTab(tabHost.newTabSpec("333")
- .setIndicator("", getResources().getDrawable(R.drawable.likui))
- .setContent(R.id.tab3));
- tabHost.setBackgroundColor(Color.argb(150, 22, 70, 150));
- tabHost.setCurrentTab(0);
- tabHost.setOnTabChangedListener(new OnTabChangeListener() {
- @Override
- public void onTabChanged(String tabId) {
- Toast.makeText(FourthActivity.this, tabId, Toast.LENGTH_SHORT)
- .show();
- }
- });
二、ViewPager + PageAdapter
目前最常见的tab界面就是使用viewpager来实现了。
先来说一下viewpager的一般使用步骤:
1. 在布局文件中添加viewpager控件
2. 在代码中设置viewpager适配器,该类继承与pagerAdapter或它的子类。必须实现以下四个方法:
(1)getCount()
(2)instantiateItem()
(3)destroyItem()
(4)isViewFromObject()
3. 初始化viewpager控件,设置监听器
4. 设置监听事件(setOnPageChangeListener)
下面看一下这种方式的效果图:
主要的功能代码如下:
- private void init() {
- viewPager = (ViewPager) findViewById(R.id.first_vp);
- LayoutInflater inflater = LayoutInflater.from(this);
- View view1 = inflater.inflate(R.layout.first_layout1, null);
- View view2 = inflater.inflate(R.layout.first_layout2, null);
- View view3 = inflater.inflate(R.layout.first_layout3, null);
- list.add(view1);
- list.add(view2);
- list.add(view3);
- viewPager.setAdapter(pagerAdapter);
- viewPager.setOnPageChangeListener(new OnPageChangeListener() {
- @Override
- public void onPageSelected(int arg0) {
- setDots(arg0);
- }
- @Override
- public void onPageScrolled(int arg0, float arg1, int arg2) {
- }
- @Override
- public void onPageScrollStateChanged(int arg0) {
- }
- });
- }
- private PagerAdapter pagerAdapter = new PagerAdapter() {
- <span style="white-space:pre"> </span>//官方建议这么写
- @Override
- public boolean isViewFromObject(View arg0, Object arg1) {
- return arg0 == arg1;
- }
- <span style="white-space:pre"> </span>//返回一共有多少个界面
- @Override
- public int getCount() {
- return list.size();
- }
- <span style="white-space:pre"> </span>//实例化一个item
- @Override
- public Object instantiateItem(ViewGroup container, int position) {
- container.addView(list.get(position));
- return list.get(position);
- }
- <span style="white-space:pre"> </span>//销毁一个item
- @Override
- public void destroyItem(ViewGroup container, int position, Object object) {
- container.removeView(list.get(position));
- }
- };
适配器中必须要实现以上的四个方法。
如果只有这几个页面,交互性肯定是不好的,所以需要添加“指示器”,用来标识当前的页面是哪一个!我在这里用点来实现。就像效果图显示的那样。
- /**
- * 初始化底部的点
- */
- private void initDots() {
- pointLayout = (LinearLayout) findViewById(R.id.point_layout);
- dots = new ImageView[list.size()];
- for (int i = 0; i < list.size(); i++) {
- dots[i] = (ImageView) pointLayout.getChildAt(i);
- }
- currentIndex = 0;
- dots[currentIndex].setBackgroundResource(R.drawable.dian_down);
- }
- /**
- * 当滚动的时候更换点的背景图
- */
- private void setDots(int position) {
- if (position < 0 || position > list.size() - 1
- || currentIndex == position) {
- return;
- }
- dots[position].setBackgroundResource(R.drawable.dian_down);
- dots[currentIndex].setBackgroundResource(R.drawable.dian);
- currentIndex = position;
- }
重点就是页面切换之后,点也要切换。这时候就用到了OnPageChangeListener中的onPageSelected(int arg0)这个方法了。
- @Override
- public void onPageSelected(int arg0) {
- setDots(arg0);
- }
三、Fragment + FragmentManager
fragment相信大家在项目中肯定都用过。这个方法主要就是利用fragmentManager对fragment的事务管理功能。
- // 三个选项卡
- private LinearLayout tab1Layout, tab2Layout, tab3Layout;
- // 默认选中第一个tab
- private int index = 1;
- // fragment管理类
- private FragmentManager fragmentManager;
- // 三个fragment
- private Fragment tab1Fragment, tab2Fragment, tab3Fragment;
- @Override
- protected void onCreate(Bundle savedInstanceState) {
- super.onCreate(savedInstanceState);
- setContentView(R.layout.activity_second);
- fragmentManager = getSupportFragmentManager();
- init();
- }
- /**
- * 初始化控件
- */
- private void init() {
- tab1Layout = (LinearLayout) findViewById(R.id.tab1_layout);
- tab2Layout = (LinearLayout) findViewById(R.id.tab2_layout);
- tab3Layout = (LinearLayout) findViewById(R.id.tab3_layout);
- tab1Layout.setOnClickListener(this);
- tab2Layout.setOnClickListener(this);
- tab3Layout.setOnClickListener(this);
- //
- setDefaultFragment();
- }
- /**
- * 设置默认显示的fragment
- */
- private void setDefaultFragment() {
- FragmentTransaction transaction = fragmentManager.beginTransaction();
- tab1Fragment = new Tab1Fragment();
- transaction.replace(R.id.content_layout, tab1Fragment);
- transaction.commit();
- }
- /**
- *切换fragment
- * @param newFragment
- */
- private void replaceFragment(Fragment newFragment) {
- FragmentTransaction transaction = fragmentManager.beginTransaction();
- if (!newFragment.isAdded()) {
- transaction.replace(R.id.content_layout, newFragment);
- transaction.commit();
- } else {
- transaction.show(newFragment);
- }
- }
- /**
- * 改变现象卡的选中状态
- */
- private void clearStatus() {
- if (index == 1) {
- tab1Layout.setBackgroundColor(getResources().getColor(R.color.tab));
- } else if (index == 2) {
- tab2Layout.setBackgroundColor(getResources().getColor(R.color.tab));
- } else if (index == 3) {
- tab3Layout.setBackgroundColor(getResources().getColor(R.color.tab));
- }
- }
- @Override
- public void onClick(View v) {
- clearStatus();
- switch (v.getId()) {
- case R.id.tab1_layout:
- if (tab1Fragment == null) {
- tab1Fragment = new Tab1Fragment();
- }
- replaceFragment(tab1Fragment);
- tab1Layout.setBackgroundColor(getResources().getColor(
- R.color.tab_down));
- index = 1;
- break;
- case R.id.tab2_layout:
- if (tab2Fragment == null) {
- tab2Fragment = new Tab2Fragment();
- }
- replaceFragment(tab2Fragment);
- tab2Layout.setBackgroundColor(getResources().getColor(
- R.color.tab_down));
- index = 2;
- break;
- case R.id.tab3_layout:
- if (tab3Fragment == null) {
- tab3Fragment = new Tab3Fragment();
- }
- replaceFragment(tab3Fragment);
- tab3Layout.setBackgroundColor(getResources().getColor(
- R.color.tab_down));
- index = 3;
- break;
- }
- }
每一个fragment对应一个布局,点击不同的按钮来切换页面。效果如下图:
四、ViewPager + Fragment + FragmentPagerAdapter
如果想使用fragment的时候又想可以左右滑动,就可以使用这种方式。主要的部分就在viewpager的适配器。它的适配器继承FragmentPagerAdapter.
- package com.tab.view.demo3;
- import java.util.ArrayList;
- import android.support.v4.app.Fragment;
- import android.support.v4.app.FragmentManager;
- import android.support.v4.app.FragmentPagerAdapter;
- public class FragmentAdapter extends FragmentPagerAdapter {
- private ArrayList<Fragment> list;
- public FragmentAdapter(FragmentManager fm, ArrayList<Fragment> list) {
- super(fm);
- this.list = list;
- }
- @Override
- public Fragment getItem(int arg0) {
- return list.get(arg0);
- }
- @Override
- public int getCount() {
- return list.size();
- }
- }
需要传入FragmentManager对象和一个存放fragment的list对象。
- /**
- * 初始化viewpager
- */
- private void initViewPager() {
- viewPager = (ViewPager) findViewById(R.id.third_vp);
- fragmentsList = new ArrayList<>();
- Fragment fragment = new Tab1Fragment();
- fragmentsList.add(fragment);
- fragment = new Tab2Fragment();
- fragmentsList.add(fragment);
- fragment = new Tab3Fragment();
- fragmentsList.add(fragment);
- viewPager.setAdapter(new FragmentAdapter(getSupportFragmentManager(),
- fragmentsList));
- viewPager.setCurrentItem(0);
- viewPager.setOnPageChangeListener(this);
- }
对button添加点击事件。
- @Override
- public void onClick(View v) {
- switch (v.getId()) {
- case R.id.tab1_tv:
- viewPager.setCurrentItem(0);
- break;
- case R.id.tab2_tv:
- viewPager.setCurrentItem(1);
- break;
- case R.id.tab3_tv:
- viewPager.setCurrentItem(2);
- break;
- }
- }
我
在布局文件中添加了一个imageview作为指示器。如果想第一种tab类型界面的实现方式那样在onPageSelected()方法中进行设置,效
果是只能当页面完全切换过来之后才能把指示器移动过去。要想实现滑动页面的时候同时移动指示器,就需要在onPageScrolled()方法中进行设
置。
- @Override
- public void onPageScrolled(int position, float positionOffset,
- int positionOffsetPixels) {
- offset = (screen1_3 - cursorImg.getLayoutParams().width) / 2;
- Log.d("111", position + "--" + positionOffset + "--"
- + positionOffsetPixels);
- final float scale = getResources().getDisplayMetrics().density;
- if (position == 0) {// 0<->1
- lp.leftMargin = (int) (positionOffsetPixels / 3) + offset;
- } else if (position == 1) {// 1<->2
- lp.leftMargin = (int) (positionOffsetPixels / 3) + screen1_3 +offset;
- }
- cursorImg.setLayoutParams(lp);
- currentIndex = position;
- }
onPageScrolled中的三个参数比较重要。第一个参数是position。它的含义是表示当前显示的界面中的第一个界面。意思就是的当滑动的时
候,有可能出现两个界面,position指的是左边的界面。第二个参数是positionOffset指的是偏移量的比例,取值范围是[0,
1)。第三个参数是positionOffsetPixels是指偏移的像素值。后两个参数都相对页面(一个page)来说的。
我之前有看到过设置指示器的时候用的前两个参数的,我也试了一下,OK的。不过感觉比较复杂,看了一下官方api,用第三个参数更简单。关键就是理解第一个参数position。用这种方法我只在代码里有两个判断就可以完成了。
效果图如下:
五、Viewpager + PagerTitleStrip / PagerTabStrip
这种方式没有上一种效果好看,而且标题变动。看一下效果图:
布局文件:
- <?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" >
- <android.support.v4.view.ViewPager
- android:id="@+id/fifth_vp"
- android:layout_width="wrap_content"
- android:layout_height="wrap_content"
- android:layout_gravity="center" >
- <android.support.v4.view.PagerTabStrip
- android:id="@+id/fifth_strip"
- android:layout_width="wrap_content"
- android:layout_height="wrap_content"
- android:layout_gravity="top"
- android:background="#7EC0EE"
- android:padding="10dip" />
- </android.support.v4.view.ViewPager>
- </LinearLayout>
先来说一下PagerTitleStrip和PagerTabStrip的区别:PagerTitleStrip没有指示器,只有标题,且标题没有响应事
件;而PagerTabStrip是带有指示器的,当然也有标题,具有相应事件。二者的实现只在布局文件中有区别,只需要把
android.support.v4.view.PagerTabStrip改成
android.support.v4.viewPagerTitleStrip即可。
代码中需要注意的就是,在适配器中重写getPageTitle(int)方法来显示标题。
- PagerAdapter pagerAdapter = new PagerAdapter() {
- //此处省略其他的方法
- // 重写此方法即可显示标题
- @Override
- public CharSequence getPageTitle(int position) {
- return titleList.get(position);
- }
- ;
总结:
我目前所遇到的tab类型界面的实现方式就是这么多了,若果大家有其他的实现方式,请留言。如果我写的有误,请留言指正,共同进步!谢谢!
Demo下载地址:http://download.csdn.net/detail/crazy1235/8358671
Android UI 之 Tab类型界面总结的更多相关文章
- android ui篇 自己写界面
对于一些较为简单的界面则自己进行写. 在这里就需要了解xml文件中一些基本的属性以及android手机的知识. 一.目前手机屏幕像素密度基本有5种情况.(以下像素密度简称密度) 密度 ldpi mdp ...
- Android UI学习 - Tab的学习和使用(转)
本文是参考Android官方提供的sample里面的ApiDemos的学习总结. TabActivity 首先Android里面有个名为TabActivity来给我们方便使用.其中有以下可 ...
- android Tab 类型切换界面
实现方案:viewpager + fragment + FragmentPagerAdapter 效果图: 可以左右滑动切换选项卡,或者点击: 如果想使用fragment的时候又想可以左右滑动,就可以 ...
- Android项目Tab类型主界面大总结 Fragment+TabPageIndicator+ViewPager
转载请标明出处:http://blog.csdn.net/lmj623565791/article/details/24740977 Android如今实现Tab类型的界面方式越来越多,今天就把常见的 ...
- Android Tab类型主界面 Fragment+TabPageIndicator+ViewPager
文章地址: Android项目Tab类型主界面大总结 Fragment+TabPageIndicator+ViewPager 1.使用ViewPager + PagerAdapter 每个页面的内容都 ...
- Android UI开发第三十九篇——Tab界面实现汇总及比较
Tab布局是iOS的经典布局,Android应用中也有大量应用,前面也写过Android中TAb的实现,<Android UI开发第十八篇——ActivityGroup实现tab功能>.这 ...
- 【Android UI设计与开发】第05期:引导界面(五)实现应用程序只启动一次引导界面
[Android UI设计与开发]第05期:引导界面(五)实现应用程序只启动一次引导界面 jingqing 发表于 2013-7-11 14:42:02 浏览(229501) 这篇文章算是对整个引导界 ...
- android ui界面设计参数讲解
百度文库: http://wenku.baidu.com/link?url=s66Hw6byBEzmjL77doYL1YQN4Y_39F7MovaHKs5mVGrzTDOQCAmiM-1N_6Cdm- ...
- iPhone/iPad/Android UI尺寸规范 UI尺寸规范,UI图标尺寸,UI界面尺寸,iPhone6尺寸,iPhone6 Plus尺寸,安卓尺寸,iOS尺寸
iPhone/iPad/Android UI尺寸规范 UI尺寸规范,UI图标尺寸,UI界面尺寸,iPhone6尺寸,iPhone6 Plus尺寸,安卓尺寸,iOS尺寸 iPhone界面尺寸 设备 分辨 ...
随机推荐
- AUTH过程
INITIALIZE UPDATE: 在安全通道的显式发起期间,INITIALIZEUPDATE命令用于在卡和主机之间传送卡和会话数据.这个命令开始一个安全通道会话的发起. CPURESET() // ...
- 第三次作业,github的基本操作
chengjiangtao@pc MINGW32 ~$ git config --global user.name "chengjiangtao" chengjiangtao@pc ...
- Node.js 学习(四)Node.js 回调函数
Node.js 异步编程的直接体现就是回调. 异步编程依托于回调来实现,但不能说使用了回调后程序就异步化了. 回调函数在完成任务后就会被调用,Node 使用了大量的回调函数,Node 所有 API 都 ...
- OpenCms 集成外部Solr Server
OpenCms默认是以内嵌的Solr作为全文搜索服务的,不过我们也可以配置一个独立的Solr搜索服务器 设置外部Solr Server 1. 从Solr 官方站点http://lucene.apach ...
- cygwin and its host machine
Senario 本来我是想要修改下 machine name 在Ubuntu中的步骤是这样的 1 sudo hostname newMechineName 2 sudo vi /etc/hostnam ...
- HDU 5763 Another Meaning KMP+DP
题目链接: http://acm.hdu.edu.cn/showproblem.php?pid=5763 Another Meaning Time Limit: 2000/1000 MS (Java/ ...
- ionice
ionice – 获取或设置程序的IO调度与优先级. 命令格式: ionice [[-c class] [-n classdata] [-t]] -p PID [PID]… ionice [-c cl ...
- 02.JSP的3个编译指令
本章介绍JSP的3个编译指令,在JSP中常见的编译指令有如下3个: 1.page:用于针对当前页面的指令. 2.include:用于指定包含另一个页面. ...
- 【BZOJ】【1030】【JSOI2007】文本生成器
AC自动机/DP Orz ZYF 玛雅快要省选了,赶紧复(xue)习(xi)一下AC自动机…… 其实在AC自动机上DP并没有当初想的那么复杂……就是把DP的转移关系换成了AC自动机上的边而已(不过这题 ...
- <string>和<string.h>的区别
转自:http://blog.csdn.net/houjixin/article/details/8648969 在C++开发过程中经常会遇到两个比较容易混淆的头文件引用#include<str ...