2013-06-13 3 views
5

私はすぐにオブジェクトの割り当てを行わないことを学び、すべてのペイント割り当てを別のメソッドに移動したカスタムビューを持っています。onDraw()(StaticLayout)でオブジェクトの割り当てを避けますか?

スパニング可能な 'stuff'が適用されているテキストの場合は、StaticLayoutを使用する必要があります。

layoutBpm = new StaticLayout(bpmValue, 
      textPaintBPM, arcRadius, Layout.Alignment.ALIGN_NORMAL, 0, 1, 
      false); 

    layoutBpm.draw(canvas); 

これはonDrawを使用することに意味があるように見えましたが、私はもちろんこれを避けるように警告しています。パフォーマンス上の問題を避けるために私ができることはすべてやっているので、私はこれを正しく実行しようとしています。

StaticLayoutのパラメータのいくつかが実際に何をしているのか理解できているような文書は見つかりませんでした(浮動小数点数spacingmult?float spacingadd?)が、3番目にStaticLayoutの最大幅それは私のキャンバスのサイズに関連してonMeasureからしか得ることができません。これはonMeasureやonDrawに割り当てを入れたいと思っています。どちらもそれが意味するものではありません。 onDrawにStaticLayoutを代入するのは大丈夫ですか?これを行うにはより良い方法がありますか?

これは理にかなっていると思いますが、これは非常に新しいです。何か助けてくれてありがとう。

(編集:?私はこの方法では、この割り当てを入れて、ちょうど愚かされていて、私を警告Eclipseを停止するが、文句を言わない、実際に役立つonDraw/onMeasureから呼び出すと仮定)

答えて

5

とても、ため警告の理由があります多くの場合、描画操作でオブジェクトを何度も再作成する必要はありません。 onDraw()は、Viewの他のメソッドと比較して何百回も呼び出すことができます。ほとんどの場合、再作成されるオブジェクトは、正確なパラメータで再作成されます。それ以外のときは、新しいオブジェクトを作成するよりもオブジェクトの状態を変更するだけのオーバーヘッドが少なくなります。

StaticLayoutの場合は、テキストが変更されたときや、パディング、スペーシング、または最大幅を調整するときに、新しいものを作成する必要があります。テキストが頻繁に変更される場合は、毎回それを再測定するDynamicLayoutと考えてください。再測定は新しいオブジェクトを作成するよりもオーバーヘッドになりますが、onDraw()よりも頻繁に起きることはありません。

テキストが頻繁に変更されず、絶対にStaticLayoutを使用しなければならない場合は、この構造のようなもので逃げることができます。

StaticLayout myLayout; 
String textSource = defaultSource; 
Paint textPaint = defaultPaint; 
int textWidth = defaultWidth; 

public CustomView(Context ctx) { 
    super(ctx); 
    createLayout(); 
} 

public void setText(String text) { 
    textSource = text; 
    createLayout(); 
} 

public void setWidth(int width) { 
    textWidth = width; 
    createLayout(); 
} 

@Override 
public void onDraw(Canvas canvas) { 
    myLayout.draw(canvas); 
} 

private void createLayout() { 
    myLayout = new StaticLayout(textSource, textPaint, textWidth, Layout.Alignment.ALIGN_NORMAL, 0, 1, false); 
} 

基本的には、何か変更があった場合にのみ新しいレイアウトを作成します。そうでなければ、最後に作成したオブジェクトを再利用します。測定パスをスキップする

EDIT:

一つの方法は、新たにリサイズビュー自体にView#measureを呼び出すことです。したがって、あなたのcreateLayout()メソッドは、このようなものになります。

private void createLayout() { 
     myLayout = new StaticLayout(textSource, textPaint, textWidth, Layout.Alignment.ALIGN_NORMAL, 0, 1, false); 
     int textWidthSpec = MeasureSpec.makeMeasureSpec(maxLayoutWidth, MeasureSpec.AT_MOST); 
     int textHeightSpec = MeasureSpec.makeMeasureSpec(maxLayoutHeight, MeasureSpec.AT_MOST); 
     myLayout.measure(textWidthSpec, textHeightSpec); 
     forceLayout(); 
    } 

基本的には、レイアウトの最大値を表示することができます。それはそれ自身を測定し、それは子供です。 forceLayout()は親(カスタムビュー)で呼び出され、新しい測定値に基づいて他のコンテンツを再レイアウトします。

私はこれをStaticLayoutで行ったことがないので、何が起こるか分かりません。このタイプの測定は、ビューが作成されたときにすでに処理されている可能性がありますが、そうでない可能性があります。

こちらがお役に立てば幸いです。

+0

ありがとう、これは私に物を見る少し新しい方法を与えました。私が上記の実装をしている唯一の問題は、 'textPaint'は既に呼び出されている' onMeasure() 'に依存しています(テキストはキャンバスのサイズに従って拡大縮小されます)。' textWidth' )、私は 'createLayout()'をコンストラクタで最初に表示することはできません。私は 'onMeasure()'に置くことができますが、私はそれほど頻繁に呼び出されません。 – Anthony

+0

実際にはテキストが大きく変化します。私が作業しているビューは実際には円形のSeekBarですが、StaticLayoutはSeekBarの進行に関連する中間のテキストに使用されます。円の周りに指をドラッグすると、その値は常に変化します。値が大きく変わっても長さは常に3桁になっているのでレイアウトは決してサイズを調整する必要がないので、StaticLayoutは大丈夫です。静的/動的レイアウトに関するドキュメントはほとんど見つからないので、これが正しいかどうかはわかりません。どんな助けにも感謝します。 – Anthony

+0

最終的には(私は思うが)、onMeasure()を 'onSizeChanged()'に置き換えたのは、私のレイアウトのニーズが単純で、 'onMeasure()'ではなく 'createLayout Lintは何らかの理由で 'onSizeChanged()'でオブジェクトの割り当てを気にしないようですが、 'onMeasure()'ではそれを嫌いです。私はこれら両方の方法が同じ時間量と呼ばれていることを想像しています。それで、なぜそれが1つではなく他の人ではないのか分かりませんが、それは大丈夫です。私の主な関心事は、私が行った 'onDraw()'の割り当てを取り除くことでした。再度、感謝します。 – Anthony

関連する問題