返回介绍

2.2 数据源的初始化

发布于 2024-12-23 21:21:14 字数 4237 浏览 0 评论 0 收藏 0

到这里我们已经确定了 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 技术交流群。

扫码二维码加入Web技术交流群

发布评论

需要 登录 才能够评论, 你可以免费 注册 一个本站的账号。
列表为空,暂无数据
    我们使用 Cookies 和其他技术来定制您的体验包括您的登录状态等。通过阅读我们的 隐私政策 了解更多相关信息。 单击 接受 或继续使用网站,即表示您同意使用 Cookies 和您的相关数据。
    原文