警告的原因是,您通常不需要在绘制操作中多次重新创建对象。与View 中的其他方法相比,onDraw() 可以被调用数百次。大多数时候,正在重新创建的对象是使用确切的参数重新创建的。其他时候,更改对象状态的开销比创建新对象要少。
在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();
}
基本上,它的作用是告诉布局 View 可以达到的最大值。它会衡量自己和孩子。 forceLayout() 将在父级(您的自定义视图)上调用,它将根据新测量重新布局其他内容。
我应该注意,我从来没有用 StaticLayout 做过这个,所以我不知道会发生什么。似乎在创建视图时可能已经处理了这种类型的测量,但可能没有。
我希望这会有所帮助。