Android 在onDraw()中避免对象分配(StaticLayout)?
我有一个自定义视图,我很快就学会了不在其中进行对象分配,并将所有绘制分配移动到另一个方法中,很好 我需要使用StaticLayout,但是对于一些应用了可扩展的“东西”的文本Android 在onDraw()中避免对象分配(StaticLayout)?,android,ondraw,Android,Ondraw,我有一个自定义视图,我很快就学会了不在其中进行对象分配,并将所有绘制分配移动到另一个方法中,很好 我需要使用StaticLayout,但是对于一些应用了可扩展的“东西”的文本 layoutBpm = new StaticLayout(bpmValue, textPaintBPM, arcRadius, Layout.Alignment.ALIGN_NORMAL, 0, 1, false); layoutBpm.draw(canva
layoutBpm = new StaticLayout(bpmValue,
textPaintBPM, arcRadius, Layout.Alignment.ALIGN_NORMAL, 0, 1,
false);
layoutBpm.draw(canvas);
这对我来说似乎是有道理的,但我当然被警告要避免这样做。对我来说,尽我所能避免任何性能问题是很重要的,所以我正在努力正确地做到这一点
我似乎找不到任何我能理解的文档来解释StaticLayout的一些参数实际上做了什么(float spacingmult?float spacingadd?),但第三个我认为是StaticLayout文本的最大宽度,我只能从onMeasure中获得,因为它与我的画布大小有关。这让我想把作业放在测量或onDraw中,这两个似乎都不是我应该做的。在onDraw中放置StaticLayout赋值可以吗?或者有更好的方法来实现这一点吗
希望这是有意义的,我对这很陌生。谢谢你的帮助
(编辑:我假设将此赋值放在方法中并从onDraw/onMeasure调用是愚蠢的,会停止Eclipse警告我,但实际上没有帮助?发出警告的原因是,通常情况下,您不需要在绘制操作中多次重新创建对象<与
视图中的其他方法相比,code>onDraw()
可以被调用数百次。大多数情况下,正在重新创建的对象都是使用精确的参数重新创建的。其他时候,更改对象状态的开销比创建新对象的开销要小
对于静态布局
,您只需要在文本更改或调整填充、间距或最大宽度时创建新布局。如果文本经常改变,那么您可能需要考虑<代码>动态布局> /代码>,它将每次重新测量自身。重新测量要比创建新对象花费更多的开销,但它发生的频率不可能比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);
}
基本上,只有在某些内容发生更改时才创建新布局。否则,只需重复使用上次创建的对象
编辑:
跳过测量过程的一种方法是对新调整大小的视图本身调用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(),该父级将根据新的测量值重新布局其他内容
我应该注意到,我从来没有用静态布局做过这件事,所以我不知道会发生什么。在创建视图时,似乎已经处理了这种类型的度量,但可能没有
我希望这有帮助 谢谢,这给了我一种稍微新的看待事物的方式。实现上述功能的唯一问题是
textPaint
依赖于已调用的onMeasure()
(文本根据画布大小进行缩放),以及textWidth
(确定文本何时换行),因此我无法执行createLayout()
在构造函数中首次查看。我可以把它放在onMeasure()
替换为onSizeChanged()
,因为我的布局需求很简单,并将对createLayout()
的初始调用放在那里,而不是onMeasure()
。出于某种原因,Lint似乎不介意在onSizeChanged()
中分配对象,但不喜欢在onMeasure()中分配对象。我想这两种方法被调用的次数是一样的,所以我不知道为什么其中一种方法是好的,而另一种方法是不好的,但不管怎样,这似乎是好的。我主要关心的是如何从我已经完成的onDraw()
中获得分配。再次感谢。我很高兴你设法使一些东西起作用,但这里有一些注释。皮棉警告被编程为简单的常见错误。仅仅因为你没有得到警告并不意味着它是好的。另一方面,仅仅因为你得到了警告并不意味着它是坏的。这只不过是一个建议。onSizeChanged()实际上不会被调用太多,因为只有在onMeasure()中记录了不同的度量时才会调用它。另一方面,onMeasure会为树中的每个视图调用,甚至可能更多。无论大小是否改变。可以在不经过onMeasure()过程的情况下重新测量布局。基本上,对于新的测量,您在视图上调用View#measure()
,视图本身将重新测量。但是,不同之处在于父视图中的其他元素将保持不变。如果出现问题,则需要调用布局过程来重新调整视图中的其他图元。我已经用我的意思更新了答案。