关闭 x
IT技术网
    技 采 号
    ITJS.cn - 技术改变世界
    • 实用工具
    • 菜鸟教程
    IT采购网 中国存储网 科技号 CIO智库

    IT技术网

    IT采购网
    • 首页
    • 行业资讯
    • 系统运维
      • 操作系统
        • Windows
        • Linux
        • Mac OS
      • 数据库
        • MySQL
        • Oracle
        • SQL Server
      • 网站建设
    • 人工智能
    • 半导体芯片
    • 笔记本电脑
    • 智能手机
    • 智能汽车
    • 编程语言
    IT技术网 - ITJS.CN
    首页 » 安卓开发 »Android UI 之 Tab类型界面总结

    Android UI 之 Tab类型界面总结

    2015-08-12 00:00:00 出处:CSDN
    分享

    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() {  
    //官方建议这么写  
            @Override  
            public boolean isViewFromObject(View arg0, Object arg1) {  
                return arg0 == arg1;  
            }  
     //返回一共有多少个界面  
            @Override  
            public int getCount() {  
                return list.size();  
            }  
    //实例化一个item  
            @Override  
            public Object instantiateItem(ViewGroup container, int position) {  
                container.addView(list.get(position));  
                return list.get(position);  
            }  
    //销毁一个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);  
    }
    上一篇返回首页 下一篇

    声明: 此文观点不代表本站立场;转载务必保留本文链接;版权疑问请联系我们。

    别人在看

    电脑屏幕不小心竖起来了?别慌,快捷键搞定

    Destoon 模板存放规则及语法参考

    Destoon系统常量与变量

    Destoon系统目录文件结构说明

    Destoon 系统安装指南

    Destoon会员公司主页模板风格添加方法

    Destoon 二次开发入门

    Microsoft 将于 2026 年 10 月终止对 Windows 11 SE 的支持

    Windows 11 存储感知如何设置?了解Windows 11 存储感知开启的好处

    Windows 11 24H2 更新灾难:系统升级了,SSD固态盘不见了...

    IT头条

    Synology 更新 ActiveProtect Manager 1.1 以增强企业网络弹性和合规性

    00:43

    新的 Rubrik Agent Cloud 加速了可信的企业 AI 代理部署

    00:34

    宇树科技 G1人形机器人,拉动一辆重达1.4吨的汽车

    00:21

    Cloudera 调查发现,96% 的企业已将 AI 集成到核心业务流程中,这表明 AI 已从竞争优势转变为强制性实践

    02:05

    投资者反对马斯克 1 万亿美元薪酬方案,要求重组特斯拉董事会

    01:18

    技术热点

    大型网站的 HTTPS 实践(三):基于协议和配置的优化

    ubuntu下右键菜单添加新建word、excel文档等快捷方式

    Sublime Text 简明教程

    用户定义SQL Server函数的描述

    怎么在windows 7开始菜单中添加下载选项?

    SQL Server 2016将有哪些功能改进?

      友情链接:
    • IT采购网
    • 科技号
    • 中国存储网
    • 存储网
    • 半导体联盟
    • 医疗软件网
    • 软件中国
    • ITbrand
    • 采购中国
    • CIO智库
    • 考研题库
    • 法务网
    • AI工具网
    • 电子芯片网
    • 安全库
    • 隐私保护
    • 版权申明
    • 联系我们
    IT技术网 版权所有 © 2020-2025,京ICP备14047533号-20,Power by OK设计网

    在上方输入关键词后,回车键 开始搜索。Esc键 取消该搜索窗口。