先来看两个Activity的页面效果:
这两个Activity页面的实现代码分别为:
HomeWithTabActivity.java
package zou.zohar.tabbarview.activity;
import android.os.Bundle;
import android.support.design.widget.Snackbar;
import android.support.v4.app.Fragment;
import android.view.View;
import android.widget.ImageView;
import java.util.ArrayList;
import java.util.List;
import zou.zohar.tabbarview.R;
import zou.zohar.tabbarview.fragment.TabFragment1;
import zou.zohar.tabbarview.fragment.TabFragment2;
import zou.zohar.tabbarview.fragment.TabFragment3;
import zou.zohar.tabbarview.fragment.TabFragment4;
import zou.zohar.tabbarview.widge.TabBarView;
public class HomeWithTabActivity extends TabWithViewPagerBaseActivity {
@Override
protected void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
}
@Override
public TabBarView.ItemStyle getItemStyle() {
return TabBarView.ItemStyle.ICON_TEXT;
}
@Override
public List<TabBarView.TabItemView> getTabViews() {
List<TabBarView.TabItemView> tabItemViews = new ArrayList<>();
tabItemViews.add(new TabBarView.TabItemView(this, "标题1", R.color.colorPrimary,
R.color.colorAccent, R.mipmap.ic_launcher, R.mipmap.ic_launcher_deep));
tabItemViews.add(new TabBarView.TabItemView(this, "标题2", R.color.colorPrimary,
R.color.colorAccent, R.mipmap.ic_launcher, R.mipmap.ic_launcher_deep));
tabItemViews.add(new TabBarView.TabItemView(this, "标题3", R.color.colorPrimary,
R.color.colorAccent, R.mipmap.ic_launcher, R.mipmap.ic_launcher_deep));
tabItemViews.add(new TabBarView.TabItemView(this, "标题4", R.color.colorPrimary,
R.color.colorAccent, R.mipmap.ic_launcher, R.mipmap.ic_launcher_deep));
return tabItemViews;
}
@Override
public List<Fragment> getFragments() {
List<Fragment> fragments = new ArrayList<>();
fragments.add(new TabFragment1());
fragments.add(new TabFragment2());
fragments.add(new TabFragment3());
fragments.add(new TabFragment4());
return fragments;
}
@Override
public View getCenterView() {
ImageView imageView = new ImageView(this);
imageView.setImageResource(R.mipmap.ic_launcher_round);
imageView.setOnClickListener(new View.OnClickListener() {
@Override
public void onClick(View v) {
Snackbar.make(v, "center view click", Snackbar.LENGTH_SHORT).show();
}
});
return imageView;
}
@Override
public int getContentLayout() {
return R.layout.activity_home_with_tab;
}
}
OrderListWithTabActivity.java
package zou.zohar.tabbarview.activity;
import android.os.Bundle;
import android.support.v4.app.Fragment;
import android.view.View;
import java.util.ArrayList;
import java.util.List;
import zou.zohar.tabbarview.R;
import zou.zohar.tabbarview.fragment.TabFragment1;
import zou.zohar.tabbarview.fragment.TabFragment2;
import zou.zohar.tabbarview.fragment.TabFragment3;
import zou.zohar.tabbarview.fragment.TabFragment4;
import zou.zohar.tabbarview.widge.TabBarView;
public class OrderListWithTabActivity extends TabWithViewPagerBaseActivity {
@Override
protected void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
}
@Override
public TabBarView.ItemStyle getItemStyle() {
return TabBarView.ItemStyle.TEXT;
}
@Override
public List<TabBarView.TabItemView> getTabViews() {
List<TabBarView.TabItemView> tabItemViews = new ArrayList<>();
tabItemViews.add(new TabBarView.TabItemView(this, "已完成", R.color.colorPrimary,
R.color.colorAccent, R.mipmap.ic_launcher, R.mipmap.ic_launcher_deep));
tabItemViews.add(new TabBarView.TabItemView(this, "未付款", R.color.colorPrimary,
R.color.colorAccent, R.mipmap.ic_launcher, R.mipmap.ic_launcher_deep));
tabItemViews.add(new TabBarView.TabItemView(this, "待收货", R.color.colorPrimary,
R.color.colorAccent, R.mipmap.ic_launcher, R.mipmap.ic_launcher_deep));
tabItemViews.add(new TabBarView.TabItemView(this, "待评价", R.color.colorPrimary,
R.color.colorAccent, R.mipmap.ic_launcher, R.mipmap.ic_launcher_deep));
return tabItemViews;
}
@Override
public List<Fragment> getFragments() {
List<Fragment> fragments = new ArrayList<>();
fragments.add(new TabFragment1());
fragments.add(new TabFragment2());
fragments.add(new TabFragment3());
fragments.add(new TabFragment4());
return fragments;
}
@Override
public View getCenterView() {
return null;
}
@Override
public int getContentLayout() {
return R.layout.activity_order_list_with_tab;
}
}
看起来,两者的代码几乎是一模一样的,唯一不同的就是他们各自的xmlLayout布局文件不同。
接下来我们来看看具体是怎么实现的。
首先介绍一下我们的自定义标签栏
TabBarView.java
package zou.zohar.tabbarview.widge;
import android.content.Context;
import android.content.res.TypedArray;
import android.support.annotation.NonNull;
import android.support.v4.content.ContextCompat;
import android.util.AttributeSet;
import android.view.Gravity;
import android.view.LayoutInflater;
import android.view.View;
import android.view.ViewGroup;
import android.widget.ImageView;
import android.widget.LinearLayout;
import android.widget.TextView;
import java.util.ArrayList;
import java.util.List;
import zou.zohar.tabbarview.R;
public class TabBarView extends LinearLayout {
/**
* attribute
* centerView的bottomMargin
*/
private int childrenBottomMargin;
/**
* tabItemView的展示样式
* 默认为 ICON_TEXT
*/
private ItemStyle mItemStyle = ItemStyle.ICON_TEXT;
/**
* 最新选择的item的position,-1表示没有选择任何一个
*/
private int mCheckedPos = -1;
/**
* tabItemViews集合
*/
private List<TabItemView> mTabItemViewList;
public TabBarView(Context context) {
super(context);
init();
}
public TabBarView(Context context, AttributeSet attrs) {
super(context, attrs);
TypedArray attributes = context.obtainStyledAttributes(attrs, R.styleable.TabItemView);
childrenBottomMargin = attributes.getInt(R.styleable.TabItemView_childrenBottomMargin, 40);
attributes.recycle();
init();
}
private void init() {
mTabItemViewList = new ArrayList<>();
}
public void setItemStyle(@NonNull ItemStyle itemStyle) {
this.mItemStyle = itemStyle;
}
public void setTabItemViews(@NonNull List<TabItemView> tabItemViews) {
setTabItemViews(tabItemViews, null);
}
public void setTabItemViews(@NonNull List<TabItemView> tabItemViewList, View centerView) {
/**
* 不能重复设置mTabItemViewList
*/
if (mTabItemViewList.size() != 0) {
throw new RuntimeException("mTabItemViewList cannot be repeated!");
}
mTabItemViewList.addAll(tabItemViewList);
if (mTabItemViewList.size() < 2) {
throw new RuntimeException("The length of mTabItemViewList must not be less than 2!");
}
for (int i = 0; i < mTabItemViewList.size(); i++) {
if (centerView != null && i == mTabItemViewList.size() / 2) {
/**
* 给centerView设置childrenBottomMargin属性
*/
LayoutParams layoutParams = new LayoutParams(ViewGroup.LayoutParams.WRAP_CONTENT, ViewGroup.LayoutParams.WRAP_CONTENT);
layoutParams.height = this.getLayoutParams().height + childrenBottomMargin;
layoutParams.bottomMargin = childrenBottomMargin;
layoutParams.gravity = Gravity.BOTTOM;
centerView.setLayoutParams(layoutParams);
this.addView(centerView);
}
final TabItemView tabItemView = mTabItemViewList.get(i);
tabItemView.setItemStyle(mItemStyle == ItemStyle.ICON || mItemStyle == ItemStyle.ICON_TEXT,
mItemStyle == ItemStyle.TEXT || mItemStyle == ItemStyle.ICON_TEXT);
this.addView(tabItemView);
final int currentItemPos = i;
tabItemView.setOnClickListener(new OnClickListener() {
@Override
public void onClick(View v) {
if (currentItemPos == mCheckedPos) {
return;
}
check(currentItemPos);
}
});
}
/**
* 舒适化所有的tabItemView
*/
for (TabItemView tab : mTabItemViewList) {
tab.setStatus(TabItemView.STATE_DEFAULT);
}
/**
* 默认选中第一个
*/
check(0);
}
/**
* 通过position的选择设置tabItemView的标识,使用-1作为清除标识的选择
*
* @param position tabItemView在TabBarView中的序号
*/
public void check(int position) {
if (position != -1 && position == mCheckedPos) {
return;
}
if (mCheckedPos != -1) {
mTabItemViewList.get(mCheckedPos).setStatus(TabItemView.STATE_DEFAULT);
}
if (position != -1) {
mTabItemViewList.get(position).setStatus(TabItemView.STATE_CHECKED);
}
setCheckedPos(position);
}
private void setCheckedPos(int checkedPos) {
mCheckedPos = checkedPos;
if (mOnCheckedChangeListener != null) {
mOnCheckedChangeListener.onCheckedChanged(this, mCheckedPos);
}
}
public TabItemView getCheckedTabItemView() {
return mTabItemViewList.get(mCheckedPos);
}
private OnCheckedChangeListener mOnCheckedChangeListener;
/**
* 注册一个回调函数,用来检查选项卡的选项更改
*
* @param listener the callback to call on checked state change
*/
public void setOnCheckedChangeListener(OnCheckedChangeListener listener) {
mOnCheckedChangeListener = listener;
}
public interface OnCheckedChangeListener {
/**
* <p>Called when the checked tab item has changed. When the
* selection is cleared, checkedId is -1.</p>
*
* @param tabBarView the tabBarView in which the checked tab item has changed
* @param checkedPos the position of the newly checked tab item
*/
void onCheckedChanged(TabBarView tabBarView, int checkedPos);
}
public enum ItemStyle {
ICON, TEXT, ICON_TEXT
}
/**
* ItemView
*/
public static class TabItemView extends LinearLayout {
/**
* 状态: checked and default
*/
public final static int STATE_DEFAULT = 1;
public final static int STATE_CHECKED = 2;
/**
* 标题:tabItemView上显示的文字
*/
public String title;
/**
* 标题的颜色: checked and default
*/
public int colorDef;
public int colorChecked;
/**
* 图标: checked and default
*/
public int iconResDef;
public int iconResChecked;
public ImageView ivIcon;
public TextView tvTitle;
public TabItemView(Context context, String title, int colorDef, int colorChecked,
int iconResDef, int iconResChecked) {
super(context);
this.title = title;
this.colorDef = colorDef;
this.colorChecked = colorChecked;
this.iconResDef = iconResDef;
this.iconResChecked = iconResChecked;
init();
}
public void init() {
View view = LayoutInflater.from(super.getContext()).inflate(R.layout.view_tab_item, this);
ivIcon = (ImageView) view.findViewById(R.id.ivIcon);
tvTitle = (TextView) view.findViewById(R.id.tvTitle);
LayoutParams layoutParams = new LayoutParams(ViewGroup.LayoutParams.MATCH_PARENT, ViewGroup.LayoutParams.MATCH_PARENT);
layoutParams.weight = 1;
view.setLayoutParams(layoutParams);
tvTitle.setText(title);
}
protected void setItemStyle(boolean showIcon, boolean showTitle) {
ivIcon.setVisibility(showIcon ? VISIBLE : GONE);
tvTitle.setVisibility(showTitle ? VISIBLE : GONE);
}
/**
* 设置itemView的状态
*/
public void setStatus(int status) {
ivIcon.setImageResource(status == STATE_CHECKED ? iconResChecked : iconResDef);
tvTitle.setTextColor(ContextCompat.getColor(super.getContext(), status == STATE_CHECKED ? colorChecked : colorDef));
}
}
}
再来看看它的API:
public class TabBarView extends LinearLayout
Nested classes | |
---|---|
enum | TabBarView.ItemStyle Item的展示样式枚举,有三种样式:ICON, TEXT, ICON_TEXT |
interface | TabBarView.OnCheckedChangeListener 点击Item切换tab时的回调 |
class | TabBarView.TabItemView ItemView,继承至LinearLayout |
XML added attributes | |
---|---|
childrenBottomMargin | centerView相对于TabBarView的底部外边距,默认为40。eg.childrenBottomMargin="40" |
Public methods | |
---|---|
void | setItemStyle(@NonNull ItemStyle itemStyle) 设置tabItemView的展示样式 |
void | setTabItemViews(@NonNull List<TabItemView> tabItemViews) 设置tabItemView集合 |
void | setTabItemViews(@NonNull List<TabItemView> tabItemViewList, View centerView) 设置tabItemView集合和centerView |
void | void check(int position) 切换选中的tabItemView |
TabItemView | getCheckedTabItemView() 返回当前选中的tabItemView |
void | setOnCheckedChangeListener(OnCheckedChangeListener listener) 设置切换tabItemView时的回调接口 |
注意事项:
1. setTabItemViews() 方法不可重复调用。
2. 如果需要有一个子超出父布局位置限制的centerView的话,需要在TabBarView的父布局xml中添加属性 android:clipChildren=”false”。
<?xml version="1.0" encoding="utf-8"?>
<RelativeLayout xmlns:android="http://schemas.android.com/apk/res/android"
xmlns:tools="http://schemas.android.com/apk/res-auto"
android:id="@+id/activity_home_with_tab"
android:layout_width="match_parent"
android:layout_height="match_parent"
android:clipChildren="false">
<zou.zohar.tabbarview.widge.TabBarView
android:id="@+id/tabBarView"
android:layout_width="match_parent"
android:layout_height="46dp"
tools:childrenBottomMargin="40" />
</RelativeLayout>
接下来,看一看用TabBarView+ViewPager封装的一个抽象的Activity
TabWithViewPagerBaseActivity.java
package zou.zohar.tabbarview.activity;
import android.os.Bundle;
import android.support.annotation.LayoutRes;
import android.support.v4.app.Fragment;
import android.support.v4.app.FragmentPagerAdapter;
import android.support.v4.view.ViewPager;
import android.support.v7.app.AppCompatActivity;
import android.view.View;
import java.util.List;
import zou.zohar.tabbarview.R;
import zou.zohar.tabbarview.widge.TabBarView;
/**
* Created by zohar on 2017/5/21.
* 抽象的含TabBarView和ViewPager的Activity
*/
public abstract class TabWithViewPagerBaseActivity extends AppCompatActivity {
private TabBarView tabBarView;
private ViewPager viewPager;
@Override
protected void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
setContentView(getContentLayout());
tabBarView = (TabBarView) findViewById(R.id.tabBarView);
viewPager = (ViewPager) findViewById(R.id.viewPager);
viewPager.setAdapter(new FragmentPagerAdapter(getSupportFragmentManager()) {
@Override
public Fragment getItem(int position) {
return getFragments().get(position);
}
@Override
public int getCount() {
return getFragments().size();
}
});
tabBarView.setItemStyle(getItemStyle() != null ? getItemStyle() : TabBarView.ItemStyle.ICON_TEXT);
tabBarView.setTabItemViews(getTabViews(), getCenterView());
tabBarView.setOnCheckedChangeListener(new TabBarView.OnCheckedChangeListener() {
@Override
public void onCheckedChanged(TabBarView tabBarView, int checkedPos) {
viewPager.setCurrentItem(checkedPos);
}
});
viewPager.addOnPageChangeListener(new ViewPager.OnPageChangeListener() {
@Override
public void onPageScrolled(int position, float positionOffset, int positionOffsetPixels) {
}
@Override
public void onPageSelected(int position) {
tabBarView.check(position);
}
@Override
public void onPageScrollStateChanged(int state) {
}
});
}
/**
* @return 返回tabItemView的展示样式 ( ICON, TEXT, ICON_TEXT)
*/
public abstract TabBarView.ItemStyle getItemStyle();
public abstract List<TabBarView.TabItemView> getTabViews();
public abstract List<Fragment> getFragments();
public abstract View getCenterView();
/**
* @return 返回xml布局文件
*/
public abstract
@LayoutRes
int getContentLayout();
}
看看它的API:
public abstract class TabWithViewPagerBaseActivity extends AppCompatActivity
Abstract methods | |
---|---|
TabBarView.ItemStyle | getItemStyle() 返回tabItemView的展示样式 |
List | getTabViews() 提供tabItemView的集合,不可返回null |
List< Fragment> | getFragments() 提供Fragment的集合,不可返回null |
View | getCenterView() 提供一个中间按钮,可返回null |
int | getContentLayout() 提供xml布局文件 |
注意事项:
1. 你的Activity的onCreat()方法中不能调用setContentView(int resLayout)方法,xmlLayout必须由getContentLayout()方法提供。
2. 由getContentLayout()方法提供的xml布局文件中必须得至少包含一个id为R.id.tabBarView的TabBarView和一个id为R.id.viewpager的ViewPager。
3. getTabViews()和getFragments()分别提供的集合的长度必须一致。