我有一种情况,我想调试TextView.onDraw()
的调用,所以我将其子类化为:
public class MyTextView extends AppCompatTextView {
View parent;
public MyTextView(Context context) {
super(context);
}
public MyTextView(Context context, AttributeSet attrs) {
super(context, attrs);
}
public MyTextView(Context context, AttributeSet attrs, int defStyleAttr) {
super(context, attrs, defStyleAttr);
}
public void storeParent(View parent) {
this.parent = parent;
}
@Override
protected void onDraw(Canvas canvas) {
super.onDraw(canvas);
}
}
并将其放在如下的层次结构中:(请参阅MyTextView
)
<?xml version="1.0" encoding="utf-8"?>
<ScrollView xmlns:android="http://schemas.android.com/apk/res/android"
xmlns:app="http://schemas.android.com/apk/res-auto"
xmlns:tools="http://schemas.android.com/tools"
android:layout_width="match_parent"
android:layout_height="match_parent"
tools:context="com.example.scrollviewtest1.MainActivity">
<LinearLayout
android:id="@+id/scroll_container"
android:orientation="vertical"
android:layout_width="match_parent"
android:layout_height="wrap_content">
<com.example.scrollviewtest1.MyTextView
android:id="@+id/text2"
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:text="@string/large_text" />
<TextView
android:id="@+id/text1"
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:text="Hello World!" />
</LinearLayout>
</ScrollView>
最后,我为此TextView
添加了一段非常大的文本,以便它可以滚动。
现在,如果我在onDraw()
方法中放置一个断点,我只能打一个电话。根据我的理解,当我向上和向下滚动时,我应该打电话给它。为什么会这样?
旁注:我已尝试设置setWillNotDraw(false)
,但结果没有变化。
答案 0 :(得分:0)
@pskink建议关闭H / W加速功能;有效。以下是docs对此的说法:
硬件加速绘图模型
Android系统仍然使用invalidate()和draw()来请求 屏幕更新和渲染视图,但处理实际绘图 不同。而不是立即执行绘图命令, Android系统将它们记录在显示列表中,其中包含 视图层次结构的绘图代码的输出。另一个优化 是Android系统只需要记录和更新显示 由invalidate()调用标记为脏的视图的列表。有的观点 没有失效可以简单地通过重新发布来重绘 以前录制的显示列表。新的绘图模型包含三个 阶段:
Invalidate the hierarchy Record and update display lists Draw the display lists
使用此模型,您不能依赖与脏相交的视图 执行draw()方法的区域。确保Android 系统记录视图的显示列表,必须调用invalidate()。 忘记这样做会导致视图看起来相同,即使它已经存在 已经改变了。
使用显示列表也有利于动画效果,因为 设置特定属性(例如alpha或rotation)不会 要求使目标视图无效(它是自动完成的)。 此优化也适用于具有显示列表的视图(任何视图 当您的应用程序是硬件加速时。)例如,假设 有一个LinearLayout,它包含一个Button上方的ListView。该 LinearLayout的显示列表如下所示:
DrawDisplayList(ListView) DrawDisplayList(Button)
现在假设您要更改ListView的不透明度。后 在ListView上调用setAlpha(0.5f),显示列表现在包含 这样:
SaveLayerAlpha(0.5) DrawDisplayList(ListView) Restore DrawDisplayList(Button)
未执行ListView的复杂绘图代码。相反, 系统只更新了更简单的LinearLayout的显示列表。 在未启用硬件加速的应用程序中,绘图 列表及其父代码再次执行。
<强> VS 强>
基于软件的绘图模型
在软件绘图模型中,使用以下两个绘制视图 步骤进行:
Invalidate the hierarchy Draw the hierarchy
每当应用程序需要更新其UI的一部分时,它就会调用 在任何已更改的视图上invalidate()(或其变体之一) 内容。失效消息一直向上传播 查看层次结构以计算需要的屏幕区域 重绘(脏区)。 Android系统然后绘制任何视图 与脏区域相交的层次结构。不幸, 这个绘图模型有两个缺点:
First, this model requires execution of a lot of code on every draw pass. For example, if your application calls invalidate() on a
按钮,该按钮位于另一个视图Android系统的顶部 即使它没有改变,也会重新绘制视图。 第二个问题是绘图模型可以隐藏应用程序中的错误。由于Android系统会重新绘制视图 与脏区域相交,一个您更改其内容的视图 重新绘制,即使没有调用invalidate()。当这个 发生这种情况,你依赖于另一个无效的视图来获取 正确的行为。每次修改时,此行为都可能会更改 你的申请。因此,你应该总是调用invalidate() 每当修改影响的数据或状态时,在自定义视图上 视图的绘图代码。
注意: Android视图会在属性发生变化时自动调用invalidate(),例如背景颜色或文本中的文本 TextView的。