dependencies { //grpc dependencies // You need to build grpc-java to obtain these libraries below. implementation 'io.grpc:grpc-okhttp:1.44.1'// CURRENT_GRPC_VERSION implementation 'org.apache.tomcat:annotations-api:6.0.53' implementation 'io.grpc:grpc-protobuf-lite:1.45.0' implementation 'io.grpc:grpc-stub:1.45.0' }
protectedvoidmeasureChildWithMargins(View child, int parentWidthMeasureSpec, int widthUsed, int parentHeightMeasureSpec, int heightUsed) { finalMarginLayoutParamslp= (MarginLayoutParams) child.getLayoutParams();
java.lang.ClassCastException: android.view.ViewGroup$LayoutParams cannot be cast to android.view.ViewGroup$MarginLayoutParams at android.view.ViewGroup.measureChildWithMargins(ViewGroup.java:6899) at com.hezd.taglayout.FlowLayout.onMeasure(FlowLayout.kt:23) at android.view.View.measure(View.java:24851) at androidx.constraintlayout.widget.ConstraintLayout$Measurer.measure(ConstraintLayout.java:811)
protectedvoidmeasureChildWithMargins(View child, int parentWidthMeasureSpec, int widthUsed, int parentHeightMeasureSpec, int heightUsed) { // 子ViewLayoutParams强转为MarginLayoutParms finalMarginLayoutParamslp= (MarginLayoutParams) child.getLayoutParams();
/** * *@author hezd *Create on 2021/12/24 17:08 */ classFlowLayout(context: Context, attrs: AttributeSet) : ViewGroup(context, attrs) { var lineSpacing: Int var itemSpacing: Int
privatevoidperformTraversals() { // 忽略部分代码…… intchildWidthMeasureSpec= getRootMeasureSpec(mWidth, lp.width); intchildHeightMeasureSpec= getRootMeasureSpec(mHeight, lp.height); // Ask host how big it wants to be performMeasure(childWidthMeasureSpec, childHeightMeasureSpec); }
privatestaticintgetRootMeasureSpec(int windowSize, int rootDimension) { int measureSpec; switch (rootDimension) {
case ViewGroup.LayoutParams.MATCH_PARENT: // Window can't resize. Force root view to be windowSize. measureSpec = MeasureSpec.makeMeasureSpec(windowSize, MeasureSpec.EXACTLY); break; case ViewGroup.LayoutParams.WRAP_CONTENT: // Window can resize. Set max size for root view. measureSpec = MeasureSpec.makeMeasureSpec(windowSize, MeasureSpec.AT_MOST); break; default: // Window wants to be an exact size. Force root view to be that size. measureSpec = MeasureSpec.makeMeasureSpec(rootDimension, MeasureSpec.EXACTLY); break; } return measureSpec; }
privatestaticintgetRootMeasureSpec(int windowSize, int rootDimension) { int measureSpec; switch (rootDimension) { case ViewGroup.LayoutParams.MATCH_PARENT: // Window can't resize. Force root view to be windowSize. measureSpec = MeasureSpec.makeMeasureSpec(windowSize, MeasureSpec.EXACTLY); break; case ViewGroup.LayoutParams.WRAP_CONTENT: // Window can resize. Set max size for root view. measureSpec = MeasureSpec.makeMeasureSpec(windowSize, MeasureSpec.AT_MOST); break; default: // Window wants to be an exact size. Force root view to be that size. measureSpec = MeasureSpec.makeMeasureSpec(rootDimension, MeasureSpec.EXACTLY); break; } return measureSpec; }
publicstaticintgetChildMeasureSpec(int spec, int padding, int childDimension) { // 父view的MeasureSpec约束 intspecMode= MeasureSpec.getMode(spec); intspecSize= MeasureSpec.getSize(spec);
intsize= Math.max(0, specSize - padding);
intresultSize=0; intresultMode=0; // 通过父View的MeasureSpec结合子View的布局信息 // 计算出子View的MeasureSpec约束 switch (specMode) { // Parent has imposed an exact size on us case MeasureSpec.EXACTLY: if (childDimension >= 0) { resultSize = childDimension; resultMode = MeasureSpec.EXACTLY; } elseif (childDimension == LayoutParams.MATCH_PARENT) { // Child wants to be our size. So be it. resultSize = size; resultMode = MeasureSpec.EXACTLY; } elseif (childDimension == LayoutParams.WRAP_CONTENT) { // Child wants to determine its own size. It can't be // bigger than us. resultSize = size; resultMode = MeasureSpec.AT_MOST; } break;
// Parent has imposed a maximum size on us case MeasureSpec.AT_MOST: if (childDimension >= 0) { // Child wants a specific size... so be it resultSize = childDimension; resultMode = MeasureSpec.EXACTLY; } elseif (childDimension == LayoutParams.MATCH_PARENT) { // Child wants to be our size, but our size is not fixed. // Constrain child to not be bigger than us. resultSize = size; resultMode = MeasureSpec.AT_MOST; } elseif (childDimension == LayoutParams.WRAP_CONTENT) { // Child wants to determine its own size. It can't be // bigger than us. resultSize = size; resultMode = MeasureSpec.AT_MOST; } break;
// Parent asked to see how big we want to be case MeasureSpec.UNSPECIFIED: if (childDimension >= 0) { // Child wants a specific size... let him have it resultSize = childDimension; resultMode = MeasureSpec.EXACTLY; } elseif (childDimension == LayoutParams.MATCH_PARENT) { // Child wants to be our size... find out how big it should // be resultSize = View.sUseZeroUnspecifiedMeasureSpec ? 0 : size; resultMode = MeasureSpec.UNSPECIFIED; } elseif (childDimension == LayoutParams.WRAP_CONTENT) { // Child wants to determine its own size.... find out how // big it should be resultSize = View.sUseZeroUnspecifiedMeasureSpec ? 0 : size; resultMode = MeasureSpec.UNSPECIFIED; } break; } //noinspection ResourceType return MeasureSpec.makeMeasureSpec(resultSize, resultMode); }
// Lay out child directly against the parent measure spec so that // we can obtain exected minimum width and height. // 如果父View传递的specMode约束为UNSPECIFIED测量第一个条目高度childHeight measureScrapChild(child, 0, widthMeasureSpec, heightSize);
@Override protectedvoidmeasureChildWithMargins(View child, int parentWidthMeasureSpec, int widthUsed, int parentHeightMeasureSpec, int heightUsed) { finalMarginLayoutParamslp= (MarginLayoutParams) child.getLayoutParams();
/** * This is called to find out how big a view should be. The parent * supplies constraint information in the width and height parameters. * 从文档注释可以看出:widthMeasureSpec和heightMeasureSpec是父View对子View尺寸测量的一个约束信息 */ publicfinalvoidmeasure(int widthMeasureSpec, int heightMeasureSpec) { //忽略部分代码... if (forceLayout || needsLayout) { // 忽略部分代码... intcacheIndex= forceLayout ? -1 : mMeasureCache.indexOfKey(key); if (cacheIndex < 0 || sIgnoreMeasureCache) { // measure ourselves, this should set the measured dimension flag back onMeasure(widthMeasureSpec, heightMeasureSpec); mPrivateFlags3 &= ~PFLAG3_MEASURE_NEEDED_BEFORE_LAYOUT; } } }
/** * View的onLayout是空实现,ViewGroup需要重写此方法 * 对子View进行布局 * Called from layout when this view should * assign a size and position to each of its children. * */ protectedvoidonLayout(boolean changed, int left, int top, int right, int bottom) { }
/** * A MeasureSpec encapsulates the layout requirements passed from parent to child. * Each MeasureSpec represents a requirement for either the width or the height. * A MeasureSpec is comprised of a size and a mode... */ publicstaticclassMeasureSpec
publicstaticintgetChildMeasureSpec(int spec, int padding, int childDimension) { // 父View的MeasureSpec intspecMode= MeasureSpec.getMode(spec); intspecSize= MeasureSpec.getSize(spec); // 可用空间 intsize= Math.max(0, specSize - padding);
intresultSize=0; intresultMode=0;
switch (specMode) { // 如果父View的specMode是EXACTLY case MeasureSpec.EXACTLY: if (childDimension >= 0) { resultSize = childDimension; resultMode = MeasureSpec.EXACTLY; } elseif (childDimension == LayoutParams.MATCH_PARENT) { // Child wants to be our size. So be it. resultSize = size; resultMode = MeasureSpec.EXACTLY; } elseif (childDimension == LayoutParams.WRAP_CONTENT) { // Child wants to determine its own size. It can't be // bigger than us. resultSize = size; resultMode = MeasureSpec.AT_MOST; } break;
// 如果父View的specMode是AT_MOST case MeasureSpec.AT_MOST: if (childDimension >= 0) { // Child wants a specific size... so be it resultSize = childDimension; resultMode = MeasureSpec.EXACTLY; } elseif (childDimension == LayoutParams.MATCH_PARENT) { // Child wants to be our size, but our size is not fixed. // Constrain child to not be bigger than us. resultSize = size; resultMode = MeasureSpec.AT_MOST; } elseif (childDimension == LayoutParams.WRAP_CONTENT) { // Child wants to determine its own size. It can't be // bigger than us. resultSize = size; resultMode = MeasureSpec.AT_MOST; } break;
// 如果父View的specMode是UNSPECIFIED case MeasureSpec.UNSPECIFIED: if (childDimension >= 0) { // Child wants a specific size... let him have it resultSize = childDimension; resultMode = MeasureSpec.EXACTLY; } elseif (childDimension == LayoutParams.MATCH_PARENT) { // Child wants to be our size... find out how big it should // be resultSize = View.sUseZeroUnspecifiedMeasureSpec ? 0 : size; resultMode = MeasureSpec.UNSPECIFIED; } elseif (childDimension == LayoutParams.WRAP_CONTENT) { // Child wants to determine its own size.... find out how // big it should be resultSize = View.sUseZeroUnspecifiedMeasureSpec ? 0 : size; resultMode = MeasureSpec.UNSPECIFIED; } break; } //noinspection ResourceType return MeasureSpec.makeMeasureSpec(resultSize, resultMode); }