美文网首页优秀案例
BottomNavigationView 使用和去除动画,以及解

BottomNavigationView 使用和去除动画,以及解

作者: wuchao226 | 来源:发表于2019-02-25 11:20 被阅读1次

BottomNotificationView 是用来实现底部导航的功能,item 超过3时会有偏移动画且选中时文字才会显示。

新版的 BottomNotificationView 有两个属性可以解决这个问题(网上通过反射的解决方案在这个新版本无效,因为此版本BottomNavigationView底层源码修改了)

1、引入依赖
implementation 'com.android.support:design:28.0.0'
2、设置下面两个属性解决上面的问题
app:itemHorizontalTranslationEnabled="false"
app:labelVisibilityMode="labeled"

app:itemHorizontalTranslationEnabled="false" 禁止item水平平移动画效果。

对应的的方法
是setItemHorizontalTranslationEnabled(false)

app:labelVisibilityMode="labeled" 设置图标下面的文字显示,该属性对应的值有auto、labeled、selected、unlabeled

auto 当item小于等于3是,显示文字,item大于3个默认不显示,选中显示文字
labeled 始终显示文字
selected 选中时显示
unlabeled 不显示文字

该属性对应的方法是setLabelVisibilityMode(LabelVisibilityMode.LABEL_VISIBILITY_LABELED)

3、创建导航navigation_items.xml
<?xml version="1.0" encoding="utf-8"?>
<menu xmlns:android="http://schemas.android.com/apk/res/android"
      xmlns:app="http://schemas.android.com/apk/res-auto">

    <item
        android:id="@+id/nav_bar_home"
        android:icon="@drawable/btn_nav_home_press"
        android:title="@string/nav_bar_home"
        app:showAsAction="ifRoom"/>
    <item
        android:id="@+id/nav_bar_score"
        android:icon="@drawable/btn_nav_score_normal"
        android:title="@string/nav_bar_score"
        app:showAsAction="ifRoom"/>
    <item
        android:id="@+id/nav_bar_user"
        android:icon="@drawable/btn_nav_user_normal"
        android:title="@string/nav_bar_user"
        app:showAsAction="ifRoom"/>
</menu>
4、BottomNavigationView 布局文件
<?xml version="1.0" encoding="utf-8"?>
<android.support.v7.widget.LinearLayoutCompat
    xmlns:android="http://schemas.android.com/apk/res/android"
    xmlns:app="http://schemas.android.com/apk/res-auto"
    xmlns:tools="http://schemas.android.com/tools"
    style="@style/MatchMatch.Vertical">

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

    <android.support.design.widget.BottomNavigationView
        android:id="@+id/navigation"
        android:layout_width="match_parent"
        android:layout_height="56dp"
        android:background="@color/common_white"
        android:elevation="4dp"
        android:outlineProvider="bounds"
        android:translationZ="8dp"
        app:itemHorizontalTranslationEnabled="false"
        app:itemIconTint="@color/select_item_color"
        app:itemTextColor="@color/select_item_color"
        app:labelVisibilityMode="unlabeled"
        app:menu="@menu/navigation_items"
        tools:targetApi="lollipop"/>
</android.support.v7.widget.LinearLayoutCompat>

//select_item_color.xml
<?xml version="1.0" encoding="utf-8"?>
<selector xmlns:android="http://schemas.android.com/apk/res/android">
    <item android:color="@color/common_orange" android:state_checked="true"/>
    <item android:color="@color/text_normal"/>
</selector>
5、解决对Fragment的调度与重用问题,达到最优的Fragment切换的工具类封装 NavHelper.class
/**
 * @desciption: 解决对Fragment的调度与重用问题,达到最优的Fragment切换
 */
public class NavHelper<T> {
    /**
     * 所有Tab集合
     */
    private final SparseArray<Tab<T>> tabs = new SparseArray<>();

    /** 用于初始化的必须参数*/
    private final Context mContext;
    private final int mContainerId;
    private final FragmentManager mFragmentManager;
    private final OnTabChangedListener<T> mListener;
    /**
     * 当前的一个选中的Tab
     */
    private Tab<T> mCurrentTab;

    public NavHelper(Context context, int containerId,
                     FragmentManager fragmentManager, OnTabChangedListener<T> listener) {
        mListener = listener;
        mContext = context;
        mContainerId = containerId;
        mFragmentManager = fragmentManager;
    }

    /**
     * 添加tab
     *
     * @param menuId Tab对应的菜单Id
     * @param tab    Tab
     */
    public NavHelper<T> add(int menuId, Tab<T> tab) {
        tabs.put(menuId, tab);
        return this;
    }

    /**
     * 执行点击菜单的操作
     *
     * @param menuId 菜单的Id
     * @return 是否能够处理这个点击
     */
    public boolean performClickMenu(int menuId) {
        // 集合中寻找点击的菜单对应的Tab,
        // 如果有则进行处理
        Tab<T> tab = tabs.get(menuId);
        if (tab != null) {
            doSelect(tab);
            return true;
        }
        return false;
    }

