- CompoundButton 源码分析
- LinearLayout 源码分析
- SearchView 源码解析
- LruCache 源码解析
- ViewDragHelper 源码解析
- BottomSheets 源码解析
- Media Player 源码分析
- NavigationView 源码解析
- Service 源码解析
- Binder 源码分析
- Android 应用 Preference 相关及源码浅析 SharePreferences 篇
- ScrollView 源码解析
- Handler 源码解析
- NestedScrollView 源码解析
- SQLiteOpenHelper/SQLiteDatabase/Cursor 源码解析
- Bundle 源码解析
- LocalBroadcastManager 源码解析
- Toast 源码解析
- TextInputLayout
- LayoutInflater 和 LayoutInflaterCompat 源码解析
- TextView 源码解析
- NestedScrolling 事件机制源码解析
- ViewGroup 源码解析
- StaticLayout 源码分析
- AtomicFile 源码解析
- AtomicFile 源码解析
- Spannable 源码分析
- Notification 之 Android 5.0 实现原理
- CoordinatorLayout 源码分析
- Scroller 源码解析
- SwipeRefreshLayout 源码分析
- FloatingActionButton 源码解析
- AsyncTask 源码分析
- TabLayout 源码解析
2.2 数据源的初始化
到这里我们已经确定了 NavigationView
是个 FrameLayout,其内部放置了一个 RecyclerView
,根据我们的使用情况,并不需要去单独的设置 item 数据,只需要使用属性 app:menu="@menu/drawer"
,所以,RecylcerView 对应的 Adapter 所需要的数据源,肯定也是在构造方法中获取的。
简单看一眼构造中的代码,找到如下几行:
#NavigationView if (a.hasValue(R.styleable.NavigationView_menu)) { inflateMenu(a.getResourceId(R.styleable.NavigationView_menu, 0)); } public void inflateMenu(int resId) { getMenuInflater().inflate(resId, mMenu); mPresenter.updateMenuView(false); }
可以看到呢,对我们的 menu 读取后,调用的是 getMenuInflater().inflate
,通过该方法呢,会完成对我们资源文件中定义的 menuItem 读取值 mMenu 中。读取完成以后呢,调用了 mPresenter.updateMenuView
,该方法会间接的为 Adapter
设置值以及调用 notifyDataSetChanged
,具体代码如下:
#NavigationMenuPresenter @Override public void updateMenuView(boolean cleared) { if (mAdapter != null) { mAdapter.update(); } } #NavigationMenuPresenter.NavigationMenuAdapter public void update() { prepareMenuItems(); notifyDataSetChanged(); }
第一个方法肯定是准备数据,第二个方法通知更新了。对于数据的准备呢,我们需要去了解下,因为 NavigationView
中的 item 并不是一样的,涉及到多种类型。
#NavigationMenuPresenter.NavigationMenuAdapter private void prepareMenuItems() { mItems.clear(); mItems.add(new NavigationMenuHeaderItem()); int currentGroupId = -1; int currentGroupStart = 0; boolean currentGroupHasIcon = false; for (int i = 0, totalSize = mMenu.getVisibleItems().size(); i < totalSize; i++) { MenuItemImpl item = mMenu.getVisibleItems().get(i); //..省略几行代码 if (item.hasSubMenu()) { SubMenu subMenu = item.getSubMenu(); if (subMenu.hasVisibleItems()) { if (i != 0) { mItems.add(new NavigationMenuSeparatorItem(mPaddingSeparator, 0)); } mItems.add(new NavigationMenuTextItem(item)); boolean subMenuHasIcon = false; int subMenuStart = mItems.size(); for (int j = 0, size = subMenu.size(); j < size; j++) { MenuItemImpl subMenuItem = (MenuItemImpl) subMenu.getItem(j); //.. mItems.add(new NavigationMenuTextItem(subMenuItem)); } } } else { int groupId = item.getGroupId(); if (groupId != currentGroupId) { // first item in group if (i != 0) { currentGroupStart++; mItems.add(new NavigationMenuSeparatorItem( mPaddingSeparator, mPaddingSeparator)); } } mItems.add(new NavigationMenuTextItem(item)); currentGroupId = groupId; } } }
上面代码蛮长的,主要关注什么呢?很明显 mItems 是 Adapter 对应的数据源,那么我们关注的应该就是 mItems.add()
方法。
首先加了个 NavigationMenuHeaderItem
,我们都知道 RecylerView 本身并没有 addHeaderView 方法,看来对于 headLayout 也是通过多种 item type 实现的。
接下来是遍历 mMenu.getVisibleItems()
,那么我们按顺序看代码吧,首先判断的是:
- item.hasSubMenu()
如果包含 subMenu,则调用:
mItems.add(new NavigationMenuTextItem(item));
如果当前并非是第一个,则还需要添加一个分隔符(NavigationMenuSeparatorItem)
mItems.add(new NavigationMenuSeparatorItem(mPaddingSeparator, 0));
再往下就是遍历所有的 subMenu 了,也很简单,直接添加
NavigationMenuTextItem
mItems.add(new NavigationMenuTextItem(subMenuItem));
- else 分支(即不包含 subMenu)
首先判断是否是 group 的第一个 item,如果是的话,需要额外添加一个分隔符(
NavigationMenuSeparatorItem
),否则的话直接添加一个NavigationMenuTextItem
。
好了,这样的话,我们就分析完了,可以看到上面呢,一共包含几种 MenuItem 呢?
- NavigationMenuHeaderItem 对应 HeaderLayout
- NavigationMenuTextItem 对应于一般的 Item
- NavigationMenuSeparatorItem 对应分隔符
从源码上看只有上述 3 中,那么我们看一个包含多种 menu item 的效果图:
简单数一下,怎么好像是 4 种,恩,其实上图 2,4 都是 NavigationMenuTextItem
,只不过 4 中传入的 item 的 hasSubMenu=true
.
这样的话,我们就分析完成了数据源的初始化。
那么 Adapter 有了数据源,并且调用了 notifyDataSetChanged
,接下来应该看的代码就是 Adapter 内部的 onCreateViewHolder 和 onCreateViewHolder
等代码了。
如果你对这篇内容有疑问,欢迎到本站社区发帖提问 参与讨论,获取更多帮助,或者扫码二维码加入 Web 技术交流群。
绑定邮箱获取回复消息
由于您还没有绑定你的真实邮箱,如果其他用户或者作者回复了您的评论,将不能在第一时间通知您!
发布评论