炫酷的底部菜单栏BottomBar

开源项目分析BottomBar

今天分析一个炫酷的底部菜单栏开源项目,先说明下用法,再分析一下源码的实现。

GitHub地址

https://github.com/roughike/BottomBar

先上个效果图

使用

添加依赖

compile ‘com.roughike:bottom-bar:1.3.3‘

创建menu资源文件

res/menu/bottombar_menu.xml:

<menu xmlns:android="http://schemas.android.com/apk/res/android">
    <item
        android:id="@+id/bottomBarItemOne"
        android:icon="@drawable/ic_recents"
        android:title="Recents" />
        ...
</menu>

关联Activity

public class MainActivity extends AppCompatActivity {
    private BottomBar mBottomBar;

    @Override
    protected void onCreate(Bundle savedInstanceState) {
        super.onCreate(savedInstanceState);
        setContentView(R.layout.activity_main);
        //关联到当前 activity
        mBottomBar = BottomBar.attach(this, savedInstanceState);
        //从 menu.xml初始化导航栏 并设置监听
        mBottomBar.setItemsFromMenu(R.menu.bottombar_menu, new OnMenuTabClickListener() {
            @Override
            public void onMenuTabSelected(@IdRes int menuItemId) {
                if (resId == R.id.bottomBarItemOne) {
                    //当tab被选中时候触发
                }
            }

            @Override
            public void onMenuTabReSelected(@IdRes int menuItemId) {
                if (resId == R.id.bottomBarItemOne) {
                   //当前选中的 tab 再次被点击时候触发
                }
            }
        });

        //设置导航栏选中时候的颜色 导航>=3的时候有效
        mBottomBar.mapColorForTab(0, ContextCompat.getColor(this, R.color.colorAccent));
        mBottomBar.mapColorForTab(1, 0xFF5D4037);
        mBottomBar.mapColorForTab(2, "#7B1FA2");
    }

    @Override
    protected void onSaveInstanceState(Bundle outState) {
        super.onSaveInstanceState(outState);
        //保存底部导航状态 这一步是必须的
        mBottomBar.onSaveInstanceState(outState);
    }
}

BottomBar其他功能设置

  • 不关联 xml 文件代码创建底部导航选项卡
mBottomBar.setItems(
  new BottomBarTab(R.drawable.ic_recents, "Recents"),
  new BottomBarTab(R.drawable.ic_favorites, "Favorites"),
  new BottomBarTab(R.drawable.ic_nearby, "Nearby")
);
mBottomBar.setOnTabClickListener(linstener);
  • 设置未读消息
//为第一个tab创建一个背景红色内容为13的右上角提醒
BottomBarBadge unreadMessages = mBottomBar.makeBadgeForTabAt(0, "#FF0000", 13);

// 控制提醒显示和隐藏
unreadMessages.show();
unreadMessages.hide();

// 更改提醒数字
unreadMessages.setCount(4);

// 显示和隐藏的动画持续的时间
unreadMessages.setAnimationDuration(200);

//tab 未选中时也显示
unreadMessages.setAutoShowAfterUnSelection(true);
  • 自定义显示效果
// 设置平板显示效果和手机显示效果一致
mBottomBar.noTabletGoodness();

// 当超过3个 tab 的时候设置所有 tab 都固定显示
mBottomBar.useFixedMode();

// 暗色主题
mBottomBar.useDarkTheme();

// 设置 tab使用自定义的 textStyle
mBottomBar.setTextAppearance(R.style.MyTextAppearance);
//TAB使用自定义字体 字体需放在 assets 文件夹下
mBottomBar.setTypeFace("MyFont.ttf");

还有很多其他设置就不一一介绍了,有兴趣的请移驾 ==GitHub项目地址==https://github.com/roughike/BottomBar

原理分析

要分析其原理我们先看下

库项目结构

项目结构如图

  • scrollsweetness下是自定义的CoordinatorLayout.Behavior

    BottomNavigationBehavior继承自VerticalScrollingBehavior 用于实现随页面的滚动隐藏与显示 BottomBar ,至于实现原理关于CoordinatorLayout.Behavior,展开来讲的话又是很大一篇,限于本人能力所限这里就不做深入了。

  • BadgeCircle

    这个比较简单 就一个方法用来生成未读提醒提示的的背景

  • BottomBarBadge

    继承自 TextView 是未读提醒显示所用的的自定义 view,设置显示隐藏的动画

  • BottomBarTab

    BottomBarTab继承自BottomBarItemBase 是存储单个tab属性的实体类

  • 其他类

    MiscUtils是处理动画、颜色、宽高之类的工具类

    剩下的都是一些回掉监听的接口

  • 资源文件

    layout 目录下的 xml 文件分别对应着不同状态的下的布局文件

由项目结构可知大部分内容都在BottomBar这个类中

