android上FragmentTabHost实现自己定义Tab Indicator
近期一直在做安卓开发,发现Tab布局能够用FragmentTabHost来实现,唯一不好的就是不能实现带图标的tabindicator, V4版本号中的尽管API有支持,可是不管怎么设置Drawable对象都不起作用,所以被逼无赖。发现indicator能够支持传进一个View做tabtitle,于是经过一番各种坑之后,我做了一个自己定义的Tab indicator,能够实现切换提示、显示带图标的tabtitle,同一时候支持滑动切换到不同Tab。
首先来看一下效果吧。
我的实现思路是这种:
第一步。当然是建立android V4版本号的FragmentTabHost的布局XML文件,普通情况下是不建议修改的,我是直接copy官网上的。
文件内容例如以下:
<?xml version="1.0" encoding="utf-8"?>
<android.support.v4.app.FragmentTabHost
xmlns:android="http://schemas.android.com/apk/res/android"
android:id="@android:id/tabhost"
android:layout_width="match_parent"
android:layout_height="match_parent" > <LinearLayout
android:layout_width="match_parent"
android:layout_height="match_parent"
android:orientation="vertical" > <TabWidget
android:id="@android:id/tabs"
android:layout_width="fill_parent"
android:layout_height="wrap_content"
android:layout_gravity="bottom"/> <FrameLayout
android:id="@android:id/tabcontent"
android:layout_width="fill_parent"
android:layout_height="0dp"
android:layout_weight="1" />
</LinearLayout> </android.support.v4.app.FragmentTabHost>
第二步,建立自己定义的tab-indicator XML布局文件,实现自己定义tab title View。XML文件内容例如以下:
<?xml version="1.0" encoding="utf-8"?>
<LinearLayout xmlns:android="http://schemas.android.com/apk/res/android"
android:layout_width="fill_parent"
android:layout_height="fill_parent"
android:orientation="horizontal" > <LinearLayout
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:orientation="vertical" > <LinearLayout
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:orientation="horizontal" > <ImageView
android:id="@+id/tab_icon_1"
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:layout_margin="5dp"
android:contentDescription="icon" /> <TextView
android:id="@+id/tab_name_1"
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:textColor="#000"
android:textSize="24sp" />
</LinearLayout> <View
android:id="@+id/tab_border_line_1"
android:layout_width="fill_parent"
android:layout_height="3dp"
android:background="#ff0000" />
</LinearLayout> <LinearLayout
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:orientation="vertical" > <LinearLayout
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:orientation="horizontal" > <ImageView
android:id="@+id/tab_icon_2"
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:layout_margin="5dp"
android:contentDescription="icon" /> <TextView
android:id="@+id/tab_name_2"
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:textColor="#000"
android:textSize="24sp" />
</LinearLayout> <View
android:id="@+id/tab_border_line_2"
android:layout_width="fill_parent"
android:layout_marginTop="1dp"
android:layout_height="3dp"
android:background="#ff0000" />
</LinearLayout> <LinearLayout
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:orientation="vertical" > <LinearLayout
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:orientation="horizontal" > <ImageView
android:id="@+id/tab_icon_3"
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:layout_margin="5dp"
android:contentDescription="icon" /> <TextView
android:id="@+id/tab_name_3"
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:textColor="#000"
android:textSize="24sp" />
</LinearLayout> <View
android:id="@+id/tab_border_line_3"
android:layout_width="fill_parent"
android:layout_marginTop="0.5dp"
android:layout_height="3dp"
android:background="#ff0000" />
</LinearLayout> </LinearLayout>
第四步:当然是在MainActivity的onCreate方法中实现FragmentTabHost对象的初始化,建立一个真正的tab布局界面。
代码实现例如以下:
tabHost = (FragmentTabHost) findViewById(android.R.id.tabhost);
tabHost.setup(this, getSupportFragmentManager(), android.R.id.tabcontent);
第五步:也是最恶搞的一步,就是把View传到V4的每一个tab的indicator中去,这里要特别说明一下。事实上起作用的仅仅有第一个设置进去的View,其他尽管是必须的,可是无需不论什么设置。否则FragmentTabHost将无法正常工作。这个是我吐血得到的教训:代码例如以下:
ImageView piv = (ImageView)llView.findViewById(R.id.tab_icon_1);
TextView ptv = (TextView)llView.findViewById(R.id.tab_name_1);
ptv.setText("找人");
piv.setImageBitmap(personIcon); piv = (ImageView)llView.findViewById(R.id.tab_icon_2);
ptv = (TextView)llView.findViewById(R.id.tab_name_2);
ptv.setText("圈子");
piv.setImageBitmap(circleIcon); piv = (ImageView)llView.findViewById(R.id.tab_icon_3);
ptv = (TextView)llView.findViewById(R.id.tab_name_3);
ptv.setText("博客");
piv.setImageBitmap(blogIcon); // 必须有这个,可是没有鸟用
View view2 = getLayoutInflater().inflate(R.layout.tab_indicator, (ViewGroup) mRoot.findViewById(android.R.id.tabs), false);
View view3 = getLayoutInflater().inflate(R.layout.tab_indicator, (ViewGroup) mRoot.findViewById(android.R.id.tabs), false); Log.i("my-debug", "go here to setup tab content");
tabHost.addTab(
tabHost.newTabSpec("找人").setIndicator(llView),
PersonFragment.class, null);
tabHost.addTab(
tabHost.newTabSpec("圈子").setIndicator(view2),
CircleFragment.class, null);
tabHost.addTab(
tabHost.newTabSpec("博客").setIndicator(view3),
BlogFragment.class, null);
第六步。加入手势側滑支持与现实默觉得第一个tab上的内容,实现代码例如以下:
// 显示第一tab内容Fragment
tabHost.setCurrentTab(0);
View v = (View)llView.findViewById(R.id.tab_border_line_1);
v.setBackgroundColor(Color.BLUE);
mDetector = new GestureDetectorCompat(this, new MyGestureListener());
当中手势側滑支持基于SimpleOnGestureListener类实现,同一时候要重载onTouchEvent方法才干够工作。
完整的MainActivity的代码例如以下:
package com.example.gesturedemo; import android.annotation.SuppressLint;
import android.graphics.Bitmap;
import android.graphics.BitmapFactory;
import android.graphics.Color;
import android.os.Bundle;
import android.support.v4.app.FragmentActivity;
import android.support.v4.app.FragmentTabHost;
import android.support.v4.view.GestureDetectorCompat;
import android.util.Log;
import android.view.GestureDetector;
import android.view.MotionEvent;
import android.view.View;
import android.view.ViewGroup;
import android.widget.ImageView;
import android.widget.TextView;
import android.widget.Toast; @SuppressLint("NewApi")
public class MainActivity extends FragmentActivity {
private FragmentTabHost tabHost;
private GestureDetectorCompat mDetector;
private View llView;
private static int tabIndex = 0;
@Override
protected void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
setContentView(R.layout.activity_main); // get tabhost and setup it
tabHost = (FragmentTabHost) findViewById(android.R.id.tabhost);
tabHost.setup(this, getSupportFragmentManager(), android.R.id.tabcontent); // load icons
Bitmap personIcon = BitmapFactory.decodeResource(this.getResources(), R.drawable.person);
Bitmap circleIcon = BitmapFactory.decodeResource(this.getResources(), R.drawable.circle);
Bitmap blogIcon = BitmapFactory.decodeResource(this.getResources(), R.drawable.blog); // add tabs
Log.i("my-debug", "go here to setup tab header");
View mRoot = getLayoutInflater().inflate(R.layout.activity_main, null);
llView = getLayoutInflater().inflate(R.layout.tab_indicator, (ViewGroup) mRoot.findViewById(android.R.id.tabs), false); ImageView piv = (ImageView)llView.findViewById(R.id.tab_icon_1);
TextView ptv = (TextView)llView.findViewById(R.id.tab_name_1);
ptv.setText("找人");
piv.setImageBitmap(personIcon); piv = (ImageView)llView.findViewById(R.id.tab_icon_2);
ptv = (TextView)llView.findViewById(R.id.tab_name_2);
ptv.setText("圈子");
piv.setImageBitmap(circleIcon); piv = (ImageView)llView.findViewById(R.id.tab_icon_3);
ptv = (TextView)llView.findViewById(R.id.tab_name_3);
ptv.setText("博客");
piv.setImageBitmap(blogIcon); // 必须有这个。可是没有鸟用
View view2 = getLayoutInflater().inflate(R.layout.tab_indicator, (ViewGroup) mRoot.findViewById(android.R.id.tabs), false);
View view3 = getLayoutInflater().inflate(R.layout.tab_indicator, (ViewGroup) mRoot.findViewById(android.R.id.tabs), false); Log.i("my-debug", "go here to setup tab content");
tabHost.addTab(
tabHost.newTabSpec("找人").setIndicator(llView),
PersonFragment.class, null);
tabHost.addTab(
tabHost.newTabSpec("圈子").setIndicator(view2),
CircleFragment.class, null);
tabHost.addTab(
tabHost.newTabSpec("博客").setIndicator(view3),
BlogFragment.class, null); // 显示第一tab内容Fragment
tabHost.setCurrentTab(0);
View v = (View)llView.findViewById(R.id.tab_border_line_1);
v.setBackgroundColor(Color.BLUE);
mDetector = new GestureDetectorCompat(this, new MyGestureListener());
} @Override
public boolean onTouchEvent(MotionEvent event) {
this.mDetector.onTouchEvent(event);
return super.onTouchEvent(event);
} public void showNextTab()
{
tabIndex++;
if(tabIndex >= 3)
{
tabIndex = 0;
}
tabHost.setCurrentTab(tabIndex);
View v1 = (View)llView.findViewById(R.id.tab_border_line_1);
View v2 = (View)llView.findViewById(R.id.tab_border_line_2);
View v3 = (View)llView.findViewById(R.id.tab_border_line_3);
v1.setBackgroundColor(Color.RED);
v2.setBackgroundColor(Color.RED);
v3.setBackgroundColor(Color.RED);
if(tabIndex == 0) {
v1.setBackgroundColor(Color.BLUE);
}
else if(tabIndex == 1) {
v2.setBackgroundColor(Color.BLUE);
}
else if(tabIndex == 2) {
v3.setBackgroundColor(Color.BLUE);
}
} class MyGestureListener extends GestureDetector.SimpleOnGestureListener {
private static final String DEBUG_TAG = "Gestures"; @Override
public boolean onDown(MotionEvent event) {
Log.d(DEBUG_TAG, "onDown: " + event.getX());
return true;
} @Override
public boolean onFling(MotionEvent event1, MotionEvent event2, float velocityX, float velocityY) {
Log.d(DEBUG_TAG, "onFling: " + event1.getX());
float deltaX = event1.getX() - event2.getX();
Log.i("gesture", "deltaX : " + deltaX);
if(deltaX > 20) {
showNextTab();
}
else {
Toast.makeText(getApplicationContext(), "从右向左滑动開始应用...", Toast.LENGTH_SHORT).show();
}
return true;
}
} }
使用的三个Fragment程序代码基本一样,无需一一给出,这里仅仅给出PersonFragment类的实现代码例如以下:
package com.example.gesturedemo; import android.os.Bundle;
import android.support.v4.app.Fragment;
import android.view.LayoutInflater;
import android.view.View;
import android.view.ViewGroup;
import android.widget.TextView; public class PersonFragment extends Fragment { @Override
public void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
} @Override
public View onCreateView(LayoutInflater inflater, ViewGroup container,
Bundle savedInstanceState) {
View v = inflater.inflate(R.layout.common_content, container, false);
TextView tv = (TextView) v.findViewById(R.id.textView1);
tv.setText("相逢未必曾相识");
return v;
}
}
使用的布局文件XML内容例如以下:
<?xml version="1.0" encoding="utf-8"? >
<LinearLayout xmlns:android="http://schemas.android.com/apk/res/android"
android:layout_width="fill_parent"
android:layout_height="fill_parent"
android:orientation="vertical" > <TextView
android:id="@+id/textView1"
android:layout_width="fill_parent"
android:layout_height="wrap_content"
android:textSize="36sp"
android:gravity="center"
android:text="tabhost" /> </LinearLayout>
android上FragmentTabHost实现自己定义Tab Indicator的更多相关文章
- Android 上的 制表符(tab) —— 一个奇妙的字符 (cocos2dx crash)
今天測试发现了游戏的一个问题,系统邮件,假设发了tab,在android上一打开邮件内容就会crash.并且他们非常确定是tab的问题. 凭我多个月的经验(确实没多年. . .)来看.从来没听说在an ...
- Android典型界面设计——FragmentTabHost+Fragment实现底部tab切换
一.问题描述 在上次博文中,我们使用RadioGroup+ViewPage+Fragmen实现了顶部滑动导航(查看文章:http://www.cnblogs.com/jerehedu/p/460759 ...
- 怎样 TabHostFragment自己定义 tab键(indicator)
1 获得 tabHostFragment: ActionBarActivity activity2 = (ActionBarActivity) activity; mTabHost = new Fra ...
- [Android] Android 使用 FragmentTabHost + Fragment 实现 微信 底部菜单
Android 使用 FragmentTabHost + Fragment 实现 微信 底部菜单 利用FragmentTabHost实现底部菜单,在该底部菜单中,包括了4个TabSpec,每个TabS ...
- android FragmentActivity+FragmentTabHost+Fragment框架布局
这周比较闲,计划系统的学习一下android开发,我本是一名IOS程序员,对手机开发还是有自己的一套思路的, 固这套思路用到我当前学android上了,先选择从Main页面的tabbar部分代码入手, ...
- Android 上使用 iconfont 的一种便捷方案
最近在学习 AIOSO(Alibaba Internal Open Source Organization,即阿里巴巴内部开源组织) 的一个子项目MMCherryUI,这是一个流式布局,可以在运行时做 ...
- 【Android Developers Training】 8. 定义Action Bar风格
注:本文翻译自Google官方的Android Developers Training文档,译者技术一般,由于喜爱安卓而产生了翻译的念头,纯属个人兴趣爱好. 原文链接:http://developer ...
- Android上dip、dp、px、sp等单位说明(转)
dip device independent pixels(设备独立像素). 不同设备不同的显示效果,这个和设备硬件有关,一般我们为了支持WVGA.HVGA和QVGA 推荐使用这个,不依赖像素. 在 ...
- Android上dip、dp、px、sp等单位说明
Android上dip.dp.px.sp等单位说明 dip device independent pixels(设备独立像素). 不同设备不同的显示效果,这个和设备硬件有关,一般我们为了支持WVGA ...
随机推荐
- Linux基础系列-Day7
NFS服务(基于CentOS 7.0) NFS(Network File System),网络文件系统,是linux与linux之间进行文件共享的服务,在NFS应用,本地NFS的客户端可以透明地读写位 ...
- Python的替换函数——strip(),replace()和re.sub()(转)
原文地址:http://blog.csdn.net/zcmlimi/article/details/47709049 在Python中常用的三个"替换"函数是strip(),rep ...
- 【BZOJ 2646】【NEERC 2011】flight
http://www.lydsy.com/JudgeOnline/problem.php?id=2646 夏令营alpq654321讲课时说这道题很简单但并没有几个人提交,最近想复习一下线段树,脑袋一 ...
- [BZOJ2006][NOI2010]超级钢琴(ST表+堆)
2006: [NOI2010]超级钢琴 Time Limit: 20 Sec Memory Limit: 512 MBSubmit: 3679 Solved: 1828[Submit][Statu ...
- 【构造】Ural Championship April 30, 2017 Problem K. King’s island
题意:让你构造一个n个点的简单多边形,使得所有点是整点,并且所有边长是整数,并且没有边平行于坐标轴. 就利用勾股数,如下图这样构造即可,n为偶数时,只需矩形拼成,n为奇数时,封上虚线边即可. #inc ...
- [Luogu1843]奶牛晒衣服
题目大意: 你要晒n件衣服,第i件衣服有w[i]滴水, 每件衣服每秒钟会自然风干a滴水,将这件衣服放入烘干机中每秒钟会烘干a+b滴水. 一秒钟不可以拆开,问晒干所有的衣服至少要多少时间? 思路: 二分 ...
- 21点游戏java实现
21点的基本知识 21点是世界上比较流行的扑克游戏项目 除掉大小王的一副扑克牌,共计52张牌 21点不区分花色,其中A----10均代表扑克牌本身的点数J Q K代表10点 区分庄家和闲家,其中闲家可 ...
- java阶乘问题
问题描述: 编写代码求:1!+2!+3!+…+20!的值 代码 public class Demo { public static void main(String[] args) { long nu ...
- Promise对象的基本用法
主要作用 1.用来传递异步操作的消息 2.三种状态:pending.Resolved.Rejected,而且只能从第一种状态转到后两者状态之一. 3.缺点 (1)一旦新建就会立即执行 (2)如果不设置 ...
- Codeforces Gym 100269D Dwarf Tower spfa
Dwarf Tower 题目连接: http://codeforces.com/gym/100269/attachments Description Little Vasya is playing a ...