更多关于Toolbar的使用请移步Toolbar使用详解系列

从Toolbar的使用一步步解析Toolbar源码

大体架构

e4791b821a0207a70612c8502a242666.png

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;//找到

do {

if(eventType == 2) {

tagName = parser.getName();

if(!tagName.equals("menu")) {

throw new RuntimeException("Expecting menu, got " + tagName);

}

eventType = parser.next();

break;

}

eventType = parser.next();

} while(eventType != 1);

//开始遍历

for(boolean reachedEndOfMenu = false; !reachedEndOfMenu; eventType = parser.next()) {

switch(eventType) {

case 1:

throw new RuntimeException("Unexpected end of document");

case 2:

if(!lookingForEndOfUnknownTag) {

tagName = parser.getName();

if(tagName.equals("group")) {

menuState.readGroup(attrs);

} else if(tagName.equals("item")) {//添加菜单项

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中。

欢迎大家讨论,纯属抛砖引玉。

版权声明:本文为博主原创文章,未经博主允许不得转载。

原文:http://blog.csdn.net/qq284565035/article/details/47107821

Logo

为开发者提供学习成长、分享交流、生态实践、资源工具等服务,帮助开发者快速成长。

更多推荐