开发流程之五:TabBar切换应用主页面

引言:
当我们的启动页、引导页、网络请求管理类和用户管理类都一步步完善好之后,就要开始实现整个应用的界面了,根据主流应用和多数用户的习惯。首页(主页面)一般都是有底部导航栏的,根据所点击的导航栏中不同的按钮,完成对应的Fragment的切换是主流的做法。
效果如下,上方是ViewPager中的“日更”Fragment,底下一排就是用来切换不同Fragment的TabBar的按钮:

image.png

首先整理一下思路:

整个布局在一个Activity中,上方是一个ViewPager,底部是一个TabBar。通过点击TabBar中的不同按钮,实现ViewPager中不同的Fragment之间的切换,从而实现该功能。这里的底部TabBar可以自己写,也可以用第三方的,这里采用第三方。

实现:

步骤一、
引入依赖:
compile 'me.majiajie:pager-bottom-tab-strip:2.2.4'

步骤二、
主页面:

  1. xml布局:
    其中 NoScrollMainViewpage是继承自ViewPager的自定义控件,其作用是使ViewPager不滑动,可先直接复制下来放入项目中备用(后面有源代码)。
    PageNavigationView为第三方的TabBar切换工具。
<RelativeLayout                       
    xmlns:android="http://schemas.android.com/apk/res/android"
    android:layout_width="match_parent"
    android:layout_height="match_parent"
    android:clipToPadding="false"
    android:fitsSystemWindows="true">

    <!--首页ViewPager,不可左右滑动的VP,-->
    <com.smartlib.cmnObject.ui.NoScrollMainViewpage
        android:id="@+id/vp_main_home"
        android:background="@color/white"
        android:layout_above="@+id/ll_bottom_tab_bar"
        android:layout_below="@id/rl_main_navigation"
        android:layout_width="match_parent"
        android:layout_height="match_parent">
    </com.smartlib.cmnObject.ui.NoScrollMainViewpage>
   
    <LinearLayout
        android:id="@+id/ll_bottom_tab_bar"
        android:orientation="vertical"
        android:layout_alignParentBottom="true"
        android:layout_width="match_parent"
        android:layout_height="49.5dp">

        <!--用于底部切换的TabBar-->
        <me.majiajie.pagerbottomtabstrip.PageNavigationView
            android:id="@+id/tab_bar"
            android:background="@color/transparent"
            android:layout_width="match_parent"
            android:layout_height="49dp">
       </me.majiajie.pagerbottomtabstrip.PageNavigationView>

    </LinearLayout>

</RelativeLayout>

NoScrollMainViewpage源代码如下,直接复制到项目中:

/**
 * 不可以滑动的viewpager
 */
public class NoScrollMainViewpage extends ViewPager {
    private boolean noScroll = false;
    /**
    * 上一次x坐标
    */
    private float beforeX;
    private int xDown, xUp, yDown, yUp;

    private int pageIndex;
    private OnTouchListener onTouchListener;

    public void setIndex(int index) {
        this.pageIndex = index;
    }

    public NoScrollMainViewpage(Context context, AttributeSet attrs) {
        super(context, attrs);
        // TODO Auto-generated constructor stub
    }

    public NoScrollMainViewpage(Context context) {
        super(context);
    }

    public void setNoScroll(boolean noScroll) {
        this.noScroll = noScroll;
    }

    @Override
    public void scrollTo(int x, int y) {
        super.scrollTo(x, y);
    }

    @Override
    public boolean onTouchEvent(MotionEvent event) {
        if (noScroll)
            return false;
        else
            return super.onTouchEvent(event);
    }

    @Override
    public boolean dispatchTouchEvent(MotionEvent ev) {
        int index = getCurrentItem();
        if (noScroll) {
            return super.dispatchTouchEvent(ev);
        } else {
            switch (ev.getAction()) {
                case MotionEvent.ACTION_DOWN://按下如果‘仅’作为‘上次坐标’,不妥,因为可能存在左滑,motionValue大于0的情况(来回滑,只要停止坐标在按下坐标的右边,左滑仍然能滑过去)
                    beforeX = ev.getX();
                    break;
                case MotionEvent.ACTION_MOVE:
                    float motionValue = ev.getX() - beforeX;
                    if (motionValue > 0 && index == 1 && pageIndex == 0) {//禁止左滑
                        return true;
                    }
                    beforeX = ev.getX();//手指移动时,再把当前的坐标作为下一次的‘上次坐标’,解决上述问题
                    break;
                case MotionEvent.ACTION_UP:
                    break;
                default:
                    break;
            }
            if (onTouchListener != null) {
                onTouchListener.onTouch(this, ev);
            }
            return super.dispatchTouchEvent(ev);
        }
    }

