如何随时在视图上绘制形状和线条?
How to draw shapes and lines on a View whenever I want?
"Whenever I want" 我的意思是当用户单击按钮或发生某种事件时或在 onCreate
中我可以在上面绘制新内容...我找到了一些教程,他们说我应该创建一个自定义视图并覆盖 onDraw
。所以我尝试了以下方法:
public class CanvasView extends View {
private Canvas canvas;
private Paint paint;
public Canvas getCanvas() {
return canvas;
}
public Paint getPaint () {
return paint;
}
public CanvasView (Context c) {
super(c);
paint = new Paint ();
paint.setColor (Color.BLACK);
paint.setStrokeWidth (5);
}
public CanvasView(Context context, AttributeSet attrs) {
super (context, attrs);
paint = new Paint ();
paint.setColor (Color.BLACK);
paint.setStrokeWidth (5);
}
public CanvasView(Context context, AttributeSet attrs, int defStyleAttr) {
super (context, attrs, defStyleAttr);
paint = new Paint ();
paint.setColor (Color.BLACK);
paint.setStrokeWidth (5);
}
@Override
protected void onDraw (Canvas c) {
canvas = c;
}
}
也许是我太天真了。我添加了一个名为 canvas
的字段并添加了一个 getter。如您所见,在 onDraw
方法中,我将 canvas 参数分配给该字段。然后在 onCreate
方法中我这样做了:
canvas = (CanvasView)findViewById (R.id.canvas);
canvas.getCanvas ().drawLine (100, 100, 500, 100, canvas.getPaint ());
我觉得我的所作所为真的很傻。无论如何,我 运行 我的应用程序和... NPE!我推断 canvas.getCanvas()
为空。
所以这个方法不行。我的代码有什么问题?如果我不应该这样做,我可以使用哪些其他视图来随时在上面绘制东西?
您写道:
And then in the onCreate method I did this:
canvas = (CanvasView)findViewById (R.id.canvas);
canvas.getCanvas ().drawLine (100, 100, 500, 100, canvas.getPaint ());
您需要在 onDraw(...)
中完成绘图。将 canvas.drawline(...)
移至该方法。
做 canvas.drawLine(...)
而不是 canvas.getCanvas().drawLine(...)
。
您需要初始化您的 Paint
实例。不要做 canvas.getPaint()
。创建一个字段 mPaint
并在构造函数中初始化它。
有关完整的工作示例,请参阅 Android 开发人员,自定义绘图:
http://developer.android.com/training/custom-views/custom-drawing.html
我想到了一个解决方案,而且很有效!我删除了自定义视图中的 Canvas
字段以及 Paint
字段。然后我创建了一个名为 Shape
:
的接口
public interface Shape {
void draw (Canvas c);
}
这是新的 CanvasView
class:
import android.content.Context;
import android.graphics.Canvas;
import android.util.AttributeSet;
import android.view.View;
import java.util.ArrayList;
public class CanvasView extends View {
private ArrayList<Shape> shapes;
public CanvasView (Context c) {
super(c);
init ();
}
public CanvasView(Context context, AttributeSet attrs) {
super (context, attrs);
init ();
}
public CanvasView(Context context, AttributeSet attrs, int defStyleAttr) {
super (context, attrs, defStyleAttr);
init ();
}
private void init () {
shapes = new ArrayList<> ();
}
@Override
protected void onDraw (Canvas c) {
super.onDraw (c);
for (Shape s : shapes) {
s.draw (c);
}
}
public void addShape (Shape s) {
shapes.add (s);
}
public void clear () {
shapes.clear ();
}
}
如您所见,class 有一个需要绘制的形状数组列表。我们可以像这样实现 draw 方法来画一条线:
canvas.addShape (new Shape () {
@Override
public void draw(Canvas c) {
Paint p = new Paint ();
p.setColor (Color.BLACK);
p.setStrokeWidth (5);
c.drawLine (100, 100, 500, 100, p);
}
});
我认为这是一个很好的方法。它基本上使用接口作为 "delegate" 在 canvas 上绘制形状。当调用 onDraw
时,它会在 Canvas
上绘制 ArrayList
中的所有形状。哦,引用类型之美!
"Whenever I want" 我的意思是当用户单击按钮或发生某种事件时或在 onCreate
中我可以在上面绘制新内容...我找到了一些教程,他们说我应该创建一个自定义视图并覆盖 onDraw
。所以我尝试了以下方法:
public class CanvasView extends View {
private Canvas canvas;
private Paint paint;
public Canvas getCanvas() {
return canvas;
}
public Paint getPaint () {
return paint;
}
public CanvasView (Context c) {
super(c);
paint = new Paint ();
paint.setColor (Color.BLACK);
paint.setStrokeWidth (5);
}
public CanvasView(Context context, AttributeSet attrs) {
super (context, attrs);
paint = new Paint ();
paint.setColor (Color.BLACK);
paint.setStrokeWidth (5);
}
public CanvasView(Context context, AttributeSet attrs, int defStyleAttr) {
super (context, attrs, defStyleAttr);
paint = new Paint ();
paint.setColor (Color.BLACK);
paint.setStrokeWidth (5);
}
@Override
protected void onDraw (Canvas c) {
canvas = c;
}
}
也许是我太天真了。我添加了一个名为 canvas
的字段并添加了一个 getter。如您所见,在 onDraw
方法中,我将 canvas 参数分配给该字段。然后在 onCreate
方法中我这样做了:
canvas = (CanvasView)findViewById (R.id.canvas);
canvas.getCanvas ().drawLine (100, 100, 500, 100, canvas.getPaint ());
我觉得我的所作所为真的很傻。无论如何,我 运行 我的应用程序和... NPE!我推断 canvas.getCanvas()
为空。
所以这个方法不行。我的代码有什么问题?如果我不应该这样做,我可以使用哪些其他视图来随时在上面绘制东西?
您写道:
And then in the onCreate method I did this: canvas = (CanvasView)findViewById (R.id.canvas); canvas.getCanvas ().drawLine (100, 100, 500, 100, canvas.getPaint ());
您需要在
onDraw(...)
中完成绘图。将canvas.drawline(...)
移至该方法。做
canvas.drawLine(...)
而不是canvas.getCanvas().drawLine(...)
。您需要初始化您的
Paint
实例。不要做canvas.getPaint()
。创建一个字段mPaint
并在构造函数中初始化它。
有关完整的工作示例,请参阅 Android 开发人员,自定义绘图: http://developer.android.com/training/custom-views/custom-drawing.html
我想到了一个解决方案,而且很有效!我删除了自定义视图中的 Canvas
字段以及 Paint
字段。然后我创建了一个名为 Shape
:
public interface Shape {
void draw (Canvas c);
}
这是新的 CanvasView
class:
import android.content.Context;
import android.graphics.Canvas;
import android.util.AttributeSet;
import android.view.View;
import java.util.ArrayList;
public class CanvasView extends View {
private ArrayList<Shape> shapes;
public CanvasView (Context c) {
super(c);
init ();
}
public CanvasView(Context context, AttributeSet attrs) {
super (context, attrs);
init ();
}
public CanvasView(Context context, AttributeSet attrs, int defStyleAttr) {
super (context, attrs, defStyleAttr);
init ();
}
private void init () {
shapes = new ArrayList<> ();
}
@Override
protected void onDraw (Canvas c) {
super.onDraw (c);
for (Shape s : shapes) {
s.draw (c);
}
}
public void addShape (Shape s) {
shapes.add (s);
}
public void clear () {
shapes.clear ();
}
}
如您所见,class 有一个需要绘制的形状数组列表。我们可以像这样实现 draw 方法来画一条线:
canvas.addShape (new Shape () {
@Override
public void draw(Canvas c) {
Paint p = new Paint ();
p.setColor (Color.BLACK);
p.setStrokeWidth (5);
c.drawLine (100, 100, 500, 100, p);
}
});
我认为这是一个很好的方法。它基本上使用接口作为 "delegate" 在 canvas 上绘制形状。当调用 onDraw
时,它会在 Canvas
上绘制 ArrayList
中的所有形状。哦,引用类型之美!