android 几个自定义视图的 onclick 问题

android onclick for several custom Views issue

早上好,我正在一个 ralativeLayout 中绘制 9 个自定义视图。

然后我想为每个视图分配点击侦听器。

问题是当我点击其中一个视图时,我得到了对最后绘制的视图的引用,即使我实际上点击了第一个。

这是我的代码:

public class MainActivity extends Activity {

MySurfaceView view;
RelativeLayout layout;
List<CustomCircles> circlesArr;

@Override
protected void onCreate(Bundle savedInstanceState) {
    super.onCreate(savedInstanceState);

    setContentView(R.layout.activity_main);

    layout = (RelativeLayout) findViewById(R.id.relativeLayout);

    ViewTreeObserver vto = layout.getViewTreeObserver();
    vto.addOnGlobalLayoutListener(new ViewTreeObserver.OnGlobalLayoutListener() {

        @Override
        public void onGlobalLayout() {
            layout.getViewTreeObserver().removeOnGlobalLayoutListener(this);

            int width = layout.getMeasuredWidth();
            int height = layout.getMeasuredHeight();

            int radius = calculateCircleRadius(height);
            calculateCirclesPosition(radius);
        }
    });
}

int circlesPerRow = 3;
int rows = 3;

 private void calculateCirclesPosition(int radius) {

    int index = 0;
    circlesArr = new ArrayList<CustomCircles>();

    for (int i = 0; i < rows; ++i) {
        int y = radius + ((radius * 2) * i);
        RelativeLayout.LayoutParams params = null;
        if(i == 0) {
            params = new RelativeLayout.LayoutParams(
                    LayoutParams.WRAP_CONTENT, LayoutParams.WRAP_CONTENT);
            params.addRule(RelativeLayout.ALIGN_PARENT_TOP);
        } else if(i == 1) {
            params = new RelativeLayout.LayoutParams(
                    LayoutParams.WRAP_CONTENT, LayoutParams.WRAP_CONTENT);
            params.addRule(RelativeLayout.BELOW, circlesArr.get(0).id);
        } else if(i == 2) {
            params = new RelativeLayout.LayoutParams(
                    LayoutParams.WRAP_CONTENT, LayoutParams.WRAP_CONTENT);
            params.addRule(RelativeLayout.BELOW, circlesArr.get(3).id);
        }


        for (int j = 0; j < circlesPerRow; ++j) {

            int x = radius + ((radius * 2) * j);
            Punto centro = new Punto(x, y);
            Cerchio cerchio = new Cerchio(centro, radius);
            cerchio.indexInArray = index;

            CirclesHandler.get().getCircleList().add(cerchio);

            CustomCircles circle = new CustomCircles(this, centro,
                    radius, index++);
            circle.setTag("circle" + index);

            Log.v("jajaja", "setted index is "+ index);

            circlesArr.add(circle);

            if(j == 0) {
                params.addRule(RelativeLayout.ALIGN_PARENT_LEFT);
            } else {
                params = new RelativeLayout.LayoutParams(
                        LayoutParams.WRAP_CONTENT, LayoutParams.WRAP_CONTENT);
                params.addRule(RelativeLayout.RIGHT_OF, circlesArr.get(j-1).getId());
            }

            layout.addView(circle, params); 
        }
    }
}

private int calculateCircleRadius(int height) {
    return (height / 3) / 2;
}
}

CustomCircleViewClass

public class CustomCircles extends View implements View.OnClickListener {

Punto centro;
Paint paint;
int radius;
int id;

public CustomCircles(Context context, Punto centro, int radius, int id) {
    this(context);
    this.centro = centro;
    this.radius = radius;
    this.id = id;
    //setId(id);
}

public CustomCircles(Context context) {
    super(context);
    init();
}

public CustomCircles(Context context, AttributeSet attrs, int defStyleAttr) {
    super(context, attrs, defStyleAttr);
}

public CustomCircles(Context context, AttributeSet attrs) {
    super(context, attrs);
}

private void init() {

    this.setOnClickListener(this);
    paint = new Paint();
    paint.setColor(Color.parseColor("#000000"));
}

@Override
protected void onDraw(Canvas canvas) {
    super.onDraw(canvas);

    canvas.drawCircle(centro.x, centro.y, radius, paint);
}

@Override
public void onClick(View v) {
    Log.v("jajaja", "Clicked " + this.getTag());
}
}

感谢您的宝贵时间

您将圈子放在 RelativeLayout 中而没有位置选项,这就是为什么它们都可以有 getLeft()==0getTop()==0

对于所有圈子调用View方法setId(index),对于LayoutParams需要添加规则:

params.addRule(RelativeLayout.RIGHT_OF, prevCircle.getId());
params.addRule(RelativeLayout.ALIGN_TOP, prevCircle.getId());

params.addRule(RelativeLayout.BELOW, circleAbove.getId());
params.addRule(RelativeLayout.ALIGN_LEFT, circleAbove.getId());

换一个新的圆圈。

几天后,我尝试改变我的方法,使用 onMeasure() 和 onLayout()。 终于找到了!