    /**
     * 进行真实的Tab选择操作
     *
     * @param tab tab
     */
    private void doSelect(Tab<T> tab) {
        Tab<T> oldTab = null;
        if (mCurrentTab != null) {
            oldTab = mCurrentTab;
            if (oldTab == tab) {
                // 如果说当前的Tab就是点击的Tab,
                // 那么我们不做处理
                notifyTabReselect(tab);
                return;
            }
        }
        // 赋值并调用切换方法
        mCurrentTab = tab;
        doTabChanged(mCurrentTab, oldTab);
    }

    private void notifyTabReselect(Tab<T> tab) {
        // TODO 二次点击Tab所做的操作
    }

    /**
     * 进行Fragment的真实的调度操作
     *
     * @param newTab 新的
     * @param oldTab 旧的
     */
    private void doTabChanged(Tab<T> newTab, Tab<T> oldTab) {
        FragmentTransaction ft = mFragmentManager.beginTransaction();
        if (oldTab != null) {
            if (oldTab.fragment != null) {
                // 从界面移除,但是还在Fragment的缓存空间中
                ft.detach(oldTab.fragment);
            }
        }
        if (newTab != null) {
            if (newTab.fragment == null) {
                //首次新建
                Fragment fragment = Fragment.instantiate(mContext, newTab.clx.getName());
                // 缓存起来
                newTab.fragment = fragment;
                // 提交到FragmentManger
                ft.add(mContainerId, fragment, newTab.clx.getName());
            } else {
                // 从FragmentManger的缓存空间中重新加载到界面中
                ft.attach(newTab.fragment);
            }
        }
        // 提交事务
        ft.commit();
        //通知回调
        notifyTabSelect(newTab, oldTab);
    }

    /**
     * 回调我们的监听器
     *
     * @param newTab 新的Tab<T>
     * @param oldTab 旧的Tab<T>
     */
    private void notifyTabSelect(Tab<T> newTab, Tab<T> oldTab) {
        if (mListener != null) {
            mListener.onTabChanged(newTab, oldTab);
        }
    }

    /**
     * 获取当前的显示的Tab
     *
     * @return 当前的Tab
     */
    public Tab<T> getCurrentTab() {
        return mCurrentTab;
    }

    /**
     * 定义事件处理完成后的回调接口
     *
     * @param <T>
     */
    public interface OnTabChangedListener<T> {
        /**
         * 回调接口
         *
         * @param newTab newTab
         * @param oldTab oldTab
         */
        void onTabChanged(Tab<T> newTab, Tab<T> oldTab);
    }

    /**
     * 所有的Tab基础属性
     *
     * @param <T> 泛型的额外参数
     */
    public static class Tab<T> {
        /**
         * Fragment所对应的class值
         */
        public Class<?> clx;
        /**
         * 额外的字段,用户自己设定需要使用
         */
        public T extra;
        /**
         * 内部缓存的对应的Fragment,Package权限,外部无法使用
         */
        Fragment fragment;

        public Tab(Class<?> clx, T extra) {
            this.clx = clx;
            this.extra = extra;
        }
    }
}
6、在Activity中的使用
public class MainActivity extends BaseActivity implements BottomNavigationView.OnNavigationItemSelectedListener,
        NavHelper.OnTabChangedListener<Integer> {

    private BottomNavigationView mNavigation;
    private FragmentManager mFragmentManager;
    private long pressTime = 0;
    private NavHelper<Integer> mNavHelper;

    @Override
    protected int setLayoutId() {
        return R.layout.activity_main;
    }

    @Override
    protected void onBindView(Bundle savedInstanceState) {
        initView();
    }

    private void initView() {
        mNavigation = findViewById(R.id.navigation);
        mFragmentManager = getSupportFragmentManager();
        mNavHelper = new NavHelper<>(this, R.id.bottom_nav_bar_content,
                mFragmentManager, this);
        mNavHelper.add(R.id.nav_bar_home, new NavHelper.Tab<Integer>(HomeFragment.class, R.string.nav_bar_home))
                .add(R.id.nav_bar_score, new NavHelper.Tab<Integer>(IntegralMallFragment.class, R.string.nav_bar_home))
                .add(R.id.nav_bar_user, new NavHelper.Tab<Integer>(PersonalCenterFragment.class, R.string.nav_bar_home));

        // 添加对底部按钮点击的监听
        mNavigation.setOnNavigationItemSelectedListener(this);

        // 从底部导中接管我们的Menu,然后进行手动的触发第一次点击
        Menu menu = mNavigation.getMenu();
        // 触发首次选中Home
        menu.performIdentifierAction(R.id.nav_bar_home, 0);
    }

    @Override
    public void onBackPressed() {
        if (System.currentTimeMillis() - pressTime > 2000) {
            pressTime = System.currentTimeMillis();
            ToastUtils.showShort("再按一次退出程序");
        } else {
            AppActivityManager.getInstance().exitApp(this);
        }
    }

    @Override
    public boolean onNavigationItemSelected(@NonNull MenuItem menuItem) {
        // 转接事件流到工具类中
        return mNavHelper.performClickMenu(menuItem.getItemId());
    }

    /**
     * NavHelper 处理后回调的方法
     *
     * @param newTab 新的Tab
     * @param oldTab 就的Tab
     */
    @Override
    public void onTabChanged(NavHelper.Tab newTab, NavHelper.Tab oldTab) {

    }
}

相关文章

网友评论

    本文标题:BottomNavigationView 使用和去除动画,以及解

    本文链接:https://www.haomeiwen.com/subject/xyewyqtx.html