最近遇到一个问题,想定制actionmode,首先需要去掉actionmode左边的√ 号,其次用setcustomview 自定义布局。安网上的方法:
<style name="AppTheme" parent="android:Theme.Holo">
<item name="android:actionModeCloseButtonStyle">@style/NoCloseButton</item>
</style> <style name="NoCloseButton" parent="@android:style/Widget.ActionButton.CloseMode">
<item name="android:visibility">gone</item>
</style>
去掉了左边的√ 号。
但接下来setcustomview的时候,布局无法充满整个actionbar。 绿色标出的部分无法填满,xml布局写的是match_parent
<style name="AppTheme" parent="android:Theme.Holo">
<item name="android:actionModeCloseButtonStyle">@style/NoCloseButton</item>
</style> <style name="NoCloseButton" parent="@android:style/Widget.ActionButton.CloseMode">
<item name="android:visibility">gone</item>
</style>
去掉了左边的√ 号。
但接下来setcustomview的时候,布局无法充满整个actionbar。 绿色标出的部分无法填满,xml布局写的是match_parent
代码内 actionMOde. setCustomView(mCustomView)id = action_mode_close_button 就是所谓的 左边的√ 号
visible 被设置为 GONE
下面一楼说明原因
因此,要找3个TextView 的linearLayout的大小在哪里确定,就应该去找它的父容器,
从#8 楼的图看出,应该定位到 ActionBarContextView 去看源码
下面是 源码 actionBarContextView.java - onMeasure() 的一部分 if (mClose != null) {
availableWidth = measureChildView(mClose, availableWidth, childSpecHeight, 0);
MarginLayoutParams lp = (MarginLayoutParams) mClose.getLayoutParams();
availableWidth -= lp.leftMargin + lp.rightMargin;
}meaasureChildView()方法在父类AbsActionbarView中: protected int measureChildView(View child, int availableWidth, int childSpecHeight,
int spacing) {
child.measure(MeasureSpec.makeMeasureSpec(availableWidth, MeasureSpec.AT_MOST),
childSpecHeight); availableWidth -= child.getMeasuredWidth();
availableWidth -= spacing; return Math.max(0, availableWidth);
}可以看到 mClose (就是 “√ 号”)只是判断了是否为null,但是却没有判断是否visible == GONE
一个本该不measure的view(因为是GONE),但是依然计算了。
这就导致在计算后,availableWidth 变小了在回到ActionBarCOntextView - OnMeasure()if (mCustomView != null) {
ViewGroup.LayoutParams lp = mCustomView.getLayoutParams();
final int customWidthMode = lp.width != LayoutParams.WRAP_CONTENT ?
MeasureSpec.EXACTLY : MeasureSpec.AT_MOST;
final int customWidth = lp.width >= 0 ?
Math.min(lp.width, availableWidth) : availableWidth;
final int customHeightMode = lp.height != LayoutParams.WRAP_CONTENT ?
MeasureSpec.EXACTLY : MeasureSpec.AT_MOST;
final int customHeight = lp.height >= 0 ?
Math.min(lp.height, height) : height;
mCustomView.measure(MeasureSpec.makeMeasureSpec(customWidth, customWidthMode),
MeasureSpec.makeMeasureSpec(customHeight, customHeightMode));
}可以看到 customWidth 被赋值的是 availableWidth(这时候这个值已经变小了)
因此最后拿到的结果就是大家看到的样子。
Layout作为一个container,用来存放我们的customView
然后重写内面的onMeasure方法,宽度等于屏幕的宽度就好了。这么做的原因:
1. View的大小,是由父容器传递进来的参数—— measure Spec 决定的(上面我有说到)
2. 改变View的大小,不让父容器决定,不理会父容器传递的参数,由自己来给自己确定大小,因此需要重写onMeasure这样的副作用是:如果 mClose 按钮重新设置成Visible,customView是不会从屏幕宽度变小,会覆盖 mClose 按钮