您的位置:首页 > 其它

自定义TabBarView,快速实现Tab+ViewPager的Activity

2017-05-24 17:21 483 查看
先来看两个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 checke
dcca
d 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
childrenBottomMargincenterView相对于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()分别提供的集合的长度必须一致。
内容来自用户分享和网络整理,不保证内容的准确性,如有侵权内容,可联系管理员处理 点击这里给我发消息