[Android]Toolbar使用详解(三)——源码解析
16lz
2021-01-24
更多关于Toolbar的使用请移步Toolbar使用详解系列
从Toolbar的使用一步步解析Toolbar源码
大体架构
API 0.设置导航图标
mToolbar.setNavigationIcon(R.drawable.ic_actionbar_flow);
源码如下
public void setNavigationIcon(int resId) { this.setNavigationIcon(this.mTintManager.getDrawable(resId)); }
setNavigationIcon
public void setNavigationIcon(@Nullable Drawable icon) { if(icon != null) { this.ensureNavButtonView(); if(this.mNavButtonView.getParent() == null) { this.addSystemView(this.mNavButtonView); this.updateChildVisibilityForExpandedActionView(this.mNavButtonView); } } else if(this.mNavButtonView != null && this.mNavButtonView.getParent() != null) { this.removeView(this.mNavButtonView); } if(this.mNavButtonView != null) { this.mNavButtonView.setImageDrawable(icon); } }
先判断传入图片参数是否为null
- null,移除导航图片。
- 不为null,新建一个ImageView,设置其LayoutParams,最后设置ImageView的图片为入参。
ensureNavButtonView
保证导航图片不为null,为null则新建并添加。
private void ensureNavButtonView() { if(this.mNavButtonView == null) { this.mNavButtonView = new ImageButton(this.getContext(), (AttributeSet)null, attr.toolbarNavigationButtonStyle); Toolbar.LayoutParams lp = this.generateDefaultLayoutParams(); lp.gravity = 8388611 | this.mButtonGravity & 112; this.mNavButtonView.setLayoutParams(lp); } }
设置导航图标,通过LayoutParams.gravity lp.gravity=8388611设置gravity=start即左边开始位置
在Toolbar构造函数内对gravity进行了初始化
this.mButtonGravity = 48;
48:gravity = top &112 = 得到gravity的纵向位置
综上,即设置导航坐标处于左上位置
关于gravity的详细说明
继续往下判断父窗体是否为null
addSystemView
private void addSystemView(View v) { android.view.ViewGroup.LayoutParams vlp = v.getLayoutParams(); Toolbar.LayoutParams lp; if(vlp == null) { lp = this.generateDefaultLayoutParams(); } else if(!this.checkLayoutParams(vlp)) { lp = this.generateLayoutParams(vlp); } else { lp = (Toolbar.LayoutParams)vlp; } lp.mViewType = 1; this.addView(v, lp); }
因为Toolbar继承自ViewGroup,当导航图标的父窗体为null时,将图标添加到Toolbar上。 updateChildVisbilityForExpandedActionView
设置导航图标为可见API 1.setNavifationOnClickListener
源码如下 public void setNavigationOnClickListener(OnClickListener listener) { this.ensureNavButtonView(); this.mNavButtonView.setOnClickListener(listener); }
ensureNavButtonView上面已作出说明 setOnClickListener
this.mNavButtonView是ImageView,这里就是简单对其设置一个点击按钮的监听事件。API 2.setTitle
public void setTitle(CharSequence title) { if(!TextUtils.isEmpty(title)) {
//title不为null if(this.mTitleTextView == null) {
//如果主标题TextView不存在则新建 Context context = this.getContext(); this.mTitleTextView = new TextView(context); this.mTitleTextView.setSingleLine(); this.mTitleTextView.setEllipsize(TruncateAt.END); if(this.mTitleTextAppearance != 0) { this.mTitleTextView.setTextAppearance(context, this.mTitleTextAppearance); } if(this.mTitleTextColor != 0) {
//设置字体颜色 this.mTitleTextView.setTextColor(this.mTitleTextColor); } } if(this.mTitleTextView.getParent() == null) {
//若父窗体为null,则添加主标题TextView,同导航图标 this.addSystemView(this.mTitleTextView);
//同样更新为可见状态 this.updateChildVisibilityForExpandedActionView(this.mTitleTextView); } } else if(this.mTitleTextView != null && this.mTitleTextView.getParent() != null) {
//title为null则移除主标题的TextView this.removeView(this.mTitleTextView); } if(this.mTitleTextView != null) {
//存在主标题TextView则设置文字 this.mTitleTextView.setText(title); }
//设置当前文件 this.mTitleText = title;
API 3.setSubTitle、setTitleTextColor、setSubTitleTextColor
原理跟setTitle一样不再赘述。API 4.inflateMenu
public void inflateMenu(int resId) { this.getMenuInflater().inflate(resId, this.getMenu()); }
最终调用的是SupportMenuInflater.inflate方法 public void inflate(int menuRes, Menu menu) { if(!(menu instanceof SupportMenu)) {
//getMenu方法下面介绍,先记住getMenu返回的是SupportMenu的实现类 super.inflate(menuRes, menu); } else { XmlResourceParser parser = null; try { parser = this.mContext.getResources().getLayout(menuRes); AttributeSet e = Xml.asAttributeSet(parser);
//分析menu.xml文件,往menu里添加menuItem this.parseMenu(parser, e, menu); } catch (XmlPullParserException var9) { throw new InflateException("Error inflating menu XML", var9); } catch (IOException var10) { throw new InflateException("Error inflating menu XML", var10); } finally { if(parser != null) { parser.close(); } } } }
getMenu
public Menu getMenu() { this.ensureMenu(); return this.mMenuView.getMenu(); }
ensureMenu
private void ensureMenu() { this.ensureMenuView(); if(this.mMenuView.peekMenu() == null) {
//沉浸式菜单为空 MenuBuilder menu = (MenuBuilder)this.mMenuView.getMenu(); if(this.mExpandedMenuPresenter == null) {
//创建沉浸式菜单的每一个菜单项 this.mExpandedMenuPresenter = new Toolbar.ExpandedActionViewMenuPresenter(null); }//显示菜单 this.mMenuView.setExpandedActionViewsExclusive(true); menu.addMenuPresenter(this.mExpandedMenuPresenter, this.mPopupContext); } }
ensureMenuView
private void ensureMenuView() { if(this.mMenuView == null) { this.mMenuView = new ActionMenuView(this.getContext()); this.mMenuView.setPopupTheme(this.mPopupTheme); this.mMenuView.setOnMenuItemClickListener(this.mMenuViewItemClickListener); this.mMenuView.setMenuCallbacks(this.mActionMenuPresenterCallback, this.mMenuBuilderCallback); Toolbar.LayoutParams lp = this.generateDefaultLayoutParams(); lp.gravity = 8388613 | this.mButtonGravity & 112; this.mMenuView.setLayoutParams(lp); this.addSystemView(this.mMenuView); } }
这里很重要,功能是新建这个Toolbar菜单栏。实现在ActionMenuView,ActionMenuView的实现不再本文的讨论范围,只要知道ActionMenuView继承LinearLayoutCompat。 其实整个Toolbar就是一个LinearLayout布局,只是在上面自定义了布局。 parseMenu
private void parseMenu(XmlPullParser parser, AttributeSet attrs, Menu menu) throws XmlPullParserException, IOException { SupportMenuInflater.MenuState menuState = new SupportMenuInflater.MenuState(menu); int eventType = parser.getEventType(); boolean lookingForEndOfUnknownTag = false; String unknownTagName = null; String tagName;
//找到
//添加菜单项 menuState.readItem(attrs); } else if(tagName.equals("menu")) { SubMenu subMenu = menuState.addSubMenuItem(); this.parseMenu(parser, attrs, subMenu); } else { lookingForEndOfUnknownTag = true; unknownTagName = tagName; } } break; case 3: tagName = parser.getName(); if(lookingForEndOfUnknownTag && tagName.equals(unknownTagName)) { lookingForEndOfUnknownTag = false; unknownTagName = null; } else if(tagName.equals("group")) { menuState.resetGroup(); } else if(tagName.equals("item")) { if(!menuState.hasAddedItem()) { if(menuState.itemActionProvider != null && menuState.itemActionProvider.hasSubMenu()) { menuState.addSubMenuItem(); } else { menuState.addItem(); } } } else if(tagName.equals("menu")) { reachedEndOfMenu = true; } } } }
分析完毕后就把MenuItem显示到Menu上。 API 5.setOnMenuItemClickListener
private final ActionMenuView.OnMenuItemClickListener mMenuViewItemClickListener = new ActionMenuView.OnMenuItemClickListener() { @Override public boolean onMenuItemClick(MenuItem item) { if (mOnMenuItemClickListener != null) { return mOnMenuItemClickListener.onMenuItemClick(item); } return false; } };
最后实现是在ActionMenuView中。 欢迎大家讨论,纯属抛砖引玉。
更多相关文章
- Android沉浸式标题栏状态栏字体颜色修改(小米和魅族以及Android6.
- android p状态栏,插入sim卡,关闭数据流量,状态栏卡图标右下角有X图标
- android 全屏 无标题
- Activity去掉标题栏失败(使用AppCompat)
- android应用中去掉标题栏的方法
- 通过设置android:imeOptions来改变软键盘Enter键图标
- Android(安卓)标题栏上加一个返回按钮 超简单的返回
- Android中隐藏标题栏和状态栏(电源,信号,时间等信息)
- Android(安卓)Toast带图标水平布局的简单实现