创建 2 个自定义视图时,Android 自定义视图上的 onTouchEvent 不起作用
onTouchEvent on Android custom view doesn't work when 2 custom view are created
我的目标是在 Activity 中绘制 3 个相等的自定义视图。自定义视图覆盖 onTouchEvent。如果我通过 XML 或以编程方式在 Activity 中仅添加一个自定义视图,一切正常。如果我添加 2 个自定义视图(相同的自定义视图),则触摸事件仅适用于一个自定义视图,另一个在布局中固定,根本不会拦截任何内容。我看过其他讨论,但找不到问题所在。
我的自定义视图 class:
public class IconCropView extends View {
//contants strings
private static final String TAG = "IconCropView";
private static final int TEXT_COLOR = Color.RED;
private static final float TEXT_SIZE = 30.0f;
private static final float STROKE_WIDTH = 4.0f;
//drawing objects
private Paint paint;
//text
private Paint textPaint;
//point objects
private Point[] points;
private Point start;
private Point offset;
//variable ints
private int altezzaMinima;
private int altezza;
private int halfCorner;
private int cornerColor;
private int edgeColor;
private int outsideColor;
private int corner = 30;
//variable booleans
private boolean initialized = false;
//drawables
private Drawable moveDrawable;
private Drawable resizeDrawable2;
//context
Context context;
//Rect del canvas
Rect cropBorder;
boolean clickInCropRect;
public IconCropView(Context context) {
super(context);
this.context = context;
init(null,null);
}
public IconCropView(Context context, @Nullable AttributeSet attrs) {
super(context, attrs);
this.context = context;
init(attrs,null);
}
public IconCropView(Context context, @Nullable AttributeSet attrs, int defStyleAttr) {
super(context, attrs, defStyleAttr);
this.context = context;
init(attrs,null);
}
public IconCropView(Context context, Point[] punti) {
super(context);
this.context = context;
init(null,punti);
}
private void init(@Nullable AttributeSet attrs,Point[] punti ){
paint = new Paint();
start = new Point();
offset = new Point();
//initial dimensions
altezzaMinima = 400;
altezza = altezzaMinima;
halfCorner = 25;
//colors
cornerColor = Color.BLACK;
edgeColor = Color.WHITE;
outsideColor =Color.parseColor("#00000088");
//initialize corners;
points = new Point[4];
points[0] = new Point();
points[1] = new Point();
points[2] = new Point();
points[3] = new Point();
if(punti == null) {
//init corner locations;
//top left
points[0].x = 0;
points[0].y = 0;
//top right
points[1].x = 600;
points[1].y = 0;
//bottom left
points[2].x = 0;
points[2].y = altezzaMinima;
//bottom right
points[3].x = 600;
points[3].y = altezzaMinima;
}
if(punti != null){
//init corner locations;
//top left
points[0].x = punti[0].x;
points[0].y = punti[0].y;
//top right
points[1].x = punti[1].x;
points[1].y = punti[1].y;
//bottom left
points[2].x = punti[2].x;
points[2].y = punti[2].y;
//bottom right
points[3].x = punti[3].x;
points[3].y = punti[3].y;
}
//init drawables
resizeDrawable2 = getResources().getDrawable(R.drawable.circle);
//set initialized to true
initialized = true;
//inizializzo testo
textPaint = new Paint();
textPaint.setColor(TEXT_COLOR);
textPaint.setTextSize(TEXT_SIZE);
}
@Override
protected void onDraw(Canvas canvas) {
super.onDraw(canvas);
//set paint to draw edge, stroke
if(initialized) {
paint.setAntiAlias(true);
paint.setStyle(Paint.Style.STROKE);
paint.setStrokeJoin(Paint.Join.ROUND);
paint.setColor(edgeColor);
paint.setStrokeWidth(4);
cropBorder = new Rect(points[0].x + halfCorner, points[0].y + halfCorner,points[0].x + halfCorner + 500,points[0].y + halfCorner + altezza);
//crop rectangle
canvas.drawRect(cropBorder, paint);
//set paint to draw outside color, fill
paint.setStyle(Paint.Style.FILL);
paint.setColor(outsideColor);
resizeDrawable2.setBounds(points[2].x, points[2].y, points[2].x + halfCorner*2, points[2].y + halfCorner*2);
//place corner drawable
resizeDrawable2.draw(canvas);
}
}
@Override
public boolean onTouchEvent(MotionEvent event) {
//return super.onTouchEvent(event);
switch(event.getActionMasked()){
case MotionEvent.ACTION_DOWN:{
//get the coordinates
start.x = (int)event.getX();
start.y = (int)event.getY();
//get the corner touched if any
corner = getCorner(start.x, start.y);
//get the offset of touch(x,y) from corner top-left point
offset = getOffset(start.x, start.y, corner);
//account for touch offset in starting point
start.x = start.x - offset.x;
start.y = start.y - offset.y;
// dentro il rettangolo
clickInCropRect = cropBorder.contains( start.x, start.y);
break;
}
case MotionEvent.ACTION_MOVE:{
if(corner == 0 || clickInCropRect ) {
points[0].x = Math.max(points[0].x + (int) Math.min(Math.floor((event.getX() - start.x - offset.x)), Math.floor(getWidth() - points[0].x - 2*halfCorner - (cropBorder.width()))), 0);
points[1].x = Math.max(points[1].x + (int) Math.min(Math.floor((event.getX() - start.x - offset.x)), Math.floor(getWidth() - points[1].x - 2*halfCorner)), altezza);
points[2].x = Math.max(points[2].x + (int) Math.min(Math.floor((event.getX() - start.x - offset.x)), Math.floor(getWidth() - points[2].x - 2*halfCorner - (cropBorder.width()))), 0);
points[3].x = Math.max(points[3].x + (int) Math.min(Math.floor((event.getX() - start.x - offset.x)), Math.floor(getWidth() - points[3].x - 2*halfCorner)), altezza);
points[0].y = Math.max(points[0].y + (int) Math.min(Math.floor((event.getY() - start.y - offset.y)), Math.floor(getHeight() - points[0].y - 2*halfCorner - (cropBorder.height()) )), 0);
points[1].y = Math.max(points[1].y + (int) Math.min(Math.floor((event.getY() - start.y - offset.y)), Math.floor(getHeight() - points[1].y - 2*halfCorner - (cropBorder.height()))), 0);
points[2].y = Math.max(points[2].y + (int) Math.min(Math.floor((event.getY() - start.y - offset.y)), Math.floor(getHeight() - points[2].y - 2*halfCorner)), altezza);
points[3].y = Math.max(points[3].y + (int) Math.min(Math.floor((event.getY() - start.y - offset.y)), Math.floor(getHeight() - points[3].y - 2*halfCorner)), altezza);
start.x = points[0].x+(cropBorder.width()/2);
start.y = points[0].y+(cropBorder.height()/2);
Log.v("TOUCHED", points[0].x + " ");
invalidate();
}
else if (corner == 2){
altezza = Math.min((Math.min((Math.max(altezzaMinima, (int)(altezza + Math.floor(event.getY()) - start.y - offset.y))), altezza + (getHeight() - points[2].y - 2* halfCorner ))), altezza + (getWidth() - points[1].x - 2* halfCorner ));
points[2].y = points[0].y + altezza;
points[3].y = points[0].y + altezza;
points[3].x = points[0].x + altezza;
points[1].x = points[0].x + altezza;
start.y = points[2].y;
invalidate();
}
break;
}
}
return true;
}
private int getCorner(float x, float y){
int corner = 5;
for (int i = 0; i < points.length; i++){
float dx = x - points[i].x;
float dy = y - points[i].y;
int max = halfCorner * 2;
if(dx <= max && dx >= 0 && dy <= max && dy >= 0){
return i;
}
}
return corner;
}
private Point getOffset(int left, int top, int corner){
Point offset = new Point();
if(corner == 5){
offset.x = 0;
offset.y = 0;
}else{
offset.x = left - points[corner].x;
offset.y = top - points[corner].y;
}
return offset;
}
@Override
protected void onMeasure(int widthMeasureSpec, int heightMeasureSpec) {
super.onMeasure(widthMeasureSpec, heightMeasureSpec);
}
}
在 onCreate Activity 中:
IconCropView iconCrop1 = new IconCropView(context);
IconCropView iconCrop2 = new IconCropView(context,punti);
RelativeLayout myLayout = findViewById(R.id.myLayout);
myLayout .addView(iconCrop1);
myLayout .addView(iconCrop2);
我也把它们放在 XML 文件中,但结果是一样的。
我会感谢你的帮助。
谢谢大家
我解决了这个问题。问题不在于 onTouchEvent,而在于定义 IconCropView 的容器。在我简单地定义一个元素并将其添加到布局之前。现在我认为正确的方法是:
- 定义创建 IconCropView 的布局。它应该大于 IconCropview 否则它不能随触摸移动:
RelativeLayout.LayoutParams params = new RelativeLayout.LayoutParams(mImageViewWidth, mImageViewHeight / 4 );
- 定义与其容器相关的 IconCropView 边距。
params.setMargins(marginLeft, marginTop, marginRight, marginBottom);
3)创建新的IconCropView并将其添加到父布局中activity。 Mlayout是activity的主要布局:
IconCropView cropView = new IconCropView(context, width, height);
cropView .setLayoutParams(params);
mLayout.addView(cropView);
我希望这对某人有用。
我的目标是在 Activity 中绘制 3 个相等的自定义视图。自定义视图覆盖 onTouchEvent。如果我通过 XML 或以编程方式在 Activity 中仅添加一个自定义视图,一切正常。如果我添加 2 个自定义视图(相同的自定义视图),则触摸事件仅适用于一个自定义视图,另一个在布局中固定,根本不会拦截任何内容。我看过其他讨论,但找不到问题所在。 我的自定义视图 class:
public class IconCropView extends View {
//contants strings
private static final String TAG = "IconCropView";
private static final int TEXT_COLOR = Color.RED;
private static final float TEXT_SIZE = 30.0f;
private static final float STROKE_WIDTH = 4.0f;
//drawing objects
private Paint paint;
//text
private Paint textPaint;
//point objects
private Point[] points;
private Point start;
private Point offset;
//variable ints
private int altezzaMinima;
private int altezza;
private int halfCorner;
private int cornerColor;
private int edgeColor;
private int outsideColor;
private int corner = 30;
//variable booleans
private boolean initialized = false;
//drawables
private Drawable moveDrawable;
private Drawable resizeDrawable2;
//context
Context context;
//Rect del canvas
Rect cropBorder;
boolean clickInCropRect;
public IconCropView(Context context) {
super(context);
this.context = context;
init(null,null);
}
public IconCropView(Context context, @Nullable AttributeSet attrs) {
super(context, attrs);
this.context = context;
init(attrs,null);
}
public IconCropView(Context context, @Nullable AttributeSet attrs, int defStyleAttr) {
super(context, attrs, defStyleAttr);
this.context = context;
init(attrs,null);
}
public IconCropView(Context context, Point[] punti) {
super(context);
this.context = context;
init(null,punti);
}
private void init(@Nullable AttributeSet attrs,Point[] punti ){
paint = new Paint();
start = new Point();
offset = new Point();
//initial dimensions
altezzaMinima = 400;
altezza = altezzaMinima;
halfCorner = 25;
//colors
cornerColor = Color.BLACK;
edgeColor = Color.WHITE;
outsideColor =Color.parseColor("#00000088");
//initialize corners;
points = new Point[4];
points[0] = new Point();
points[1] = new Point();
points[2] = new Point();
points[3] = new Point();
if(punti == null) {
//init corner locations;
//top left
points[0].x = 0;
points[0].y = 0;
//top right
points[1].x = 600;
points[1].y = 0;
//bottom left
points[2].x = 0;
points[2].y = altezzaMinima;
//bottom right
points[3].x = 600;
points[3].y = altezzaMinima;
}
if(punti != null){
//init corner locations;
//top left
points[0].x = punti[0].x;
points[0].y = punti[0].y;
//top right
points[1].x = punti[1].x;
points[1].y = punti[1].y;
//bottom left
points[2].x = punti[2].x;
points[2].y = punti[2].y;
//bottom right
points[3].x = punti[3].x;
points[3].y = punti[3].y;
}
//init drawables
resizeDrawable2 = getResources().getDrawable(R.drawable.circle);
//set initialized to true
initialized = true;
//inizializzo testo
textPaint = new Paint();
textPaint.setColor(TEXT_COLOR);
textPaint.setTextSize(TEXT_SIZE);
}
@Override
protected void onDraw(Canvas canvas) {
super.onDraw(canvas);
//set paint to draw edge, stroke
if(initialized) {
paint.setAntiAlias(true);
paint.setStyle(Paint.Style.STROKE);
paint.setStrokeJoin(Paint.Join.ROUND);
paint.setColor(edgeColor);
paint.setStrokeWidth(4);
cropBorder = new Rect(points[0].x + halfCorner, points[0].y + halfCorner,points[0].x + halfCorner + 500,points[0].y + halfCorner + altezza);
//crop rectangle
canvas.drawRect(cropBorder, paint);
//set paint to draw outside color, fill
paint.setStyle(Paint.Style.FILL);
paint.setColor(outsideColor);
resizeDrawable2.setBounds(points[2].x, points[2].y, points[2].x + halfCorner*2, points[2].y + halfCorner*2);
//place corner drawable
resizeDrawable2.draw(canvas);
}
}
@Override
public boolean onTouchEvent(MotionEvent event) {
//return super.onTouchEvent(event);
switch(event.getActionMasked()){
case MotionEvent.ACTION_DOWN:{
//get the coordinates
start.x = (int)event.getX();
start.y = (int)event.getY();
//get the corner touched if any
corner = getCorner(start.x, start.y);
//get the offset of touch(x,y) from corner top-left point
offset = getOffset(start.x, start.y, corner);
//account for touch offset in starting point
start.x = start.x - offset.x;
start.y = start.y - offset.y;
// dentro il rettangolo
clickInCropRect = cropBorder.contains( start.x, start.y);
break;
}
case MotionEvent.ACTION_MOVE:{
if(corner == 0 || clickInCropRect ) {
points[0].x = Math.max(points[0].x + (int) Math.min(Math.floor((event.getX() - start.x - offset.x)), Math.floor(getWidth() - points[0].x - 2*halfCorner - (cropBorder.width()))), 0);
points[1].x = Math.max(points[1].x + (int) Math.min(Math.floor((event.getX() - start.x - offset.x)), Math.floor(getWidth() - points[1].x - 2*halfCorner)), altezza);
points[2].x = Math.max(points[2].x + (int) Math.min(Math.floor((event.getX() - start.x - offset.x)), Math.floor(getWidth() - points[2].x - 2*halfCorner - (cropBorder.width()))), 0);
points[3].x = Math.max(points[3].x + (int) Math.min(Math.floor((event.getX() - start.x - offset.x)), Math.floor(getWidth() - points[3].x - 2*halfCorner)), altezza);
points[0].y = Math.max(points[0].y + (int) Math.min(Math.floor((event.getY() - start.y - offset.y)), Math.floor(getHeight() - points[0].y - 2*halfCorner - (cropBorder.height()) )), 0);
points[1].y = Math.max(points[1].y + (int) Math.min(Math.floor((event.getY() - start.y - offset.y)), Math.floor(getHeight() - points[1].y - 2*halfCorner - (cropBorder.height()))), 0);
points[2].y = Math.max(points[2].y + (int) Math.min(Math.floor((event.getY() - start.y - offset.y)), Math.floor(getHeight() - points[2].y - 2*halfCorner)), altezza);
points[3].y = Math.max(points[3].y + (int) Math.min(Math.floor((event.getY() - start.y - offset.y)), Math.floor(getHeight() - points[3].y - 2*halfCorner)), altezza);
start.x = points[0].x+(cropBorder.width()/2);
start.y = points[0].y+(cropBorder.height()/2);
Log.v("TOUCHED", points[0].x + " ");
invalidate();
}
else if (corner == 2){
altezza = Math.min((Math.min((Math.max(altezzaMinima, (int)(altezza + Math.floor(event.getY()) - start.y - offset.y))), altezza + (getHeight() - points[2].y - 2* halfCorner ))), altezza + (getWidth() - points[1].x - 2* halfCorner ));
points[2].y = points[0].y + altezza;
points[3].y = points[0].y + altezza;
points[3].x = points[0].x + altezza;
points[1].x = points[0].x + altezza;
start.y = points[2].y;
invalidate();
}
break;
}
}
return true;
}
private int getCorner(float x, float y){
int corner = 5;
for (int i = 0; i < points.length; i++){
float dx = x - points[i].x;
float dy = y - points[i].y;
int max = halfCorner * 2;
if(dx <= max && dx >= 0 && dy <= max && dy >= 0){
return i;
}
}
return corner;
}
private Point getOffset(int left, int top, int corner){
Point offset = new Point();
if(corner == 5){
offset.x = 0;
offset.y = 0;
}else{
offset.x = left - points[corner].x;
offset.y = top - points[corner].y;
}
return offset;
}
@Override
protected void onMeasure(int widthMeasureSpec, int heightMeasureSpec) {
super.onMeasure(widthMeasureSpec, heightMeasureSpec);
}
}
在 onCreate Activity 中:
IconCropView iconCrop1 = new IconCropView(context);
IconCropView iconCrop2 = new IconCropView(context,punti);
RelativeLayout myLayout = findViewById(R.id.myLayout);
myLayout .addView(iconCrop1);
myLayout .addView(iconCrop2);
我也把它们放在 XML 文件中,但结果是一样的。
我会感谢你的帮助。
谢谢大家
我解决了这个问题。问题不在于 onTouchEvent,而在于定义 IconCropView 的容器。在我简单地定义一个元素并将其添加到布局之前。现在我认为正确的方法是:
- 定义创建 IconCropView 的布局。它应该大于 IconCropview 否则它不能随触摸移动:
RelativeLayout.LayoutParams params = new RelativeLayout.LayoutParams(mImageViewWidth, mImageViewHeight / 4 );
- 定义与其容器相关的 IconCropView 边距。
params.setMargins(marginLeft, marginTop, marginRight, marginBottom);
3)创建新的IconCropView并将其添加到父布局中activity。 Mlayout是activity的主要布局:
IconCropView cropView = new IconCropView(context, width, height);
cropView .setLayoutParams(params);
mLayout.addView(cropView);
我希望这对某人有用。