Android view.invalidate() 的奇怪行为
Strange behavior with Android view.invalidate()
我在 LinearLayout 中垂直放置了 3 个自定义视图,它们用于显示不同的动态信息,因此它们应该在不同的时间失效和重绘。但是我发现视图失效超出了通常的预期,即:如果您使顶部视图失效,则所有 3 个视图同时失效,如果您使中间视图失效,则中间和底部视图都失效,顶部视图不是,如果你使底部视图无效,只有底部视图本身无效,这就是我想要的,那么前两种情况发生了什么?我搜索并得到了类似的问题,例如:
Android Invalidate() only single view
不过好像没有确切的答案。我 post 我的代码在这里,欢迎任何评论。
TestView.java
package com.vrb.myview;
import android.app.Activity;
import android.os.Bundle;
import android.view.View;
public class TestView extends Activity {
@Override
protected void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
setContentView(R.layout.main);
}
public void onTest(View view){
MyView1 mv1 = (MyView1)findViewById(R.id.mv1);
MyView1 mv2 = (MyView1)findViewById(R.id.mv2);
MyView1 mv3 = (MyView1)findViewById(R.id.mv3);
mv1.invalidate(); // all 3 views are invalidated
// mv2.invalidate(); // mv2 and mv3 are invalidated
// mv3.invalidate(); // only mv3 is invalidated,this is what I want
}
}
MyView1.java
package com.vrb.myview;
import java.util.Random;
import android.content.Context;
import android.graphics.Canvas;
import android.graphics.Color;
import android.graphics.Paint;
import android.graphics.Rect;
import android.util.AttributeSet;
import android.util.Log;
import android.view.View;
public class MyView1 extends View {
Rect rc=null;
Paint p=null;
Random r;
public MyView1(Context ctx){
super(ctx);
rc = new Rect();
p = new Paint();
r = new Random();
}
public MyView1(Context ctx, AttributeSet set){
super(ctx, set);
rc = new Rect();
p = new Paint();
r = new Random();
}
public void onDraw(Canvas canvas){
if(canvas.getClipBounds(rc)){
Log.d("MyView1","id="+getId()+" Rect: "+rc.left+","+rc.top+","+rc.right+","+rc.bottom);
p.setColor(Color.argb(0xff, Math.abs(r.nextInt())%255, Math.abs(r.nextInt())%255, Math.abs(r.nextInt())%255));
canvas.drawRect(rc, p);
}else{
Log.d("MyView1","id="+getId()+" Rect=null");
}
}
}
main.xml
<LinearLayout xmlns:android="http://schemas.android.com/apk/res/android"
xmlns:tools="http://schemas.android.com/tools"
android:layout_width="match_parent"
android:layout_height="match_parent"
android:id="@+id/root"
android:orientation="vertical"
tools:context="com.vrb.myview.TestView" >
<com.vrb.myview.MyView1
android:layout_width="match_parent"
android:layout_height="100px"
android:id="@+id/mv1" />
<com.vrb.myview.MyView1
android:layout_width="match_parent"
android:layout_height="100px"
android:id="@+id/mv2" />
<com.vrb.myview.MyView1
android:layout_width="match_parent"
android:layout_height="100px"
android:id="@+id/mv3" />
<Button
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:layout_gravity="center"
android:text="Invalidate"
android:onClick="onTest"
android:id="@+id/btn" />
</LinearLayout>
您不应依赖调用 onDraw()
的次数或时间来了解视图的内部状态。将 p.setColor()
调用移至单独的 public 方法,并在其末尾调用 invalidate()
。例如:
public class MyView1 extends View {
...
public void changePaint() {
p.setColor(Color.argb(0xff, Math.abs(r.nextInt()) % 255, Math.abs(r.nextInt()) % 255, Math.abs(r.nextInt()) % 255));
invalidate();
}
}
然后在您的 onTest()
方法中:
public void onTest(View view) {
MyView1 mv1 = (MyView1)findViewById(R.id.mv1);
...
mv1.changePaint();
...
}
我在 LinearLayout 中垂直放置了 3 个自定义视图,它们用于显示不同的动态信息,因此它们应该在不同的时间失效和重绘。但是我发现视图失效超出了通常的预期,即:如果您使顶部视图失效,则所有 3 个视图同时失效,如果您使中间视图失效,则中间和底部视图都失效,顶部视图不是,如果你使底部视图无效,只有底部视图本身无效,这就是我想要的,那么前两种情况发生了什么?我搜索并得到了类似的问题,例如:
Android Invalidate() only single view
不过好像没有确切的答案。我 post 我的代码在这里,欢迎任何评论。
TestView.java
package com.vrb.myview;
import android.app.Activity;
import android.os.Bundle;
import android.view.View;
public class TestView extends Activity {
@Override
protected void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
setContentView(R.layout.main);
}
public void onTest(View view){
MyView1 mv1 = (MyView1)findViewById(R.id.mv1);
MyView1 mv2 = (MyView1)findViewById(R.id.mv2);
MyView1 mv3 = (MyView1)findViewById(R.id.mv3);
mv1.invalidate(); // all 3 views are invalidated
// mv2.invalidate(); // mv2 and mv3 are invalidated
// mv3.invalidate(); // only mv3 is invalidated,this is what I want
}
}
MyView1.java
package com.vrb.myview;
import java.util.Random;
import android.content.Context;
import android.graphics.Canvas;
import android.graphics.Color;
import android.graphics.Paint;
import android.graphics.Rect;
import android.util.AttributeSet;
import android.util.Log;
import android.view.View;
public class MyView1 extends View {
Rect rc=null;
Paint p=null;
Random r;
public MyView1(Context ctx){
super(ctx);
rc = new Rect();
p = new Paint();
r = new Random();
}
public MyView1(Context ctx, AttributeSet set){
super(ctx, set);
rc = new Rect();
p = new Paint();
r = new Random();
}
public void onDraw(Canvas canvas){
if(canvas.getClipBounds(rc)){
Log.d("MyView1","id="+getId()+" Rect: "+rc.left+","+rc.top+","+rc.right+","+rc.bottom);
p.setColor(Color.argb(0xff, Math.abs(r.nextInt())%255, Math.abs(r.nextInt())%255, Math.abs(r.nextInt())%255));
canvas.drawRect(rc, p);
}else{
Log.d("MyView1","id="+getId()+" Rect=null");
}
}
}
main.xml
<LinearLayout xmlns:android="http://schemas.android.com/apk/res/android"
xmlns:tools="http://schemas.android.com/tools"
android:layout_width="match_parent"
android:layout_height="match_parent"
android:id="@+id/root"
android:orientation="vertical"
tools:context="com.vrb.myview.TestView" >
<com.vrb.myview.MyView1
android:layout_width="match_parent"
android:layout_height="100px"
android:id="@+id/mv1" />
<com.vrb.myview.MyView1
android:layout_width="match_parent"
android:layout_height="100px"
android:id="@+id/mv2" />
<com.vrb.myview.MyView1
android:layout_width="match_parent"
android:layout_height="100px"
android:id="@+id/mv3" />
<Button
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:layout_gravity="center"
android:text="Invalidate"
android:onClick="onTest"
android:id="@+id/btn" />
</LinearLayout>
您不应依赖调用 onDraw()
的次数或时间来了解视图的内部状态。将 p.setColor()
调用移至单独的 public 方法,并在其末尾调用 invalidate()
。例如:
public class MyView1 extends View {
...
public void changePaint() {
p.setColor(Color.argb(0xff, Math.abs(r.nextInt()) % 255, Math.abs(r.nextInt()) % 255, Math.abs(r.nextInt()) % 255));
invalidate();
}
}
然后在您的 onTest()
方法中:
public void onTest(View view) {
MyView1 mv1 = (MyView1)findViewById(R.id.mv1);
...
mv1.changePaint();
...
}