为什么没有为我设置 OnTouchListener?
Why OnTouchListener is not set for me?
我正在开发一个名为 CanvasView
的自定义视图。这是一个允许我在 onDraw
方法之外绘制内容的视图。它是这样的:
public class CanvasView extends View {
private ArrayList<Shape> shapes;
private Paint paint;
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<> ();
paint = new Paint ();
paint.setStrokeWidth (5);
paint.setColor (Color.BLACK);
}
//focus on this method, I think the others are irrelevant
@Override
public void setOnTouchListener (final OnTouchListener listener) {
final OnTouchListener baseListener = new OnTouchListener () {
@Override
public boolean onTouch(View v, MotionEvent event) {
float x = event.getX ();
float y = event.getY ();
if (x < 18 || x > getWidth () - 18 || y < 18 ||
y > getHeight () - 18)
return false;
return true;
}
};
super.setOnTouchListener (new OnTouchListener () {
@Override
public boolean onTouch(View v, MotionEvent event) {
if (baseListener.onTouch (v, event)) {
if (listener != null) {
return listener.onTouch (v, event);
} else {
return true;
}
}
return false;
}
});
}
@Override
protected void onDraw (Canvas c) {
super.onDraw (c);
for (Shape s : shapes) {
s.draw (c);
}
//draw the border. irrelevant
c.drawLine (3, 3, getWidth () - 3, 3, paint);
c.drawLine (3, getHeight () - 3, getWidth () - 3, getHeight () - 3, paint);
c.drawLine (3, 3, 3, getHeight () - 3, paint);
c.drawLine (getWidth () - 3, 3, getWidth () - 3, getHeight () - 3, paint);
//draw the inner border
c.drawLine (18, 18, getWidth () - 18, 18, paint);
c.drawLine (18, getHeight () - 18, getWidth () - 18, getHeight () - 18, paint);
c.drawLine (18, 18, 18, getHeight () - 18, paint);
c.drawLine (getWidth () - 18, 18, getWidth () - 18, getHeight () - 18, paint);
}
public void addShape (Shape s) {
shapes.add (s);
}
public void clear () {
shapes.clear ();
}
}
解释:
Shape
是一个带有方法的接口:
public void draw (Canvas c);
关注 setOnTouchListener
覆盖。我覆盖了这个方法,因为我想限制用户不要触摸 CanvasView
的边界。如您所见,我首先调用 baseListener
来检查触摸是否在边界内。然后我调用构造函数中传递的侦听器。这是一个好习惯吗?
反正我在onCreate
方法中设置了一个CanvasView
的OnTouchListener
:
canvas.setOnTouchListener (new View.OnTouchListener () {
@Override
public boolean onTouch(View v, final MotionEvent event) {
if (point1 != null && point2 != null) {
throw new IllegalStateException ("Both point1 and point2 are not null");
}
if (point1 == null) {
point1 = new PointF (event.getX (), event.getY ());
} else { //point2 is null
point2 = new PointF (event.getX (), event.getY ());
canvas.addShape (new Shape () {
@Override
public void draw(Canvas c) {
c.drawLine (point1.x, point1.y, point2.x, point2.y, paint);
}
});
canvas.setOnTouchListener (null);
}
canvas.addShape (new Shape () {
@Override
public void draw(Canvas c) {
c.drawCircle (event.getX (), event.getY (), 13, paint);
}
});
return true;
}
});
解释:
point1
和 point2
是在 activity class 中声明的字段。当用户触摸屏幕时,其中一个将被实例化,并在该点绘制一个小圆圈。当用户第二次触摸时,point2
被实例化并在两点之间绘制一条线。
当我 运行 我的应用程序触摸屏幕时,没有绘制任何东西!我认为 setOnClickListener
覆盖写得不正确。谁能告诉我为什么?
视图的onDraw
方法仅在首次创建视图时调用。要再次调用它,您需要在视图上使用 invalidate()
函数将视图标记为“脏”(已进行更改),每次视图内容更改时。
因此,调用此函数的方便位置是在 addShape
函数中向视图添加形状之后。
public void addShape (Shape s) {
shapes.add (s);
this.invalidate();
}
我正在开发一个名为 CanvasView
的自定义视图。这是一个允许我在 onDraw
方法之外绘制内容的视图。它是这样的:
public class CanvasView extends View {
private ArrayList<Shape> shapes;
private Paint paint;
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<> ();
paint = new Paint ();
paint.setStrokeWidth (5);
paint.setColor (Color.BLACK);
}
//focus on this method, I think the others are irrelevant
@Override
public void setOnTouchListener (final OnTouchListener listener) {
final OnTouchListener baseListener = new OnTouchListener () {
@Override
public boolean onTouch(View v, MotionEvent event) {
float x = event.getX ();
float y = event.getY ();
if (x < 18 || x > getWidth () - 18 || y < 18 ||
y > getHeight () - 18)
return false;
return true;
}
};
super.setOnTouchListener (new OnTouchListener () {
@Override
public boolean onTouch(View v, MotionEvent event) {
if (baseListener.onTouch (v, event)) {
if (listener != null) {
return listener.onTouch (v, event);
} else {
return true;
}
}
return false;
}
});
}
@Override
protected void onDraw (Canvas c) {
super.onDraw (c);
for (Shape s : shapes) {
s.draw (c);
}
//draw the border. irrelevant
c.drawLine (3, 3, getWidth () - 3, 3, paint);
c.drawLine (3, getHeight () - 3, getWidth () - 3, getHeight () - 3, paint);
c.drawLine (3, 3, 3, getHeight () - 3, paint);
c.drawLine (getWidth () - 3, 3, getWidth () - 3, getHeight () - 3, paint);
//draw the inner border
c.drawLine (18, 18, getWidth () - 18, 18, paint);
c.drawLine (18, getHeight () - 18, getWidth () - 18, getHeight () - 18, paint);
c.drawLine (18, 18, 18, getHeight () - 18, paint);
c.drawLine (getWidth () - 18, 18, getWidth () - 18, getHeight () - 18, paint);
}
public void addShape (Shape s) {
shapes.add (s);
}
public void clear () {
shapes.clear ();
}
}
解释:
Shape
是一个带有方法的接口:
public void draw (Canvas c);
关注 setOnTouchListener
覆盖。我覆盖了这个方法,因为我想限制用户不要触摸 CanvasView
的边界。如您所见,我首先调用 baseListener
来检查触摸是否在边界内。然后我调用构造函数中传递的侦听器。这是一个好习惯吗?
反正我在onCreate
方法中设置了一个CanvasView
的OnTouchListener
:
canvas.setOnTouchListener (new View.OnTouchListener () {
@Override
public boolean onTouch(View v, final MotionEvent event) {
if (point1 != null && point2 != null) {
throw new IllegalStateException ("Both point1 and point2 are not null");
}
if (point1 == null) {
point1 = new PointF (event.getX (), event.getY ());
} else { //point2 is null
point2 = new PointF (event.getX (), event.getY ());
canvas.addShape (new Shape () {
@Override
public void draw(Canvas c) {
c.drawLine (point1.x, point1.y, point2.x, point2.y, paint);
}
});
canvas.setOnTouchListener (null);
}
canvas.addShape (new Shape () {
@Override
public void draw(Canvas c) {
c.drawCircle (event.getX (), event.getY (), 13, paint);
}
});
return true;
}
});
解释:
point1
和 point2
是在 activity class 中声明的字段。当用户触摸屏幕时,其中一个将被实例化,并在该点绘制一个小圆圈。当用户第二次触摸时,point2
被实例化并在两点之间绘制一条线。
当我 运行 我的应用程序触摸屏幕时,没有绘制任何东西!我认为 setOnClickListener
覆盖写得不正确。谁能告诉我为什么?
视图的onDraw
方法仅在首次创建视图时调用。要再次调用它,您需要在视图上使用 invalidate()
函数将视图标记为“脏”(已进行更改),每次视图内容更改时。
因此,调用此函数的方便位置是在 addShape
函数中向视图添加形状之后。
public void addShape (Shape s) {
shapes.add (s);
this.invalidate();
}