これは、これらの一般的に使用されるビュー メソッドが実行される順序です。
1. Constructor // choose your desired size
2. onMeasure // parent will determine if your desired size is acceptable
3. onSizeChanged
4. onLayout
5. onDraw // draw your view content at the size specified by the parent
希望のサイズを選ぶ
ビューが任意のサイズにできるとしたら、どのサイズを選択しますか? これはあなたのwrap_content
サイズであり、カスタム ビューの内容によって異なります。例:
- カスタム ビューが画像の場合、目的のサイズはおそらくビットマップのピクセル寸法にパディングを加えたものになります。(サイズを選択してコンテンツを描画するときに、パディングを計算に組み込むのはユーザーの責任です。)
- カスタム ビューがアナログ時計の場合、目的のサイズは、見栄えの良いデフォルト サイズである可能性があります。
dp
(デバイスのpx
サイズはいつでも取得できます。)
必要なサイズが重い計算を使用する場合は、コンストラクターでそれを行います。それ以外の場合は、で割り当てることができますonMeasure
。( onMeasure
、onLayout
、およびonDraw
は複数回呼び出される可能性があるため、ここで重い作業を行うのはよくありません。)
最終的なサイズの交渉
onMeasure
は、子供が親にどのくらいの大きさになりたいかを伝え、親がそれが許容できるかどうかを決定する場所です. 多くの場合、このメソッドは数回呼び出され、そのたびにさまざまなサイズの要件が渡され、妥協できるかどうかが確認されます。ただし、最終的には、子は親のサイズ要件を尊重する必要があります。
私のセットアップ方法について復習が必要な場合は、常にこの回答に戻りonMeasure
ます。
@Override
protected void onMeasure(int widthMeasureSpec, int heightMeasureSpec) {
int desiredWidth = 100;
int desiredHeight = 100;
int widthMode = MeasureSpec.getMode(widthMeasureSpec);
int widthSize = MeasureSpec.getSize(widthMeasureSpec);
int heightMode = MeasureSpec.getMode(heightMeasureSpec);
int heightSize = MeasureSpec.getSize(heightMeasureSpec);
int width;
int height;
//Measure Width
if (widthMode == MeasureSpec.EXACTLY) {
//Must be this size
width = widthSize;
} else if (widthMode == MeasureSpec.AT_MOST) {
//Can't be bigger than...
width = Math.min(desiredWidth, widthSize);
} else {
//Be whatever you want
width = desiredWidth;
}
//Measure Height
if (heightMode == MeasureSpec.EXACTLY) {
//Must be this size
height = heightSize;
} else if (heightMode == MeasureSpec.AT_MOST) {
//Can't be bigger than...
height = Math.min(desiredHeight, heightSize);
} else {
//Be whatever you want
height = desiredHeight;
}
//MUST CALL THIS
setMeasuredDimension(width, height);
}
上記の例では、目的の幅と高さがデフォルトに設定されています。代わりに、事前に計算して、クラス メンバー変数を使用してここに設定することもできます。
選択したサイズの使用
の後onMeasure
、ビューのサイズがわかります。このサイズは、あなたが要求したものであるかもしれないし、そうでないかもしれませんが、あなたが今取り組まなければならないものです。そのサイズを使用して、 のビューにコンテンツを描画しますonDraw
。
ノート
- 外観に影響するがサイズには影響しない変更をビューに加えるときはいつでも、 を呼び出します
invalidate()
。これによりonDraw
、再度呼び出されます (ただし、他の以前のメソッドのすべてではありません)。
- サイズに影響を与える変更をビューに加えるときはいつでも、 を呼び出します
requestLayout()
。これにより、測定と描画のプロセスが から最初からやり直されonMeasure
ます。通常はへの呼び出しと組み合わせて使用しますinvalidate()
。
- なんらかの理由で適切なサイズを事前に決定できない場合は、@nmw の提案に従って、幅ゼロ、高さゼロを要求するだけでよいと思います。
invalidate()
次に、すべてがロードされた後に(だけでなく) レイアウトを要求します。ただし、ビュー階層全体を 2 回続けて配置する必要があるため、これは少し無駄に思えます。