一緒に書く習慣をつけましょう!「ナゲッツデイリーニュープラン・4月アップデートチャレンジ」に参加して9日目です。クリックしてイベントの詳細をご覧ください。
カスタムビューで、ビューの幅または高さがwrap_contentに設定されていて、処理を行わない場合、最終的な効果はmatch_parentと同じです。この記事では、主にソースコードの観点からこれが発生する理由について説明します。
1.カスタムビューが処理されない場合wrap_content
ビューをカスタマイズするだけです。
class CustomView @JvmOverloads constructor(
context: Context,
attributes: AttributeSet? = null,
defStyleAttr: Int = 0
) : View(context, attributes, defStyleAttr) {
}
复制代码
それぞれxmlで効果を設定math_parent
して確認します。wrap_content
<com.example.gitlinux.CustomView
android:background="#00ff00"
android:layout_width="match_parent"
android:layout_height="100dp"/>
<com.example.gitlinux.CustomView
android:background="#ff0000"
android:layout_width="wrap_content"
android:layout_height="100dp"/>
复制代码
対応する:
ご覧のとおりCustomView
、幅の設定math_parent
とwrap_content
結果は同じですが、なぜこれなのか、ソースコードから答えを見つけましょう
2.View
測定仕様
View
ソースコードを見る前に、まず測定仕様を理解しましょうMeasureSpec
。上位2ビットはを表しMode
、下位30ビットはを表しSize
ます。
MeasureSpec
3つの測定モードがあります。
AT_MOST
親ビューの現在の残りの割り当て済みスペース、Size
サイズは、子ビューのサイズはを超えることはできません。これは、のモードにSize
対応LayoutParams
します。wrap_content
EXACTLY
親ビューによって検出される子ビューの最終的なサイズはSize
、対応するモードと特定LayoutParams
の値です。match_parent
UNSPECIFIED
親ビューにはビューの制限はありません。必要な大きさです。ほとんど使用されません。これを使用して、ビューの実際の幅と高さを取得できます。たとえばScrollView
、この測定モードは、で指定されます。身長。
3.ソースコード検索math_parent
がwrap_content
結果と同じであるのはなぜですか。
首先我们先有个确定的概念:View最终的宽高
MeasureSpec
是由父View的MeasureSpec
和子View的LayoutParam
来决定的。
我们以ViewGroup
的measureChildWithMargins()
方法作为切入口
首先获取子View的LayoutParam
,调用了getChildMeasureSpec()
方法传入了子View的LayoutParam
和父View的宽高的MeasureSpec
:
getChildMeasureSpec()
方法比较长,我们主要截取下其中的关键逻辑:
当父View的测试模式为EXACTLY
时,子View的LayoutParam
如果为具体数值和match_parent
,则子View的MeasureSpec
测量规格就为EXACTLY
,否则为AT_MOST
当父View的测试模式为AT_MOST
时,子View的LayoutParam
如果为wrap_content
和match_parent
,则子View的MeasureSpec
测量规格就为AT_MOST
,否则为EXACTLY
。
我们用一个表格直观的看下子View的MeasureSpec
生成过程:
图片来自于Android进阶基础系列:View的工作原理 全面理解!
现在我们回到文章最开始的那个问题 :如果自定义View的宽度设置为wrap_content
,从上面的表格中可以看出不管父View的测量规格是AT_MOST
还是EXACTLY
,子View最终的宽度大小都是和宽度设置为match_parent
时的大小相同。
最终是怎么设置成子View的宽高大小的呢,具体的源码就不带着分析了,大体的调用逻辑就是:
この
measureChildWithMargins()
メソッドでは、子ビューの幅と高さを取得した後、子ビューの-> -> ->メソッドをMeasureSpec
呼び出し、最後に子ビューの幅と高さの設定を完了します。measure()
onMeasure()
setMeasuredDimension()
setMeasuredDimensionRaw()
3.解決方法math_parent
とwrap_content
同じ結果
これには、ビューをカスタマイズするときに、Viewメソッドを書き直す必要がありますonMeasure()
。このメソッドでは、現在のビューの幅または高さがレイアウトパラメータであるかどうかを判断できますwrap_content
。そうである場合は、必要な実際の幅を手動で計算し、高さ、そしてsetMeasuredDimension()
設定を呼び出します。