    @Override  
    public boolean onInterceptTouchEvent(MotionEvent event) {
        if (noScroll){
            return false;
        } else {
            return super.onInterceptTouchEvent(event);
        }
    }

    @Override
    public void setCurrentItem(int item) {
        super.setCurrentItem(item);
    }

    @Override
    public void setOnTouchListener(OnTouchListener l) {
        super.setOnTouchListener(l);
        onTouchListener = l;
    }
}

主页面的布局到此完成。

  1. Activity中的java代码:
    其中HomeViewPagerAdapter是自定义的适配器(后面有源代码)
/**
 *主页面
 */
public class MainActivity extends AppCompatActivity{
    private NoScrollMainViewpage mViewPager;
    //TabBar的外层容器
    private LinearLayout mBottomTabBarLL;

    //将要在ViewPager中切换的三个Fragment
    private HomeListFragment homeListFragment;//日更
    private CatCircleFragment suckCatFragment;//吸猫
    private MineFragment mineFragment;//我的

    @Override
    protected void onCreate(Bundle savedInstanceState) {
        super.onCreate(savedInstanceState);
        setContentView(R.layout.activity_main);

        initView();
    }


    /**
     * 主页视图初始化
     */
    private void initView() {
        configViewPager();
        configTabBar();
 
        //TabBar的外层容器
        mBottomTabBarLL = (LinearLayout) findViewById(R.id.ll_bottom_tab_bar);
    }
   

    /**
     * 设置VP关联Fragment
     */
    private void configViewPager() {
        mViewPager = (NoScrollMainViewpage) findViewById(R.id.vp_main_home);
        mViewPager.setNoScroll(true);
        List<Fragment> fragmentList = new ArrayList<>();

        homeListFragment = new HomeListFragment();//日更
        suckCatFragment = new CatCircleFragment();//吸猫
        mineFragment = new MineFragment();//我的

        fragmentList.add(homeListFragment);
        fragmentList.add(suckCatFragment);
        fragmentList.add(mineFragment);

        FragmentManager fragmentManager = getSupportFragmentManager();

        //自定义适配器
        HomeViewPagerAdapter viewPagerAdapter = new HomeViewPagerAdapter(fragmentManager, fragmentList);
        mViewPager.setAdapter(viewPagerAdapter);
        mViewPager.setCurrentItem(0);
        mViewPager.setOffscreenPageLimit(2);//预加载2个
    }

    /**
     * 初始化底部导航
     */
    private void configTabBar() {
        PageNavigationView tabBar = (PageNavigationView) findViewById(R.id.tab_bar);
        NavigationController navigationController = tabBar.custom()
            .addItem(createTabBarItem(R.drawable.ic_day_up_date_normal, R.drawable.ic_day_up_date_selected, "日更"))
            .addItem(createTabBarItem(R.drawable.ic_cat_circlr_normal, R.drawable.ic_cat_circle_selected, "吸猫"))
            .addItem(createTabBarItem(R.drawable.ic_mine_normal, R.drawable.ic_mine_selected, "我的"))
            .build();
        navigationController.setupWithViewPager(mViewPager);
        //此方法决定点击按钮切换不同的Fragment 
        navigationController.addTabItemSelectedListener(new OnTabItemSelectedListener() {
            @Override
            public void onSelected(int index, int old) {
                //需要注意的是,本方法可能会对Fragment中的生命周期产生影响,尽量不要在本方法中使用各Fragment的对象去调用其中的方法
                if (index == 0) {
                    //第一个按钮的逻辑
                    xxx.setText("日更");
                } else if (index == 1) {
                    //第二个按钮的逻辑
                    xxx.setText("吸猫");
                } else if (index == 2) {
                   //第三个按钮的逻辑
                    xxx.setText("我的");
                }
            }

            @Override
            public void onRepeat(int index) {
      
            }
        });
    }

    /**
     * tabBar 初始图文及其颜色
     */
    private BaseTabItem createTabBarItem(int normalDrawable, int selectedDrawable, String text) {
        MainTabItemView itemView = new MainTabItemView(this);
        itemView.initialize(normalDrawable, selectedDrawable, text);
        itemView.setTextDefaultColor(getResources().getColor(R.color.color_home_list_bar_normal));
        itemView.setTextCheckedColor(getResources().getColor(R.color.color_home_list_bar_selected));
        return itemView;
    }
}

Activity中的代码到此完成,下面看一下HomeViewPagerAdapter:

3.自定义VP适配器:HomeViewPagerAdapter
代码如下:

/**
  * 主页VP适配器
  * 用来切换页卡中不同Fragment
  */
