Android App之底部tab导航常用实现方案总结

前言:
开发中遇到的大多数APP底部都有tab, 但是其实现方式各有不同,各有各的优点,今天,小生就带大家总结总结,如有更好的,还望指教…

先看看效果图

《Android App之底部tab导航常用实现方案总结》 AppBottomTab.gif

先来看看项目的目录截图,因为代码比较稍多了点,截图的目的是为了贴出的分布代码看起来更清楚。

《Android App之底部tab导航常用实现方案总结》 AppBottomTab项目目录.png

说明:
这个目录相信大家看见就很明白了,关于第一种方式,大多数开发者应该都使用过了,这里就不贴代码了。下面看FragmentTabHost方式实现的代码。

frtabhost—>FrTabHostStyleAct.java中的布局代码

<?xml version="1.0" encoding="utf-8"?>
<LinearLayout xmlns:android="http://schemas.android.com/apk/res/android"
    android:layout_width="match_parent"
    android:layout_height="match_parent"
    android:orientation="vertical">

    <FrameLayout
        android:id="@+id/realtabcontent"
        android:layout_width="match_parent"
        android:layout_height="0dip"
        android:layout_weight="1" />

    <FrameLayout
        android:layout_width="match_parent"
        android:layout_height="wrap_content">

        <View
            android:layout_width="match_parent"
            android:layout_height="1px"
            android:background="@android:color/darker_gray" />

        <myapp.com.mjj.appbottomtab.frtabhost.MyFragmentTabHost
            android:id="@+id/mytabhost"
            android:layout_width="match_parent"
            android:layout_height="wrap_content"
            android:layout_gravity="center_vertical" />

    </FrameLayout>
</LinearLayout>

FrTabHostStyleAct.java

public class FrTabHostStyleAct extends AppCompatActivity implements TabHost.OnTabChangeListener, View.OnTouchListener {

    private MyFragmentTabHost mTabHost;
    private CharSequence mTitle; // tab的底部文字
    private String[] mTitles;

    @Override
    protected void onCreate(@Nullable Bundle savedInstanceState) {
        super.onCreate(savedInstanceState);
        setContentView(R.layout.activity_frtabhoststyleact);
        initView();
    }

    private void initView() {
        mTitle = getResources().getString(R.string.main_tab_name_explore);
        mTitles = getResources().getStringArray(R.array.main_titles_arrays);
        mTabHost = (MyFragmentTabHost) findViewById(R.id.mytabhost);
        mTabHost.setup(this, getSupportFragmentManager(), R.id.realtabcontent);
        if (android.os.Build.VERSION.SDK_INT > 10) {
            mTabHost.getTabWidget().setShowDividers(0);
        }

        initTabs();

        mTabHost.setCurrentTab(0);
        mTabHost.setOnTabChangedListener(this);
    }

    private void initTabs() {
        MainTab[] tabs = MainTab.values();
        int size = tabs.length;
        for (int i = 0; i < size; i++) {
            MainTab mainTab = tabs[i];
            TabHost.TabSpec tab = mTabHost.newTabSpec(getString(mainTab.getResName()) + this.toString());
            View indicator = View.inflate(this, R.layout.tab_indicator, null);
            TextView title = (TextView) indicator.findViewById(R.id.tab_title);
            ImageView icon = (ImageView) indicator.findViewById(R.id.iv_user_flow_icon);

            Drawable drawable = this.getResources().getDrawable(mainTab.getResIcon());
            icon.setImageDrawable(drawable);

            title.setText(getString(mainTab.getResName()));
            tab.setIndicator(indicator);
            mTabHost.addTab(tab, mainTab.getClz(), null);
            mTabHost.getTabWidget().getChildAt(i).setOnTouchListener(this);
        }
    }

    @Override
    public void onTabChanged(String s) {
        final int size = mTabHost.getTabWidget().getTabCount();
        for (int i = 0; i < size; i++) {
            View v = mTabHost.getTabWidget().getChildAt(i);
            if (i == mTabHost.getCurrentTab()) {
                v.setSelected(true);
                mTitle = mTitles[i == 3 ? i - 1 : i];
            } else {
                v.setSelected(false);
            }
        }
        supportInvalidateOptionsMenu();
    }

    @Override
    public boolean onTouch(View view, MotionEvent motionEvent) {
        super.onTouchEvent(motionEvent);
        boolean consumed = false;
        if (motionEvent.getAction() == MotionEvent.ACTION_DOWN
                && view.equals(mTabHost.getCurrentTabView())) {
            Fragment currentFragment = getCurrentFragment();
            if (currentFragment != null
                    && currentFragment instanceof OnTabReselectListener) {
                OnTabReselectListener listener = (OnTabReselectListener) currentFragment;
                listener.onTabReselect();
                consumed = true;
            }
        }
        return consumed;
    }

    private Fragment getCurrentFragment() {
        return getSupportFragmentManager().findFragmentByTag(
                mTabHost.getCurrentTabTag());
    }

}

frtabhost—>MainTab .java

public enum MainTab {

    NEWS(0, R.string.main_tab_name_explore, R.drawable.radio_homepage,
            FirstFragment.class),

    TWEET(1, R.string.main_tab_name_tweet, R.drawable.radio_ordersearch,
            SecondFragment.class),

