- 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 了,也很简单,直接添加
NavigationMenuTextItemmItems.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 等代码了。
绑定邮箱获取回复消息
由于您还没有绑定你的真实邮箱,如果其他用户或者作者回复了您的评论,将不能在第一时间通知您!

发布评论