BottomBar.java

按照使用一步步跟进代码

  • attach(Activity activity, Bundle savedInstanceState)
public static BottomBar attach(Activity activity, Bundle savedInstanceState) {
        BottomBar bottomBar = new BottomBar(activity);
        bottomBar.onRestoreInstanceState(savedInstanceState);

        ViewGroup contentView = (ViewGroup) activity.findViewById(android.R.id.content);
        View oldLayout = contentView.getChildAt(0);
        contentView.removeView(oldLayout);

        bottomBar.setPendingUserContentView(oldLayout);
        contentView.addView(bottomBar, 0);

        return bottomBar;
    }

这个方法其实就做了两件事

第一 实例化bottomBar对象,恢复以前保存的状态

第二 用自定义布局替换掉原本的 contentView 内的内容

activity.setContentView其实就是向系统顶层布局里id为android.R.id.content的Framelayout内添加指定的 view,这里作者做的是将原本用户添加的 oldLayout 从 contentView 内移除,再把这个oldLayout添加到bottomBar的布局中,最后再将bottomBar添加到 contentView 中。

需要注意的是这里是先把oldLayout保存下来

private void setPendingUserContentView(View oldLayout) {
    mPendingUserContentView = oldLayout;
}

在initializeViews()中mPendingUserContentView才会真正被添加到bottomBar的布局中,而initializeViews会在updateItems方法内调用,updateItems则会在绑定menu.xml或添加tab的时候调用。

  • setItemsFromMenu
public void setItemsFromMenu(@MenuRes int menuRes, OnMenuTabClickListener listener) {
        clearItems();
        mItems = MiscUtils.inflateMenuFromResource((Activity) getContext(), menuRes);
        mMenuListener = listener;
        updateItems(mItems);

        if (mItems != null && mItems.length > 0
                && mItems instanceof BottomBarTab[]) {
            listener.onMenuTabSelected(((BottomBarTab) mItems[mCurrentTabPosition]).id);
        }
    }

这个方法的功能也很明确

首先 根据 menu 资源获得 tab 对象列表mItems

然后 绑定监听mMenuListener

最后 设置当前选中的 tab

这个方法中updateItems会被调用 如果mPendingUserContentView未被添加过则会添加到布局中

下面在看看点击事件的执行,由 updateItems 方法可知每个 tab 的 onClick 事件绑定的 listener 即为 BottomBar.this,所以找到 onClick 事件即可,onClick内只是调用了handleClick。

  • handleClick(View v)
    private void handleClick(View v) {
        if (v.getTag().equals(TAG_BOTTOM_BAR_VIEW_INACTIVE)) {
            View oldTab = findViewWithTag(TAG_BOTTOM_BAR_VIEW_ACTIVE);

            unselectTab(oldTab, true);
            selectTab(v, true);

            shiftingMagic(oldTab, v, true);
        }
        updateSelectedTab(findItemPosition(v));
    }

此方法内部的执行也是非常明确,

第一 根据 tag 找到点击事件前选中的 tab,更新 oldtab 和 newtab 的状态

第二 shiftingMagic 更新tab宽度并执行动画效果

第三 updateSelectedTab 更新未读消息提醒的显示并执行用户绑定的监听

至于其他的有兴趣的请自行下载源码分析。

GitHub下载有困难的同学看这里

BottomBar下载地址

这个库代码不是很复杂但思想很值得借鉴,效果也是非常的赞,以后会多找这样效果很赞又不会很复杂的第三方库与大家分享,我也会第一时间更新到我的微信订阅号,欢迎大家关注!

时间: 2024-08-01 21:03:12

炫酷的底部菜单栏BottomBar的相关文章

[Android] BottomBar+ViewPager+Fragment实现炫酷的底部导航效果

BottomBar BottomBar是Github上的一个开源框架,因为从1.3.3开始不支持fragments了,要自己配置,弄了很久,不管是app的fragment还是V4 的程序总是总是闪退.于是就用这种方式实现了,效果还不错.github有详细说明,多余的就不说了. 这个roughike是这个项目的所有者(大神致敬). 我用的是android studio开发,fragment全部导的V4的包(以为最开始就支持的是v4的,后面也支持了app.fragment). 首先是dependen

超炫酷的jQuery轮播焦点图 底部带切换缩略图

详细内容请点击 前面我们刚刚分享过一款jQuery/HTML5响应式焦点图动画应用,效果非常炫酷.这次我们再来分享一款基于jQuery的图片轮播焦点图,这款jQuery焦点图的特点是整个图片播放器是宽屏的效果,并且在焦点图底部有一排可以滑动的缩略图,点击缩略图可以快速跳转到相应的图片.  在线演示源码下载 学习来源:http://www.html5tricks.com/jquery-cool-image-slider-thumb.html 更多html5内容请点击

