Android 自定义视图未重绘,但正在调用 onDraw
Android custom view not repainting, though onDraw is being called
我有一个名为 ArrowView
的自定义视图。
当此视图是 ArrayAdapter
布局的一部分时,一切都很好。 (它会随着基础数据的变化而重新绘制。)
当我将相同的布局用作另一个 Adapter
的一部分时,ArrowView
不会重新绘制。
我调试了它,发现 onDraw
被调用了 ,rot
的值不同,而我期望它是 - 它是只是屏幕没有更新。
我是否需要更改我的 ArrowView
以使其正确重绘?
public class ArrowView extends View {
private Path path;
public final Paint paint;
public final Paint circlePaint;
private float rot = 30;
private float length = 0.5f;
private float width = 1.0f;
public final static int SIZE = 96;
private float size = SIZE;
private float xOff;
private float yOff;
public ArrowView(Context context, AttributeSet attrs) {
super(context, attrs);
path = new Path();
path.moveTo( 0.0f, -0.5f);
path.lineTo( 0.5f, 0.0f);
path.lineTo( 0.25f, 0.0f);
path.lineTo( 0.25f, 0.5f);
path.lineTo(-0.25f, 0.5f);
path.lineTo(-0.25f, 0.0f);
path.lineTo(-0.5f, 0.0f);
path.close();
paint = new Paint();
paint.setARGB(150, 0, 150, 0);
circlePaint = new Paint();
circlePaint.setARGB(50, 150, 150, 150);
}
@Override
protected void onDraw(Canvas canvas) {
super.onDraw(canvas);
canvas.save();
canvas.translate(xOff, yOff);
canvas.scale(size, size);
canvas.save();
canvas.translate(0.5f, 0.5f);
canvas.drawCircle(-0.0f, -0.0f, 0.5f, circlePaint);
canvas.save();
canvas.rotate(rot, 0.0f, 0.0f);
canvas.save();
canvas.scale(width, length);
canvas.drawPath(path, paint);
canvas.restore();
canvas.restore();
canvas.restore();
canvas.restore();
}
@Override
protected void onMeasure(int widthMeasureSpec, int heightMeasureSpec) {
//Get the width measurement
int widthSize = getMeasurement(widthMeasureSpec,
SIZE);
//Get the height measurement
int heightSize = getMeasurement(heightMeasureSpec,
SIZE);
size = min(widthSize, heightSize) * 0.9f;
xOff = 0.0f;
yOff = 0.05f * size;
//MUST call this to store the measurements
setMeasuredDimension(widthSize, heightSize);
}
public static int getMeasurement(int measureSpec, int contentSize) {
int specMode = View.MeasureSpec.getMode(measureSpec);
int specSize = View.MeasureSpec.getSize(measureSpec);
int resultSize = 0;
switch (specMode) {
case View.MeasureSpec.UNSPECIFIED:
//Big as we want to be
resultSize = contentSize;
break;
case View.MeasureSpec.AT_MOST:
//Big as we want to be, up to the spec
resultSize = min(contentSize, specSize);
break;
case View.MeasureSpec.EXACTLY:
//Must be the spec size
resultSize = specSize;
break;
}
return resultSize;
}
public void setLength(float length) {
this.length = length;
invalidate();
}
public float getLength() {
return length;
}
public void setWidth(float width) {
this.width = width;
invalidate();
}
public void setRot(float rot) {
this.rot = rot;
invalidate();
}
}
如果调用了 onDraw() 但视图没有自行更新,原因可能是在错误的线程上调用了它。
在您的适配器中,请确保从 UI 线程
处理您的视图
getActivity().runOnUiThread(new Runnable() {
@Override
public void run() {
mAdapter.updateRot(newRot);
});
public void updateRot(double newRot){
arrowView.setRot(newRot);
notifyDataSetChanged();
}
从适配器使用notifyDataSetChanged()刷新视图
notifyDataSetChanged(): Notifies the attached observers that the underlying data has been changed and any View reflecting the data set should refresh itself.
当我想从非ui线程和片段更新视图时,我也遇到了同样的问题; invalidate() 方法不更新视图。
所以根据 sdk 参考
http://developer.android.com/intl/es/reference/android/view/View.html
postInvalidate() 将解决问题。
这可以通过两种或更多方式完成!!!
在setter方法中调用runOnUi线程
runOnUiThread(new Runnable() {
public void run() {
this.length = length;
this.invalidate();
}
});
或者在setter方法中调用postInvalidate()
。
我有一个名为 ArrowView
的自定义视图。
当此视图是 ArrayAdapter
布局的一部分时,一切都很好。 (它会随着基础数据的变化而重新绘制。)
当我将相同的布局用作另一个 Adapter
的一部分时,ArrowView
不会重新绘制。
我调试了它,发现 onDraw
被调用了 ,rot
的值不同,而我期望它是 - 它是只是屏幕没有更新。
我是否需要更改我的 ArrowView
以使其正确重绘?
public class ArrowView extends View {
private Path path;
public final Paint paint;
public final Paint circlePaint;
private float rot = 30;
private float length = 0.5f;
private float width = 1.0f;
public final static int SIZE = 96;
private float size = SIZE;
private float xOff;
private float yOff;
public ArrowView(Context context, AttributeSet attrs) {
super(context, attrs);
path = new Path();
path.moveTo( 0.0f, -0.5f);
path.lineTo( 0.5f, 0.0f);
path.lineTo( 0.25f, 0.0f);
path.lineTo( 0.25f, 0.5f);
path.lineTo(-0.25f, 0.5f);
path.lineTo(-0.25f, 0.0f);
path.lineTo(-0.5f, 0.0f);
path.close();
paint = new Paint();
paint.setARGB(150, 0, 150, 0);
circlePaint = new Paint();
circlePaint.setARGB(50, 150, 150, 150);
}
@Override
protected void onDraw(Canvas canvas) {
super.onDraw(canvas);
canvas.save();
canvas.translate(xOff, yOff);
canvas.scale(size, size);
canvas.save();
canvas.translate(0.5f, 0.5f);
canvas.drawCircle(-0.0f, -0.0f, 0.5f, circlePaint);
canvas.save();
canvas.rotate(rot, 0.0f, 0.0f);
canvas.save();
canvas.scale(width, length);
canvas.drawPath(path, paint);
canvas.restore();
canvas.restore();
canvas.restore();
canvas.restore();
}
@Override
protected void onMeasure(int widthMeasureSpec, int heightMeasureSpec) {
//Get the width measurement
int widthSize = getMeasurement(widthMeasureSpec,
SIZE);
//Get the height measurement
int heightSize = getMeasurement(heightMeasureSpec,
SIZE);
size = min(widthSize, heightSize) * 0.9f;
xOff = 0.0f;
yOff = 0.05f * size;
//MUST call this to store the measurements
setMeasuredDimension(widthSize, heightSize);
}
public static int getMeasurement(int measureSpec, int contentSize) {
int specMode = View.MeasureSpec.getMode(measureSpec);
int specSize = View.MeasureSpec.getSize(measureSpec);
int resultSize = 0;
switch (specMode) {
case View.MeasureSpec.UNSPECIFIED:
//Big as we want to be
resultSize = contentSize;
break;
case View.MeasureSpec.AT_MOST:
//Big as we want to be, up to the spec
resultSize = min(contentSize, specSize);
break;
case View.MeasureSpec.EXACTLY:
//Must be the spec size
resultSize = specSize;
break;
}
return resultSize;
}
public void setLength(float length) {
this.length = length;
invalidate();
}
public float getLength() {
return length;
}
public void setWidth(float width) {
this.width = width;
invalidate();
}
public void setRot(float rot) {
this.rot = rot;
invalidate();
}
}
如果调用了 onDraw() 但视图没有自行更新,原因可能是在错误的线程上调用了它。
在您的适配器中,请确保从 UI 线程
处理您的视图 getActivity().runOnUiThread(new Runnable() {
@Override
public void run() {
mAdapter.updateRot(newRot);
});
public void updateRot(double newRot){
arrowView.setRot(newRot);
notifyDataSetChanged();
}
从适配器使用notifyDataSetChanged()刷新视图
notifyDataSetChanged(): Notifies the attached observers that the underlying data has been changed and any View reflecting the data set should refresh itself.
当我想从非ui线程和片段更新视图时,我也遇到了同样的问题; invalidate() 方法不更新视图。 所以根据 sdk 参考
http://developer.android.com/intl/es/reference/android/view/View.html postInvalidate() 将解决问题。
这可以通过两种或更多方式完成!!!
在setter方法中调用runOnUi线程
runOnUiThread(new Runnable() {
public void run() {
this.length = length;
this.invalidate();
}
});
或者在setter方法中调用postInvalidate()
。