カスタム ビューのサイズ変更とレイアウトの問題が発生し続けており、誰かが「ベスト プラクティス」のアプローチを提案できるかどうか疑問に思っています。問題は次のとおりです。コンテンツに必要な高さがビューの幅に依存するカスタム ビューを想像してみてください (複数行の TextView に似ています)。(明らかに、これは高さがレイアウト パラメーターによって固定されていない場合にのみ適用されます。) 問題は、特定の幅に対して、これらのカスタム ビューでコンテンツの高さを計算するのにかなりのコストがかかることです。特に、UI スレッドで計算するにはコストがかかりすぎるため、ある時点でワーカー スレッドを起動してレイアウトを計算し、完了したら UI を更新する必要があります。
問題は、これをどのように設計するかです。いくつかの戦略を考えました。それらはすべて、高さが計算されるたびに、対応する幅が記録されると想定しています。
最初の戦略は、次のコードに示されています。
protected void onMeasure(int widthMeasureSpec, int heightMeasureSpec) {
int width = measureWidth(widthMeasureSpec);
setMeasuredDimension(width, measureHeight(heightMeasureSpec, width));
}
private int measureWidth(int widthMeasureSpec) {
// irrelevant to this problem
}
private int measureHeight(int heightMeasureSpec, int width) {
int result;
int specMode = MeasureSpec.getMode(measureSpec);
int specSize = MeasureSpec.getSize(measureSpec);
if (specMode == MeasureSpec.EXACTLY) {
result = specSize;
} else {
if (width != mLastWidth) {
interruptAnyExistingLayoutThread();
mLastWidth = width;
mLayoutHeight = DEFAULT_HEIGHT;
startNewLayoutThread();
}
result = mLayoutHeight;
if (specMode == MeasureSpec.AT_MOST && result > specSize) {
result = specSize;
}
}
return result;
}
レイアウト スレッドが終了すると、Runnable が UI スレッドにポストさmLayoutHeight
れ、計算された高さに設定されてからrequestLayout()
(and invalidate()
) が呼び出されます。
2 番目の戦略は、 (レイアウト スレッドを起動せずに) その時点onMeasure
の値を常に使用することです。mLayoutHeight
幅の変更のテストとレイアウト スレッドの起動は、オーバーライドによって行われますonSizeChanged
。
3 番目の戦略は、遅延して、(必要に応じて) でレイアウト スレッドを起動するのを待つことonDraw
です。
必要な高さをできるだけ早く計算しながら、レイアウト スレッドが起動および/または強制終了される回数を最小限に抑えたいと考えています。への呼び出しの数も最小限に抑えるとよいでしょうrequestLayout()
。
ドキュメントからonMeasure
、単一のレイアウトの過程で複数回呼び出される可能性があることは明らかです。onSizeChanged
数回呼び出される可能性があることはあまり明確ではありませんが (可能性は高いと思われます) 。ですから、ロジックを入れるonDraw
方がより良い戦略かもしれないと考えています。しかし、それはカスタムビューのサイジングの精神に反しているように見えるので、私はそれに対して明らかに不合理な偏見を持っています.
他の人も同じ問題に直面したに違いありません。私が見逃したアプローチはありますか?最善のアプローチはありますか?