您的位置:首页 > 产品设计 > UI/UE

Android UI 之 Tab类型界面总结

2015-09-14 12:27 501 查看
本文转自:/article/1372663.html

Android 程序中实现Tab类型界面很常见,本人在做项目的时候也经常用到,所以想在这里总结一下,实现tab类型界面的几种方式,供大家参考。如有不对之处,欢迎大家指正!


一、TabActivity + TabWidget + TabHost.

实现TAB类型界面,首先想到的就是这种方式。但是在API level 13之后官方就不建议使用它了。不过还是在这里简单说一下它的使用吧。



使用它的关键就是布局文件了。需要在布局中添加<TabHost>、<TabWidget>、<FrameLayout>这三个控件,id分别是系统提供的:@android:id/tabhost 、@android:id/tabs 、@android:id/tabcontent 。

[html] view
plaincopy





<?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页面的布局。

[java] view
plaincopy





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)

下面看一下这种方式的效果图:



主要的功能代码如下:

[java] view
plaincopy





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) {

}

});

}

[java] view
plaincopy





private PagerAdapter pagerAdapter = new PagerAdapter() {

[java] view
plaincopy





<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));

}

};

适配器中必须要实现以上的四个方法。

如果只有这几个页面,交互性肯定是不好的,所以需要添加“指示器”,用来标识当前的页面是哪一个!我在这里用点来实现。就像效果图显示的那样。

[java] view
plaincopy





/**

* 初始化底部的点

*/

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)这个方法了。

[java] view
plaincopy





@Override

public void onPageSelected(int arg0) {

setDots(arg0);

}


三、Fragment + FragmentManager

fragment相信大家在项目中肯定都用过。这个方法主要就是利用fragmentManager对fragment的事务管理功能。

[java] view
plaincopy





// 三个选项卡

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.

[java] view
plaincopy





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对象。

[java] view
plaincopy





/**

* 初始化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添加点击事件。

[java] view
plaincopy





@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()方法中进行设置。

[java] view
plaincopy





@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

这种方式没有上一种效果好看,而且标题变动。看一下效果图:



布局文件:

[html] view
plaincopy





<?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)方法来显示标题。

[java] view
plaincopy





PagerAdapter pagerAdapter = new PagerAdapter() {

//此处省略其他的方法

[java] view
plaincopy





// 重写此方法即可显示标题

@Override

public CharSequence getPageTitle(int position) {

return titleList.get(position);

}

;



总结:

我目前所遇到的tab类型界面的实现方式就是这么多了,若果大家有其他的实现方式,请留言。如果我写的有误,请留言指正,共同进步!谢谢!

Demo下载地址:http://download.csdn.net/detail/crazy1235/8358671
内容来自用户分享和网络整理,不保证内容的准确性,如有侵权内容,可联系管理员处理 点击这里给我发消息
标签: