实现底部导航页面的几种方法

版权声明:本文为博主原创文章,未经博主允许不得转载。 https://blog.csdn.net/weixin_38703938/article/details/80231045

这种底部导航页面在我们使用的APP中使用的非常多,这里正好在项目中又看到,总结一波。

RadioGroup + FrameLayout

先上效果图


实现方法

1.布局文件

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

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


    <RadioGroup
        android:id="@+id/rg_main_bottom"
        android:layout_width="match_parent"
        android:layout_height="wrap_content"
        android:background="@drawable/et_issued_invoice_shape"
        android:orientation="horizontal">

        <RadioButton
            android:id="@+id/main_rg_bottom_home_page"
            style="@style/RadioButtonStyle"
            android:checked="true"
            android:drawableTop="@drawable/rb_main_home_page_selector"
            android:text="首页"
            android:textColor="@drawable/main_tab_text" />

        <RadioButton
            android:id="@+id/main_rg_bottom_my"
            style="@style/RadioButtonStyle"
            android:drawableTop="@drawable/rb_main_my_selector"
            android:text="我的"
            android:textColor="@drawable/main_tab_text" />
    </RadioGroup>


</LinearLayout>

对应图片可以加我的群要原图,当然你也可以用其他图代替,这不是重点。

核心代码

package learn.yfg.com.dbdhtest;

import android.app.Activity;
import android.os.Bundle;
import android.support.annotation.Nullable;
import android.support.v4.app.Fragment;
import android.support.v4.app.FragmentManager;
import android.support.v4.app.FragmentTransaction;
import android.support.v7.app.AppCompatActivity;
import android.view.View;
import android.view.ViewGroup;
import android.widget.FrameLayout;
import android.widget.RadioButton;
import android.widget.RadioGroup;

import java.util.ArrayList;
import java.util.List;

import butterknife.BindView;
import butterknife.ButterKnife;
import learn.yfg.com.dbdhtest.fragment.HomePageSimpleFragnment;
import learn.yfg.com.dbdhtest.fragment.MySimpleFragment;

/**
 * @author 酥小鱼
 * @name PersonalProject
 * @class name:learn.yfg.com.dbdhtest
 * @class describe
 * @time 2018/5/7 20:45
 * @change
 */

public class RFActivity extends AppCompatActivity implements View.OnClickListener {
    @BindView(R.id.fl_main_container)
    FrameLayout flMainContainer;
    @BindView(R.id.main_rg_bottom_home_page)
    RadioButton mainRgBottomHomePage;
    @BindView(R.id.main_rg_bottom_my)
    RadioButton mainRgBottomMy;
    @BindView(R.id.rg_main_bottom)
    RadioGroup rgMainBottom;
    List<Fragment> fragmentList = new ArrayList<>();
    Fragment fragment1;
    Fragment fragment2;

    @Override
    protected void onCreate(@Nullable Bundle savedInstanceState) {
        super.onCreate(savedInstanceState);
        setContentView(R.layout.activity_rf);
        ButterKnife.bind(this);
        fragment1 = new HomePageSimpleFragnment();
        fragment2 = new MySimpleFragment();

        //设置RadioGroup开始时设置的按钮,设置第一个按钮为默认值
        rgMainBottom.check(R.id.main_rg_bottom_home_page);

        mainRgBottomHomePage.setOnClickListener(this);
        mainRgBottomMy.setOnClickListener(this);
//初始时向容器中添加第一个Fragment对象
        addFragment(fragment1);

        //fragmentList.add(new ShopMallFragment());
//        fragmentList.add(new HomePageSimpleFragnment());
//        fragmentList.add(new MySimpleFragment());
//
//        new FragmentTabUtils(getSupportFragmentManager(), fragmentList, R.id.fl_main_container,
//                rgMainBottom);
    }

    //向Activity中添加Fragment的方法
    public void addFragment(Fragment fragment) {

        //获得Fragment管理器
        FragmentManager fragmentManager = getSupportFragmentManager();
        //使用管理器开启事务
        FragmentTransaction fragmentTransaction = fragmentManager.beginTransaction();
        //使用事务替换Fragment容器中Fragment对象
        fragmentTransaction.replace(R.id.fl_main_container, fragment);
        //提交事务,否则事务不生效
        fragmentTransaction.commit();
    }

    @Override
    public void onClick(View v) {
        switch (v.getId()) {
            case R.id.main_rg_bottom_home_page:
                addFragment(fragment1);
                break;
            case R.id.main_rg_bottom_my:
                addFragment(fragment2);
                break;
            default:
                break;
        }
    }
}

实现思路:初始默认显示一个fragment,然后给radiobutton设置点击,跳转不同的fragment,实现底部导航。

这是我自己实现的思路,有心细的会发现我注释掉了几行代码,这是一个工具类,用来实现跳转的,下面贴出这个工具类和简单分析一下。

package learn.yfg.com.dbdhtest;

import android.os.SystemClock;
import android.support.v4.app.Fragment;
import android.support.v4.app.FragmentManager;
import android.support.v4.app.FragmentTransaction;
import android.widget.RadioButton;
import android.widget.RadioGroup;

import java.util.List;

public class FragmentTabUtils implements RadioGroup.OnCheckedChangeListener {
    public static final int MIN_CLICK_DELAY_TIME = 100;
    private static Fragment mFragment;
    private long lastClickTime = 0;
    private FragmentManager manager;
    private List<Fragment> fragments;
    private int fragmentContainerId;
    private RadioGroup radioGroup;

    public FragmentTabUtils(FragmentManager manager, List<Fragment> fragments,
                            int fragmentContainerId, RadioGroup radioGroup) {
        this.manager = manager;
        this.fragments = fragments;
        this.fragmentContainerId = fragmentContainerId;
        this.radioGroup = radioGroup;
        radioGroup.setOnCheckedChangeListener(this);
        ((RadioButton) radioGroup.getChildAt(0)).setChecked(true);
        showFragment(fragments.get(0));
    }

    private void showFragment(Fragment to) {
        if (mFragment == null) {
            mFragment = fragments.get(0);
        }
        FragmentTransaction transaction = manager.beginTransaction();
        if (to.isAdded()) {
            transaction.replace(fragmentContainerId, to);
        } else {
            transaction.replace(fragmentContainerId, to);
        }
        transaction.commitAllowingStateLoss();
        mFragment = to;
    }


    @Override
    public void onCheckedChanged(RadioGroup group, int checkedId) {
        for (int i = 0; i < group.getChildCount(); i++) {
            if (group.getChildAt(i).getId() == checkedId) {
                long currentTime = SystemClock.elapsedRealtime();
                if (currentTime - lastClickTime > MIN_CLICK_DELAY_TIME) {
                    lastClickTime = currentTime;
                    showFragment(fragments.get(i));
                }
            }
        }
    }
}

1.构造器:传入的是fragment管理实例,与radiogroup对应的fragment的list,FrameLayout的id,radiogroup实例;设置了radiogroup的改变事件,radiogroup的默认值和FrameLayout的默认页面。

2.show方法:由列表中取出,记住前面的判空处理,否则会出现空指针异常。

3.change方法:设置了radiogroup的button变换与list对应取值,这里面加了个时间判断,加了一定的延迟,是为了防止过快点击造成的异常。

FlycoTabLayout + ViewPager

这是一个开源项目与Android原生控件的结合,所以你可以先去了解一下这个开源项目,我是参考这篇文章的。

实现方法

1.添加依赖:

    compile 'com.flyco.tablayout:FlycoTabLayout_Lib:2.1.0@aar'

2.布局文件

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

    <learn.yfg.com.dbdhtest.CatchableViewPager
        android:id="@+id/vp_content"
        android:layout_width="match_parent"
        android:layout_height="match_parent"
        android:layout_above="@+id/tab">
    </learn.yfg.com.dbdhtest.CatchableViewPager>

    <com.flyco.tablayout.CommonTabLayout
        android:id="@+id/tab"
        android:layout_alignParentBottom="true"
        android:layout_width="match_parent"
        android:layout_height="wrap_content"
        android:paddingTop="7dp"
        android:paddingBottom="7dp"
        android:background="#ffffff"
        app:tl_iconGravity="TOP"
        app:tl_iconHeight="24dp"
        app:tl_iconWidth="24dp"
        app:tl_divider_color="#00FFFFFF"
        app:tl_divider_padding="0dp"
        app:tl_divider_width="0dp"
        app:tl_indicator_bounce_enable="false"
        app:tl_indicator_color="#2C97DE"
        app:tl_indicator_gravity="TOP"
        app:tl_indicator_height="0dp"
        app:tl_indicator_width_equal_title="true"
        app:tl_tab_padding="3dp"
        app:tl_tab_space_equal="true"
        app:tl_textSelectColor="#2fa8fc"
        app:tl_textUnselectColor="#666"
        app:tl_textsize="15sp"
        app:tl_underline_height="0dp"/>

</RelativeLayout>

这里我们对viewpager进行了自定义控件,这里为什么要进行封装,而不使用原生的呢?主要是因为viewpage可以实现左右滑动,而我们希望上面的滑动和底部进行同步,这就涉及到滑动事件和点击事件的分发和拦截,这个说起来就有点麻烦了,我会有相应的博客来讲解的,留眼。

3.自定义的viewpager

package learn.yfg.com.dbdhtest;

import android.content.Context;
import android.support.v4.view.ViewPager;
import android.util.AttributeSet;
import android.view.MotionEvent;