public class HomeViewPagerAdapter extends FragmentPagerAdapter {

    private FragmentManager fragmentManager;
    private List<Fragment> fragmentList;

    public HomeViewPagerAdapter(FragmentManager fm, List<Fragment> list) {
        super(fm);
        this.fragmentManager = fm;
        this.fragmentList = list;
    }

    @Override
    public Fragment getItem(int position) {
        return fragmentList.get(position);
    }

    @Override
    public int getCount() {
        return fragmentList.size();
    }
}

以上,完成了应用的页面切换功能,该第三方控件还有其他更多的功能,共同学习。
结束。

最后编辑于
©著作权归作者所有,转载或内容合作请联系作者
  • 序言:七十年代末,一起剥皮案震惊了整个滨河市,随后出现的几起案子,更是在滨河造成了极大的恐慌,老刑警刘岩,带你破解...
    沈念sama阅读 194,390评论 5 459
  • 序言:滨河连续发生了三起死亡事件,死亡现场离奇诡异,居然都是意外死亡,警方通过查阅死者的电脑和手机,发现死者居然都...
    沈念sama阅读 81,821评论 2 371
  • 文/潘晓璐 我一进店门,熙熙楼的掌柜王于贵愁眉苦脸地迎上来,“玉大人,你说我怎么就摊上这事。” “怎么了?”我有些...
    开封第一讲书人阅读 141,632评论 0 319
  • 文/不坏的土叔 我叫张陵,是天一观的道长。 经常有香客问我,道长,这世上最难降的妖魔是什么? 我笑而不...
    开封第一讲书人阅读 52,170评论 1 263
  • 正文 为了忘掉前任,我火速办了婚礼,结果婚礼上,老公的妹妹穿的比我还像新娘。我一直安慰自己,他们只是感情好,可当我...
    茶点故事阅读 61,033评论 4 355
  • 文/花漫 我一把揭开白布。 她就那样静静地躺着,像睡着了一般。 火红的嫁衣衬着肌肤如雪。 梳的纹丝不乱的头发上,一...
    开封第一讲书人阅读 46,098评论 1 272
  • 那天,我揣着相机与录音,去河边找鬼。 笑死,一个胖子当着我的面吹牛,可吹牛的内容都是我干的。 我是一名探鬼主播,决...
    沈念sama阅读 36,511评论 3 381
  • 文/苍兰香墨 我猛地睁开眼,长吁一口气:“原来是场噩梦啊……” “哼!你这毒妇竟也来了?” 一声冷哼从身侧响起,我...
    开封第一讲书人阅读 35,204评论 0 253
  • 序言:老挝万荣一对情侣失踪,失踪者是张志新(化名)和其女友刘颖,没想到半个月后,有当地人在树林里发现了一具尸体,经...
    沈念sama阅读 39,479评论 1 290
  • 正文 独居荒郊野岭守林人离奇死亡,尸身上长有42处带血的脓包…… 初始之章·张勋 以下内容为张勋视角 年9月15日...
    茶点故事阅读 34,572评论 2 309
  • 正文 我和宋清朗相恋三年,在试婚纱的时候发现自己被绿了。 大学时的朋友给我发了我未婚夫和他白月光在一起吃饭的照片。...
    茶点故事阅读 36,341评论 1 326
  • 序言:一个原本活蹦乱跳的男人离奇死亡,死状恐怖,灵堂内的尸体忽然破棺而出,到底是诈尸还是另有隐情,我是刑警宁泽,带...
    沈念sama阅读 32,213评论 3 312
  • 正文 年R本政府宣布,位于F岛的核电站,受9级特大地震影响,放射性物质发生泄漏。R本人自食恶果不足惜,却给世界环境...
    茶点故事阅读 37,576评论 3 298
  • 文/蒙蒙 一、第九天 我趴在偏房一处隐蔽的房顶上张望。 院中可真热闹,春花似锦、人声如沸。这庄子的主人今日做“春日...
    开封第一讲书人阅读 28,893评论 0 17
  • 文/苍兰香墨 我抬头看了看天上的太阳。三九已至,却和暖如春,着一层夹袄步出监牢的瞬间,已是汗流浃背。 一阵脚步声响...
    开封第一讲书人阅读 30,171评论 1 250
  • 我被黑心中介骗来泰国打工, 没想到刚下飞机就差点儿被人妖公主榨干…… 1. 我叫王不留,地道东北人。 一个月前我还...
    沈念sama阅读 41,486评论 2 341
  • 正文 我出身青楼,却偏偏与公主长得像,于是被迫代替她去往敌国和亲。 传闻我的和亲对象是个残疾皇子,可洞房花烛夜当晚...
    茶点故事阅读 40,676评论 2 335