自定义控件测量
自定义 View 测量
自定义 Layout 测量
第一种情况 MeasureSpec.AT_MOST
第二种情况 MeasureSpec.EXACTLY
第三种情况 MeasureSpec.UNSPECIFIED
NestedScrollView 测量子 View 高度时
当 MeasureSpec.getMode(widthMeasureSpec) == MeasureSpec.UNSPECIFIED 时, MeasureSpec.getSize(widthMeasureSpec) 获取到的尺寸都是最大尺寸, 就算设置了相关 layout 属性还是一样. 为了避免这种情况可以通过 LayoutParams 获取 layout 属性, 根据实际情况去测量计算
// ShadowLayout 部分代码@Overrideprotected void onMeasure(int widthMeasureSpec, int heightMeasureSpec) {super.onMeasure(widthMeasureSpec, heightMeasureSpec);if (getChildCount() < 1) {return;}// ======================================================// 通过 MeasureSpec.getMode 获取模式存在一个问题:// 当获取 MeasureSpec.getMode == MeasureSpec.UNSPECIFIED 时,// 即使 xml 宽高设置的是具体值, MeasureSpec.getSize 获取到也还是推荐的值.// ======================================================// 下面的代码就是为了解决这种情况:// 为了避免 MeasureSpec.UNSPECIFIED 模式下获取不到 xml 设置的具体宽高值, 直接从 LayoutParams 中获取int width = getLayoutParams().width;int height = getLayoutParams().height;// 计算剩余空间int widthSize = MeasureSpec.getSize(widthMeasureSpec);int useWidth = (width > 0 ? width : widthSize) - mLeftPadding - mRightPadding;int childWidthSpec = MeasureSpec.makeMeasureSpec(useWidth, MeasureSpec.EXACTLY);int heightSize = MeasureSpec.getSize(heightMeasureSpec);int useHeight = (height > 0 ? height : heightSize) - mTopPadding - mBottomPadding;int childHeightSpec = MeasureSpec.makeMeasureSpec(useHeight, MeasureSpec.EXACTLY);View child = getChildAt(0);measureChild(child, childWidthSpec, childHeightSpec);// MATCH_PARENTif (width == ViewGroup.LayoutParams.MATCH_PARENT) {width = widthSize;}if (height == ViewGroup.LayoutParams.MATCH_PARENT) {height = heightSize;}// WRAP_CONTENTMarginLayoutParams lp = (MarginLayoutParams) child.getLayoutParams();if (width == ViewGroup.LayoutParams.WRAP_CONTENT) {width = child.getMeasuredWidth() + lp.leftMargin + lp.rightMargin + mLeftPadding + mRightPadding;}if (height == ViewGroup.LayoutParams.WRAP_CONTENT) {height = child.getMeasuredHeight() + lp.topMargin + lp.bottomMargin + mTopPadding + mBottomPadding;}setMeasuredDimension(width, height);}
自定义 layout 测量踩坑记录
java.lang.ClassCastException: android.view.ViewGroup$LayoutParams cannot be cast to android.view.ViewGroup$MarginLayoutParams
如果自定义 layout 是直接继承的 ViewGroup , childView 的默认 LayoutParams 就是 ViewGroup.LayoutParams
如果想要转换成 MarginLayoutParams 需要重写如下方法:
override fun generateLayoutParams(attrs: AttributeSet?): LayoutParams {return MarginLayoutParams(context, attrs)}override fun generateLayoutParams(lp: LayoutParams?): LayoutParams {return MarginLayoutParams(lp)}override fun generateDefaultLayoutParams(): LayoutParams {return MarginLayoutParams(LayoutParams.WRAP_CONTENT, LayoutParams.WRAP_CONTENT)}
参考链接
踩坑记录
自定义 Layout 中, findViewById 获得的 View 为 null
原因: 大概因为布局未加载完成
解决方案:
override fun onFinishInflate() {// 将 findViewById 相关的逻辑挪到此处即可}