我想分享我的代码:

自定义相对布局class:

public class CustomRelativeLayout extends RelativeLayout {

public CustomRelativeLayout(Context context) {
    super(context);
}

public CustomRelativeLayout(Context context, AttributeSet attrs,
        int defStyle) {
    super(context, attrs, defStyle);
}

public CustomRelativeLayout(Context context, AttributeSet attrs) {
    super(context, attrs);
}

@Override
protected void onLayout(boolean changed, int l, int t, int r, int b) {
    for (int i = 0; i < getChildCount(); ++i) {

        View v = getChildAt(i);
        Punto center = ((CustomCircles) v).centro;
        int radius = ((CustomCircles) v).radius;
        v.layout(center.x - radius, center.y - radius, center.x + radius,
                center.y + radius);
    }
}

@Override
protected void onMeasure(int widthMeasureSpec, int heightMeasureSpec) {

    for (int i = 0; i < getChildCount(); ++i) {

        View v = getChildAt(i);
        Punto center = ((CustomCircles)v).centro;
        v.measure(center.x * 2, center.y *2);
    }

      int desiredWidth = 100;
        int desiredHeight = 100;

        int widthMode = MeasureSpec.getMode(widthMeasureSpec);
        int widthSize = MeasureSpec.getSize(widthMeasureSpec);
        int heightMode = MeasureSpec.getMode(heightMeasureSpec);
        int heightSize = MeasureSpec.getSize(heightMeasureSpec);

        int width;
        int height;

        //Measure Width
        if (widthMode == MeasureSpec.EXACTLY) {
            //Must be this size
            width = widthSize;
        } else if (widthMode == MeasureSpec.AT_MOST) {
            //Can't be bigger than...
            width = Math.min(desiredWidth, widthSize);
        } else {
            //Be whatever you want
            width = desiredWidth;
        }

        //Measure Height
        if (heightMode == MeasureSpec.EXACTLY) {
            //Must be this size
            height = heightSize;
        } else if (heightMode == MeasureSpec.AT_MOST) {
            //Can't be bigger than...
            height = Math.min(desiredHeight, heightSize);
        } else {
            //Be whatever you want
            height = desiredHeight;
        }

        setMeasuredDimension(width, height);
}
}

自定义圈子class:

public class CustomCircles extends View implements View.OnClickListener {

Punto centro;
Paint paint;
int radius;
int id;

public CustomCircles(Context context, Punto centro, int radius, int id) {
    this(context);
    this.centro = centro;
    this.radius = radius;
    this.id = id;
}

public CustomCircles(Context context) {
    super(context);
    init();
}

public CustomCircles(Context context, AttributeSet attrs, int defStyleAttr) {
    super(context, attrs, defStyleAttr);
}

public CustomCircles(Context context, AttributeSet attrs) {
    super(context, attrs);
}

private void init() {

    this.setOnClickListener(this);
    paint = new Paint();
    paint.setColor(Color.parseColor("#000000"));
}

@Override
protected void onDraw(Canvas canvas) {
    super.onDraw(canvas);

    canvas.drawCircle(radius, radius, radius, paint);
}

private void changeColor() {
    this.paint.setColor(Color.parseColor("#0000FF"));
    invalidate();

}

@Override
public void onClick(View v) {
    changeColor();
}
}

主要activityclass:

 public class MainActivity extends Activity {

MySurfaceView view;
CustomRelativeLayout layout;
List<CustomCircles> circlesArr;

@Override
protected void onCreate(Bundle savedInstanceState) {
    super.onCreate(savedInstanceState);

    setContentView(R.layout.activity_main);

    layout = (CustomRelativeLayout) findViewById(R.id.customRelativeLayout);

    ViewTreeObserver vto = layout.getViewTreeObserver();
    vto.addOnGlobalLayoutListener(new ViewTreeObserver.OnGlobalLayoutListener() {

        @Override
        public void onGlobalLayout() {
            layout.getViewTreeObserver().removeOnGlobalLayoutListener(this);

            int width = layout.getMeasuredWidth();
            int height = layout.getMeasuredHeight();

            int radius = calculateCircleRadius(height);
            calculateCirclesPosition(radius);
        }
    });
}

int circlesPerRow = 3;
int rows = 3;

private void calculateCirclesPosition(int radius) {

    int index = 0;
    circlesArr = new ArrayList<CustomCircles>();

    for (int i = 0; i < rows; ++i) {
        int y = radius + ((radius * 2) * i);

        for (int j = 0; j < circlesPerRow; ++j) {

            int x = radius + ((radius * 2) * j);
            Punto centro = new Punto(x, y);
            Cerchio cerchio = new Cerchio(centro, radius);
            cerchio.indexInArray = index;

            CirclesHandler.get().getCircleList().add(cerchio);

            CustomCircles circle = new CustomCircles(this, centro,
                    radius, index++);

            circlesArr.add(circle);

            layout.addView(circle); 
        }
    }
}

private int calculateCircleRadius(int height) {
    return (height / 3) / 2;
}
}