    QUICK(2, R.string.main_tab_name_quick, R.drawable.radio_personal,
            ThirdFragment.class),

    EXPLORE(3, R.string.main_tab_name_my, R.drawable.radio_my,
            FourthFragment.class);

    private int idx;
    private int resName;
    private int resIcon;
    private Class<?> clz;

    private MainTab(int idx, int resName, int resIcon, Class<?> clz) {
        this.idx = idx;
        this.resName = resName;
        this.resIcon = resIcon;
        this.clz = clz;
    }

    public int getIdx() {
        return idx;
    }

    public void setIdx(int idx) {
        this.idx = idx;
    }

    public int getResName() {
        return resName;
    }

    public void setResName(int resName) {
        this.resName = resName;
    }

    public int getResIcon() {
        return resIcon;
    }

    public void setResIcon(int resIcon) {
        this.resIcon = resIcon;
    }

    public Class<?> getClz() {
        return clz;
    }

    public void setClz(Class<?> clz) {
        this.clz = clz;
    }
}

frtabhost—>MyFragmentTabHost .java

public class MyFragmentTabHost extends FragmentTabHost {

    private String mCurrentTag;

    private String mNoTabChangedTag;

    public MyFragmentTabHost(Context context, AttributeSet attrs) {
        super(context, attrs);
    }

    @Override
    public void onTabChanged(String tag) {
        if (tag.equals(mNoTabChangedTag)) {
            setCurrentTabByTag(mCurrentTag);
        } else {
            super.onTabChanged(tag);
            mCurrentTag = tag;
        }
    }

    public void setNoTabChangedTag(String tag) {
        this.mNoTabChangedTag = tag;
    }
}

至此,我们的第二中方式就已经实现了。

下面介绍第三种实现方式,使用TabLayout实现,对Tablayout不是很熟悉的朋友,可以去看看这篇文章:《TabLayout两种添加tab方式,结合ViewPager+Fragment实现常见界面视图》。

tablayout—>TabLayoutStyleAct.java代码

public class TabLayoutStyleAct extends FragmentActivity {

    private TabLayout mTabLayout;
    private int[] tabNames = {R.string.main_tab_name_explore, R.string.main_tab_name_tweet, R.string.main_tab_name_quick, R.string.main_tab_name_my};
    private int[] tabIcons = {R.drawable.radio_homepage, R.drawable.radio_ordersearch, R.drawable.radio_personal, R.drawable.radio_my};

    private FrameLayout container;
    private MyFragmentPagerAdaper adapter;

    @Override
    protected void onCreate(@Nullable Bundle savedInstanceState) {
        super.onCreate(savedInstanceState);
        View view = inflate(this, R.layout.activity_tablayout, null);
        setContentView(view);

        mTabLayout = (TabLayout) findViewById(R.id.tab_tablayout);

        for (int i = 0; i < tabNames.length; i++) {
            View tabView = view.inflate(this, R.layout.tab_indicator, null);
            TextView textView = (TextView) tabView.findViewById(R.id.tab_title);
            textView.setText(tabNames[i]);
            // 利用这种办法设置图标是为了解决默认设置图标和文字出现的距离较大问题
            textView.setCompoundDrawablesWithIntrinsicBounds(0, tabIcons[i], 0, 0);
            mTabLayout.addTab(mTabLayout.newTab().setCustomView(textView));
        }

        container = (FrameLayout) findViewById(R.id.fl_contains);
        adapter = new MyFragmentPagerAdaper(getSupportFragmentManager());

        // 初始化默认显示的fragment
        Fragment fragment = (Fragment) adapter.instantiateItem(container, 0);
        adapter.setPrimaryItem(container, 0, fragment);
        adapter.finishUpdate(container);
        adapter.destroyItem(container, 0, fragment);

        // Tablayout选择tab监听
        mTabLayout.addOnTabSelectedListener(new TabLayout.OnTabSelectedListener() {
            @Override
            public void onTabSelected(TabLayout.Tab tab) {
                int position = mTabLayout.getSelectedTabPosition();//tab.getPosition();
                Fragment fragment = (Fragment) adapter.instantiateItem(container, position);
                adapter.setPrimaryItem(container, position, fragment);
                adapter.finishUpdate(container);
                adapter.destroyItem(container, position, fragment);
            }

            @Override
            public void onTabUnselected(TabLayout.Tab tab) {

            }

            @Override
            public void onTabReselected(TabLayout.Tab tab) {

            }
        });
    }
}

说明:如果会使用TabLayout的朋友知道,一般我们会将TabLayout结合fragment使用时,不是TabLayout在底部的。这里就把TabLayou巧用了,放在了APP的底部,作为切换tab使用,很灵活。

不知道大家有没有注意到,现在实现的这个有没有很眼熟呢?

《Android App之底部tab导航常用实现方案总结》 AppBottomTab项目底部截图.png

没错,就是我们的简书底部tab,关于APP底部tab添加item会在我的个人微信公众号上面发出,关注获取demo。

《Android App之底部tab导航常用实现方案总结》 个人微信公众号.jpg

注:个人创建了简书专题——《Android开发资源经验分享》,欢迎投稿,共同学习。

点赞