カスタムビューがwrap_contentを処理する必要があるのはなぜですか

一緒に書く習慣をつけましょう!「ナゲッツデイリーニュープラン・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"/>
复制代码

対応する:

image.png

ご覧のとおりCustomView、幅の設定math_parentwrap_content結果は同じですが、なぜこれなのか、ソースコードから答えを見つけましょう

2.View測定仕様

Viewソースコードを見る前に、まず測定仕様を理解しましょうMeasureSpec。上位2ビットはを表しMode、下位30ビットはを表しSizeます。
MeasureSpec3つの測定モードがあります。

  • AT_MOST親ビューの現在の残りの割り当て済みスペース、Sizeサイズは、子ビューのサイズはを超えることはできません。これは、のモードにSize対応LayoutParamsします。wrap_content
  • EXACTLY親ビューによって検出される子ビューの最終的なサイズはSize、対応するモードと特定LayoutParamsの値です。match_parent
  • UNSPECIFIED親ビューにはビューの制限はありません。必要な大きさです。ほとんど使用されません。これを使用して、ビューの実際の幅と高さを取得できます。たとえばScrollView、この測定モードは、で指定されます。身長。

3.ソースコード検索math_parentwrap_content結果と同じであるのはなぜですか。

首先我们先有个确定的概念:View最终的宽高MeasureSpec是由父View的MeasureSpec和子View的LayoutParam来决定的。

我们以ViewGroupmeasureChildWithMargins()方法作为切入口

image.png 首先获取子View的LayoutParam,调用了getChildMeasureSpec()方法传入了子View的LayoutParam和父View的宽高的MeasureSpec

getChildMeasureSpec()方法比较长,我们主要截取下其中的关键逻辑:

image.png

image.png
当父View的测试模式为EXACTLY时,子View的LayoutParam如果为具体数值和match_parent,则子View的MeasureSpec测量规格就为EXACTLY,否则为AT_MOST image.png
当父View的测试模式为AT_MOST时,子View的LayoutParam如果为wrap_contentmatch_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_parentwrap_content同じ結果

これには、ビューをカスタマイズするときに、Viewメソッドを書き直す必要がありますonMeasure()。このメソッドでは、現在のビューの幅または高さがレイアウトパラメータであるかどうかを判断できますwrap_content。そうである場合は、必要な実際の幅を手動で計算し、高さ、そしてsetMeasuredDimension()設定を呼び出します。

おすすめ

転載: juejin.im/post/7084826230285369357
おすすめ