Custom object click issue in android

2019-04-28 22:43发布

问题:

I have created an custom view in android to display ball on screen. Now what I want is when I touch on that ball it should explode in four parts and every part should move different four directions ie up, down, left, right. I know I have to set touch listener to detect touch on ball but then how to create a explode effect?This issue is solved now. I'm displaying multiple balls on screen so that user can click on it and explode them.

Here is my custom view:

public class BallView extends View {
    private float x;
    private float y;
    private final int r;
    public BallView(Context context, float x1, float y1, int r) {
        super(context);
        this.x = x1;
        this.y = y1;
        this.r = r;
    }
    @Override
    protected void onDraw(Canvas canvas) {
        super.onDraw(canvas);
        canvas.drawCircle(x, y, r, mPaint);
    }

}

SmallBall with similar properties except one that is direction and an explode method to move it in direction and animation flag to stop it moving.

private final int direction;
private boolean anim;

public void explode() {
    // plus or minus x/y based on direction and stop animation if anim flag is false
    invalidate();
}

My layout xml is as follows:

<?xml version="1.0" encoding="utf-8"?>
<FrameLayout android:id="@+id/main_view"
      xmlns:android="http://schemas.android.com/apk/res/android"
      android:layout_width="fill_parent"
      android:layout_height="fill_parent"
      android:background="#FF66FF33" />

I'm adding BallView and SmallBall to activity class as follows:

final FrameLayout mainFrameLayout = (FrameLayout) findViewById(R.id.main_frame_layout);

SmallBall[] smallBalls = new SmallBall[4];
smallBalls[0] = new SmallBall(getApplicationContext(), 105, 100, 10, 1, false);
smallBalls[0].setVisibility(View.GONE);
mainFrameLayout .addView(smallBalls[0]);
// create and add other 3 balls with different directions.

BallView ball = new BallView(getApplicationContext(), 100, 100, 25, smallBalls);
listener = new MyListener(ball);
ball.setOnClickListener(listener);

mainFrameLayout.addView(ball);

I'm adding multiple BallView and their relative SmallBall array at different positions. Now what happens no matter where I click on screen last added BallView starts to explode. After that second last, and so on. So here are 2 issues:

  1. Why it call onClick/onTouch event no matter where I click on screen? It should only call listener event when I click on particular BallView.
  2. And second is why BallView starts exploding in reverse manner of how they are added to layout?

My listener class:

public void onClick(View v) {
        BallView ballView = (BallView) v;
        ballView.setVisibility(View.GONE);
        //get small balls associated with this ball.
        //loop through small ball and call their explode method.
    }

I've trimmed code due to character limitation in question.

回答1:

I don't think you need to hardcode all this in a canvas. You can call ball.setVisibility(View.GONE) in the Touch Listener and show 4 extra balls by using smallBall.setVisibility(View.Visible) for every small ball. This way you'd be able to hide big ball and can show small balls. Now for the movement effect, there can be a method in every smallBall where the direction needs to be passed and you can call it like this smallBall.explode(direction). The method implementation could be

explode(int direction){//can be String
  if(direction=NORTH)
     y--;
  //other condition checks
}

The explode method will start changing their x and y coordinate, based on the direction passed. I hope this'll give you a hint about how to implement it.



回答2:

OK, the problem is during the creation of BallView and SmalBall as View objects. I think I can fully explain this well enough, so bear with me:

A good place to start is with a layered cake. Think about standing in the kitchen and making a cake like this: adding one layer at a time. First the chocolate layer, and then the vanilla layer and then another chocolate layer. Sound good? Alright.

So, there are a lot of circles being drawn on a Canvas and seperately, Ball objects are added as Views. Note a Canvas simply represents a rectangle the user can interact with, and is associated with a View-- the FrameLayout in your code. For all intents and purposes, the Canvas is completely filling the FrameLayout. In your app, the Canvas is the bottom layer of the cake-- filling both the width and height of the ContentView (or pan).

Every call to m.addView(View v) is essentially placing a new View v on top of however many View objects are already contained in m. In terms of cake, every call to addView is adding another layer to our layer cake.

In your project, you want to add a layer to the cake but not have it fill up the entire pan. You want to put a couple strawberries on top, you don't want a full layer of strawberry.

So, by default, your BallView objects are taking up the entire screen. Each on is piling on top of the next, filling up the entire canvas. When you click, it deletes the last one-- because the last one is on top, and is taking up the width and height of the entire canvas-- and is actually the only ball that the user can possibly click on.

So you have to tell your BallView View objects to be the same size as the circle you are drawing on the Canvas object.

So, there are a couple issues here:

You can only do absolute positioning with a RelativeLayout. If you want the BallView the user can click on to be on top of the circle being drawn on the canvas, you need a way to tell the BallView where it is located, and change that position dynamically. Currently you are using a FrameLayout, which is necessary for the Canvas-- so in your XML, add a full screen <RelativeLayout>. And then, in your code, add the BallView objects to this RelativeLayout instead.

and then, FINALLY:

Go here:

Set the absolute position of a view

Good luck!



回答3:

This all thing is happening because you are not specifying LayoutParameters of Ball object. What happens here is when you add a Ball object to Layout it takes space of whole layout and that's why it reacts to click on anywhere on screen.

Now for the second issue, the reason is same. Assume situation of plates, it always pops out in LIFO manner. Here all Ball object covers whole screen so consider them as plates, so what you are doing is putting plates on top of eachother. And that's why it react to onClick method of last ball first and then second last and so on.

So your both issue will be solved after setting proper Layout parameters to Ball objects.