我有一个自定义 View ,我很快学会了不进行对象分配,并将所有Paint分配都移到了另一种方法中,很好。

但是,对于某些应用了一些跨度“填充”的文本,我需要使用StaticLayout。

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

    layoutBpm.draw(canvas);

在onDraw中,这对我来说似乎很有意义,但是我当然会被警告避免这种情况。对我来说,重要的是我会尽一切可能避免任何性能问题,因此我正在尝试正确地做到这一点。

我似乎找不到任何我能理解的文档,该文档解释了StaticLayout实际执行的某些参数(float intervalmult?float intervaladd?),但是我认为其中的第三个参数是StaticLayout文本的最大宽度,我只能从onMeasure获得,因为它与我的 Canvas 大小有关。这让我想将任务放在onMeasure或onDraw中,这似乎都不是我要做的。可以将StaticLayout分配放在onDraw上吗?或者有更好的方法吗?

希望这是有道理的,我对此很陌生。感谢您的任何帮助。

(编辑:我假设将这种分配放在一个方法中,并从onDraw/onMeasure调用只是愚蠢的,并且会停止Eclipse警告我,但实际上没有帮助吗?)

最佳答案

警告的原因是,通常,您不需要在绘制操作中多次重新创建对象。与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 本身上调用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();
    }

基本上,这是告诉布局View的最大数量。它会衡量自己,并且是 child 。将在父级(您的自定义 View )上调用forceLayout(),该父级将根据新的度量重新布局其他内容。

我应该注意,我从未使用StaticLayout做到这一点,所以我不知道会发生什么。似乎在创建 View 时可能已经处理了这种类型的测量,但也许没有。

我希望这有帮助。

10-04 19:46