/**
 * Created by 酥小鱼 on 2018/5/23
 * catch exception: Android java.lang.IllegalArgumentException: pointerIndex out of range
 */
public class CatchableViewPager extends ViewPager {
    private boolean isScroll = true;

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

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


    public void isScroll(boolean isScroll) {
        this.isScroll = isScroll;
    }

    @Override
    public boolean onInterceptTouchEvent(MotionEvent ev) {
        if (!isScroll) {
            return false;
        }
        try {
            return super.onInterceptTouchEvent(ev);
        } catch (IllegalArgumentException ex) {
        }
        return false;
    }


    @Override
    public boolean onTouchEvent(MotionEvent ev) {
        if (!isScroll) {
            return false;
        }
        try {
            return super.onTouchEvent(ev);
        } catch (IllegalArgumentException ex) {

        }

        return false;
    }
}

这里主要对滑动进行了处理,不多说,留坑。

4.核心代码

package learn.yfg.com.dbdhtest;

import android.os.Bundle;
import android.support.v4.app.Fragment;
import android.support.v4.app.FragmentManager;
import android.support.v4.app.FragmentPagerAdapter;
import android.support.v4.view.ViewPager;
import android.support.v7.app.AppCompatActivity;

import com.flyco.tablayout.CommonTabLayout;
import com.flyco.tablayout.listener.CustomTabEntity;
import com.flyco.tablayout.listener.OnTabSelectListener;

import java.util.ArrayList;
import java.util.List;

import butterknife.BindView;
import butterknife.ButterKnife;
import learn.yfg.com.dbdhtest.fragment.HomePageSimpleFragnment;
import learn.yfg.com.dbdhtest.fragment.MySimpleFragment;

public class FlycoTabLayoutActivity extends AppCompatActivity {

    @BindView(R.id.vp_content)
    CatchableViewPager mViewPager;
    @BindView(R.id.tab)
    CommonTabLayout mTabLayout;
    /*文本信息*/
    private String[] mTitles = {"首页", "我的"};
    /*未选择时的icon*/
    private int[] mIconSelectIds  = {
            R.mipmap.homeon, R.mipmap.personalcenteron};
    /*选择时的icon*/
    private int[] mIconUnSelectIds = {
            R.mipmap.home, R.mipmap.personalcenter};
    private ArrayList<CustomTabEntity> mTabEntities = new ArrayList<>();
    private List<Fragment> mFragments;

    @Override
    protected void onCreate(Bundle savedInstanceState) {
        super.onCreate(savedInstanceState);
        setContentView(R.layout.activity_flyco_tab_layout);
        ButterKnife.bind(this);
        initView();
    }

    private void initView() {
        mFragments = new ArrayList<Fragment>() {
            {
                add(new HomePageSimpleFragnment());
                add(new MySimpleFragment());
            }
        };
        /*添加数据集*/
        for (int i = 0; i < mTitles.length; i++) {
            mTabEntities.add(new TabEntity(mTitles[i], mIconSelectIds[i], mIconUnSelectIds[i]));
        }
        //设置fragment与底部联动
        mViewPager.setAdapter(new MainPagerAdapter(getSupportFragmentManager()));
        mTabLayout.setTabData(mTabEntities);
        /*选择事件*/
        mTabLayout.setOnTabSelectListener(new OnTabSelectListener() {
            @Override
            public void onTabSelect(int position) {
                mViewPager.setCurrentItem(position);
            }

            @Override
            public void onTabReselect(int position) {
            }
        });

        mViewPager.addOnPageChangeListener(new ViewPager.OnPageChangeListener() {
            @Override
            public void onPageScrolled(int position, float positionOffset, int positionOffsetPixels) {
            }
            @Override
            public void onPageSelected(int position) {
                mTabLayout.setCurrentTab(position);
                if (position == 0){
                }else  if (position == 1){

                }
            }
            @Override
            public void onPageScrollStateChanged(int state) {
            }
        });
        mViewPager.setCurrentItem(0);
    }
    /**
     *
     * ViewPager适配器
     * */
    private class MainPagerAdapter extends FragmentPagerAdapter {
        public MainPagerAdapter(FragmentManager fm) {
            super(fm);
        }

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

        @Override
        public CharSequence getPageTitle(int position) {
            return mTitles[position];
        }

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

实现思路:首先准备需要的资源,然后设置viewpager与fragment联动,底部与fragment的联动。

具体分析下:这里面我定义了一个bean,用来传递底部的标题和选中未选中的资源文件,我们可以发现定义的时候和我们使用的一个是实体类,一个是接口,这地方我并没有理解,如果有懂的,欢迎告诉我。下面的适配器和和选择事件没什么可说的,只要注意设一个初值,避免空指针。



猜你喜欢

转载自blog.csdn.net/weixin_38703938/article/details/80231045