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

来源:互联网 发布:cost of equity 知乎 编辑:程序博客网 时间:2024/06/07 04:05

先来看两个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()分别提供的集合的长度必须一致。

原创粉丝点击