股票场内基金交易,没时间盯盘?
问题缘起
在进行Coolcode项目的MyclassActivity中,我发现navigationIcon和title之间的实际间距与UI图不符,虽然康师傅说不需要改,但是出于好奇心我还是希望明白其中原因。
UI要求
实际显示
问题分析
由于学习Android时间不长,无法一步直指问题所在,所以我们就从和Toolbar有关的所有代码里面一个个找(在myclasses里面)。
首先我们在MyClassActivity中首次调用了BaseActivity中的initBackToolbar(Toolbar toolbar, @StringRes int title, @DrawableRes int navigationIcon)方法,显然这个方法并没有对距离有任何修改。
那么我们在来看这个BaseActivity中的方法,它给Toolbar设置了title和navigationIcon,但是并不能看到其中有对之间的距离有做相应修改,我们翻看其他myclasses下的类,也并没有发现。
那么,问题看来只能是出现在Toolbar中了,那么来看一下Toolbar代码。
……!
好长!相信没有完整的时间和计划大家是不会想好好看完这段代码的。那么我们直接来看里面最重要的控制输出的代码onLayout(boolean changed, int l, int r, int b)
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 55 56 |
protected void onLayout(boolean changed, int l, int t, int r, int b) { //视图输出控制 final boolean isRtl = ViewCompat.getLayoutDirection(this) == ViewCompat.LAYOUT_DIRECTION_RTL; final int width = getWidth(); final int height = getHeight(); //获取输出屏幕长宽 final int paddingLeft = getPaddingLeft(); final int paddingRight = getPaddingRight(); final int paddingTop = getPaddingTop(); final int paddingBottom = getPaddingBottom(); //获取该视图与屏幕的偏移量 int left = paddingLeft; int right = width - paddingRight; //由于Toolbar大部分情况下不需要控制纵轴,使用left,right两个变量控制控件位置 final int[] collapsingMargins = mTempMargins; collapsingMargins[0] = collapsingMargins[1] = 0; //外边距合并控制参数数组 // Align views within the minimum toolbar height, if set. final int minHeight = ViewCompat.getMinimumHeight(this); final int alignmentHeight = minHeight >= 0 ? Math.min(minHeight, b - t) : 0; //对齐方法参数 if (shouldLayout(mNavButtonView)) { //通过shouldLayout方法判定是否需要输出NavigationIcon if (isRtl) { right = layoutChildRight(mNavButtonView, right, collapsingMargins, alignmentHeight); } else { left = layoutChildLeft(mNavButtonView, left, collapsingMargins, alignmentHeight); } } //判断从左还是从右开始输出,并因此使用layoutChildLeft或是layoutChildRight进行输出 //以下省略CollapseButton和Menu空间,类似NavigationIcon控件 ........ //将NavigationIcon,CollapseButton和Menu三个控件设为一组 final int contentInsetLeft = getCurrentContentInsetLeft(); final int contentInsetRight = getCurrentContentInsetRight(); //获取系统设置的缩进值 collapsingMargins[0] = Math.max(0, contentInsetLeft - left); collapsingMargins[1] = Math.max(0, contentInsetRight - (width - paddingRight - right)); left = Math.max(left, contentInsetLeft); right = Math.min(right, width - paddingRight - contentInsetRight); //比较系统缩进值和真实缩进值大小,取大者为实际缩进值 //以下省略通过shouldLayout方法判定并输出ExpandedAction和Logo控件 ...... //以下是Title空间的输出,包含主标题和副标题 final boolean layoutTitle = shouldLayout(mTitleTextView); final boolean layoutSubtitle = shouldLayout(mSubtitleTextView); //由于内容过长以下进行省略,核心就是通过已知的参数对Title和Subtitle进行判定并输出 //以从左开始输出为例,Title控件左侧缩进参数就是left |
整理逻辑:
onLayout函数先判定并输出NavigationIcon,CollapseButton和Menu三个控件。
比较系统缩进值和真实缩进值,取大者为实际缩进值。
onLayout函数判定并输出ExpandedAction和Logo两个控件。
onLayout函数判定并输出Title和SubTitle两个控件。
根据实际需求,实际mToolbar需要输出的只有NavigationIcon和Title控件。那么两者之间的距离就应该是实际缩进值。
简单的来说,就是left = Math.max(left, contentInsetLeft);的这个left。
那么实际缩进值是如何计算的呢,我们重新进入代码:
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 |
//layoutChildLeft,layoutChildRight是Toolbar的内部方法 private int layoutChildLeft(View child, int left, int[] collapsingMargins, int alignmentHeight) { //方法需要控件视图,开始的left位置,外边距合并参数,对齐参数 final LayoutParams lp = (LayoutParams) child.getLayoutParams(); final int l = lp.leftMargin - collapsingMargins[0]; left += Math.max(0, l); collapsingMargins[0] = Math.max(0, -l); final int top = getChildTop(child, alignmentHeight); final int childWidth = child.getMeasuredWidth(); child.layout(left, top, left + childWidth, top + child.getMeasuredHeight()); left += childWidth + lp.rightMargin; return left; } //获取视图位置参数,传入View中的layout方法进行输出(这个不进行详细探究),并且修改left参数,使其变为原left位置+控件图片宽度+右缩进值 //layoutChildRight方法类似,不进行赘述 //getCurrentContentInsetLeft,getCurrentContentInsetRight是Toolbar的内部方法 public int getCurrentContentInsetLeft() { return ViewCompat.getLayoutDirection(this) == ViewCompat.LAYOUT_DIRECTION_RTL ? getCurrentContentInsetEnd() : getCurrentContentInsetStart(); } //通过输出方向判断并调用getCurrentContentInsetStart或getCurrentContentInsetEnd方法 //getCurrentContentInsetStart和getCurrentContentInsetEnd是Toolbar的内部方法 public int getCurrentContentInsetStart() { return getNavigationIcon() != null ? Math.max(getContentInsetStart(), Math.max(mContentInsetStartWithNavigation, 0)) : getContentInsetStart(); } //判定NavigationIcon是否存在,如果不存在就通过getContentInsetStart方法获取;如果存在,比较求取getContentInsetStart,mContentInsetStartWithNavigation和0的最大值 //所以实际就是比较ContentInsetStart和ContentInsetStartWithNavigation的值 |
那么ContentInsetStart和ContentInsetStartWithNavigation的值是多少呢,我们打开appcompat-v7包的以下位置.
Toolbar的默认style是appcompat-v7中的Widget.AppCompat.Toolbar
1 2 |
<style name="Widget.AppCompat.Toolbar" parent="Base.Widget.AppCompat.Toolbar"/> |
Widget.AppCompat.Toolbar的父类是Base.Widget.AppCompat.Toolbar
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 |
<style name="Base.Widget.AppCompat.Toolbar" parent="android:Widget"> <item name="titleTextAppearance">@style/TextAppearance.Widget.AppCompat.Toolbar.Title</item> <item name="subtitleTextAppearance">@style/TextAppearance.Widget.AppCompat.Toolbar.Subtitle</item> <item name="android:minHeight">?attr/actionBarSize</item> <item name="titleMargin">4dp</item> <item name="maxButtonHeight">@dimen/abc_action_bar_default_height_material</item> <item name="buttonGravity">top</item> <item name="collapseIcon">?attr/homeAsUpIndicator</item> <item name="collapseContentDescription">@string/abc_toolbar_collapse_description</item> <item name="contentInsetStart">16dp</item> <item name="contentInsetStartWithNavigation">@dimen/abc_action_bar_content_inset_with_nav</item> <item name="android:paddingLeft">@dimen/abc_action_bar_default_padding_start_material</item> <item name="android:paddingRight">@dimen/abc_action_bar_default_padding_end_material</item> </style> |
contentInsetStart的值是16dp,contentInsetStartWithNavigation简单查找出来是72dp。
所以,当我们的NavigationIcon控件宽度较小的时候,title与父视图的左边框缩进为72dp,而不是紧随NavigationIcon(一般为56db)。
解决方法
搞明白了问题的原因,自然也找到了问题的解决方法。
我们打开程序/src/main/res/values/styles.xml,自创一个新的style(父类设定为Base.Widget.AppCompat.Toolbar),在style中重写资源代码:
1 2 3 |
<item name="contentInsetStart">0dp</item> <item name="contentInsetStartWithNavigation">0dp</item> |
简单的设定为0dp的话就保证Title的left参数紧贴NavigationIcon。
当然,我们也可以进行其他的设定来控制title的位置啦!
1 2 3 4 5 6 |
<android.support.v7.widget.Toolbar android:id="@+id/toolbar" ...... app:contentInsetStartWithNavigation="0dp" ...... </android.support.v7.widget.Toolbar> |
想获得去掉 5 元限制的证券账户吗?

如果您想去掉最低交易佣金 5 元限制,使用微信扫描左边小程序二维码,访问微信小程序「优财助手」,点击底部菜单「福利」,阅读文章「通过优财开证券账户无最低交易佣金 5 元限制」,按照文章步骤操作即可获得免 5 元证券账户,股票基金交易手续费率万 2.5。
请注意,一定要按照文章描述严格操作,如错误开户是无法获得免 5 元证券账户的。
受教了!呵呵!