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

本文介绍了如何使用自定义组件TabBarView实现带有Tab和ViewPager的Activity,通过HomeWithTabActivity.java和OrderListWithTabActivity.java的代码示例,展示了其通用性和实现细节。TabBarView具有特定的API接口,并强调了setTabItemViews()方法的使用限制。同时,TabWithViewPagerBaseActivity是一个抽象基类,提供了利用TabBarView和ViewPager的模板,需要注意布局文件的设置以及getTabViews()和getFragments()方法返回的集合长度匹配。

摘要生成于 C知道 ,由 DeepSeek-R1 满血版支持, 前往体验 >

先来看两个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
enumTabBarView.ItemStyle
Item的展示样式枚举,有三种样式:ICON, TEXT, ICON_TEXT
interfaceTabBarView.OnCheckedChangeListener点击Item切换tab时的回调
classTabBarView.TabItemView
ItemView,继承至LinearLayout
XML added attributes
childrenBottomMargincenterView相对于TabBarView的底部外边距,默认为40。
eg.childrenBottomMargin="40"
Public methods
voidsetItemStyle(@NonNull ItemStyle itemStyle)
设置tabItemView的展示样式
voidsetTabItemViews(@NonNull List<TabItemView> tabItemViews)
设置tabItemView集合
voidsetTabItemViews(@NonNull List<TabItemView> tabItemViewList, View centerView)
设置tabItemView集合和centerView
voidvoid check(int position)
切换选中的tabItemView
TabItemViewgetCheckedTabItemView()
返回当前选中的tabItemView
voidsetOnCheckedChangeListener(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.ItemStylegetItemStyle()
返回tabItemView的展示样式
ListgetTabViews()
提供tabItemView的集合,不可返回null
List< Fragment>getFragments()
提供Fragment的集合,不可返回null
ViewgetCenterView()
提供一个中间按钮,可返回null
intgetContentLayout()
提供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()分别提供的集合的长度必须一致。

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值