一款炫酷Loading动画--加载成功

简介 昨天在简书上看到一篇文章,介绍了一个加载动画的实现过程 一款Loading动画的实现思路(一) 只可惜原动画是IOS上制作的,而看了一下,作者的实现思路比较复杂,于是趁着空闲写了一个Android版本,这篇文章将给大家介绍一下实现过程. 首先让我们来看一下动画效果 动画结构分析 从上面的gif图中可以看到,这个加载动画有成功,失败两种状态,由于Gif速度比较快,我们再来分别看一张慢图 1.成功状态加载动画 成功动画的状态转移描述如下: 1.加载过程,画蓝色圆环,当进度为100%时,圆环完成

[智能硬件] 3、三分钟看懂智能硬件原理——简易智能手环制作教程(包括炫酷手机客户端开发)

首先恭喜大家挺过了测试二!为什么说“挺”呢?因为测试二的难度和测试一相比有一个比较大的跳跃:首先测试一仅仅利用现有硬件模块稍加改造而DIY一个蓝牙防丢器,而测试二则要求大家具有从脑袋里的一个想法到一个全新的小设备的实现的全部能力,显然该过程不是连几根线那么简单:其次测试一对蓝牙的使用仅限于信号搜索层面,而测试二一下子深入到可靠通信的层面了,其难度可想而知:最后在测试二中客户端的设计中复杂的状态转换过程,以及嵌入式编程时需要对所使用的硬件作细致的分析,都构成了对前期基础没打牢的同学一种挑战.不过好

打造炫酷通用的ViewPager指示器 - Adapter模式适配所有

1.概述 上一期我们已经写了一篇 打造炫酷通用的ViewPager指示器 - 玩转字体变色 可是这种效果虽然绚烂可以装装A和C之间,但是在实际的大多数效果中并不常见,只是在内涵段子中有这个效果而已,那么这一期我们就用Adapter适配器模式适配所有的效果,堪称终结者.附视频地址:等这个周末吧 2.效果实现 2.1 整合上一个实例: 我还是还是拿上一个实例来做演示吧.这里我贴几种常见的效果,首先声明Android自带的有这个控件叫TabLayout,大家可以自己用用试试看好用不?我也用过但是不做任

web前端炫酷实用的HTML5应用和jQuery插件

又开始了新的一天,我们也将继续为大家分享许多优秀的HTML5应用和jQuery插件,作为前端开发者来说,这些资源可以帮助你在项目开发上派上用场.下面一起来看看这些炫酷而实用的HTML5应用和jQuery插件吧. 1.jQuery/CSS3图片洗牌切换动画特效 这是一款基于jQuery和CSS3的图片动画特效,该图片动画是洗牌的效果,我们只需点击切换按钮,即可一张张切换图片.另外,如果你长按住按钮不放,图片的洗牌效果就会更加明显和有趣,该jQuery图片特效一共有3中效果. 在线演示 源码下载 2

【Android UI设计与开发】第06期:底部菜单栏(一)使用TabActivity实现底部菜单栏

转载请注明出处:http://blog.csdn.net/yangyu20121224/article/details/8989063       从这一篇文章开始,我们将进入到一个应用程序主界面UI的开发和设计中了,底部菜单栏在Android的应用开发当中占有非常重要的地位.几乎所有的手机应用程序都有底部菜单栏这样的控件,主要是因为手机的屏幕大小有限,这样一种底部菜单栏实现起来的效果可以很方便的为用户切换自己所需要的界面,具有更强的交互性.底部菜单栏的样式和效果也是五花八门,多的数不胜数,但是

CSS3 炫酷进度条

最近心学习了一款用CSS3写出的动画进度条,主要用到了radial-gradient和 linear-grandient来实现一些特殊的效果,使进度条看起来更加炫酷,我之前的项目中几乎没有用到过这些新的CSS3的新属性.下面我就总结一下我自己用过的心德来和大家分享一下,当然啦,主要是为了自己对新知识点的复习与巩固,加深理解,日后发现不对的地方可以及时改正更新. 首先我们先来了解一下,linear-gradient和radial-gradient分别代表的是线性渐变与径向渐变,不同内核的浏览器对其

【Android UI设计与开发】第09期:底部菜单栏(四)Fragment+PopupWindow仿QQ空间最新版底部菜单栏

转载请注明出处:http://blog.csdn.net/yangyu20121224/article/details/9023451          在今天的这篇文章当中,我依然会以实战加理论结合的方式教大家如何设计出自己觉得很炫的UI界面.好的,话不多说,进入正题.今天的这篇文章主要是以仿QQ空间的底部菜单栏效果为主,实现的效果有: <1>实现了点击按钮时的切换图片效果: <2>实现了点击按钮时的切换界面效果: <3>实现了点击中间圆形按钮时弹出菜单以及按钮图片切