TextView:onDraw只被调用一次

时间:2017-10-28 08:24:19

标签: java android textview android-custom-view

我有一种情况,我想调试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),但结果没有变化。

1 个答案:

答案 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的。