开发者

Events of more instances of the same custom View

开发者 https://www.devze.com 2023-02-22 01:30 出处:网络
I\'m new with Android. In my project I have the custom View MyView with the follow code public class MyView extends View {

I'm new with Android. In my project I have the custom View MyView with the follow code

public class MyView extends View {

    private final Bitmap baseBitmap = BitmapFactory.decodeResource(
            getResources(), R.drawable.myImage);
    private final Matrix matrix;
    private boolean active = true;

    public MyView(Context context, Matrix matrix) {
        super(context);
        this.matrix = matrix;
        this.setFocusable(true);
    }

    @Override
    protected void onDraw(Canvas canvas) {
        super.onDraw(canvas);   
        if (active) {
            System.out.println("draw "+this.getId());
            canvas.drawBitmap(baseBitmap, matrix, null);
        } else {
        ...
        }
    }


    @Override
    public boolean onTouchEvent(MotionEvent event) {
        if (event.getAction() == MotionEvent.ACTION_DOWN) {
            System.out.println("--------->"+this.getId());
        } else if (event.getAction() == MotionEvent.ACTION_MOVE) {
            this.matrix.setTranslate(event.getX()-(baseBitmap.getWidth()/2), event.getY()-(baseBitmap.getHeight()/2));
            this.invalidate();
        } else if (event.getAction() == MotionEvent.ACTION_UP) {

            this.active = false;
        }
        return true;
    }

In my Activity, I instantiate MyView many times and then add them to the main layout. This is its code:

public class MyActivity extends Activity {
  @Override
  public void onCreate(Bundle savedInstanceState) {
      super.onCreate(savedInstanceState);
      Display display = getWindowManager().getDefaultDisplay();
      float cx = display.getWidth() / 2, cy = display.getHeight() / 2;
      int radius = 80;
      double distance = 0, distancePoint = 0;
      final int flags = PathMeasure.POSITION_MATRIX_FLAG
            | PathMeasure.TANGENT_MATRIX_FLAG;
      float length = 0;
      setContentView(R.layout.main);
      RelativeLayout mainLayout = (RelativeLayout) findViewById(R.id.main_view);
      Path pathCircle = new Path();
      pathCircle.addCircle(cx, cy, radius, Direction.CW);
      PathMeasure meas = new PathMeasure(pathCircle, false);
      int nObject = 10;
      length = meas.getLength();
      distance = length/nObject;
      int i = 0;        
            while(i<nObject){
                Matrix m = new Matrix();
                meas.getMatrix((float)distancePoint, m, flags);
                MyView myView = new MyView(this, m);
                System.out.println(myView.toString());
                myView.setId(i);
                mainLayout.addView(myView,i);
                i++;
                distancePoint = distance*i;
            }
      }                               
}

At runtime, when I touch any MyView element I always get the last. With "System.out.println("--------->"+this.getId());" I can see that the id of the touched element is always the last, even if I toch the first or any other element. Actualy, I just can move the last element.

Does anyone know why can't I get the event of the right istance of MyView touched?

(I hope my question is clear)

Thanks


I changed the code adding the onMeasure method. I used the code of a tutorial, dimensions are not specific for my image. The views are drawn and the result is the same, unfortunately with the same problem. I post the layout xml too, maybe could be useful.

    public class MyActivity extends Activity {
  @Override
  public void onCreate(Bundle savedInstanceState) {
      super.onCreate(savedInstanceState);
      Display display = getWindowManager().getDefaultDisplay();
      float cx = display.getWidth() / 2, cy = display.getHeight() / 2;
      int radius = 80;
      double distance = 0, distancePoint = 0;
      final int flags = PathMeasure.POSITION_MATRIX_FLAG
            | PathMeasure.TANGENT_MA开发者_JS百科TRIX_FLAG;
      float length = 0;
      setContentView(R.layout.main);
      RelativeLayout mainLayout = (RelativeLayout) findViewById(R.id.main_view);
      Path pathCircle = new Path();
      pathCircle.addCircle(cx, cy, radius, Direction.CW);
      PathMeasure meas = new PathMeasure(pathCircle, false);
      int nObject = 10;
      length = meas.getLength();
      distance = length/nObject;
      int i = 0;        
            while(i<nObject){
                Matrix m = new Matrix();
                meas.getMatrix((float)distancePoint, m, flags);
                MyView myView = new MyView(this, m);
                System.out.println(myView.toString());
                myView.setId(i);
                nt spec = MeasureSpec.makeMeasureSpec(MeasureSpec.UNSPECIFIED, MeasureSpec.UNSPECIFIED);
                      myView.measure(spec, spec);
                mainLayout.addView(myView,i);
                i++;
                distancePoint = distance*i;
            }
      }                               
}


public class MyView extends View {

    private final Bitmap baseBitmap = BitmapFactory.decodeResource(
            getResources(), R.drawable.myImage);
    private final Matrix matrix;
    private boolean active = true;

    public MyView(Context context, Matrix matrix) {
        super(context);
        this.matrix = matrix;
        this.setFocusable(true);
    }

    @Override
    protected void onDraw(Canvas canvas) {
        super.onDraw(canvas);   
        if (active) {
            System.out.println("draw "+this.getId());
            canvas.drawBitmap(baseBitmap, matrix, null);
        } else {
        ...
        }
    }


    @Override
    public boolean onTouchEvent(MotionEvent event) {
        if (event.getAction() == MotionEvent.ACTION_DOWN) {
            System.out.println("--------->"+this.getId());
        } else if (event.getAction() == MotionEvent.ACTION_MOVE) {
            this.matrix.setTranslate(event.getX()-(baseBitmap.getWidth()/2), event.getY()-(baseBitmap.getHeight()/2));
            this.invalidate();
        } else if (event.getAction() == MotionEvent.ACTION_UP) {

            this.active = false;
        }
        return true;
    }


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

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

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

            int chosenWidth = chooseDimension(widthMode, widthSize);
            int chosenHeight = chooseDimension(heightMode, heightSize);

            int chosenDimension = Math.min(chosenWidth, chosenHeight);

            setMeasuredDimension(chosenDimension, chosenDimension);
        }

        private int chooseDimension(int mode, int size) {
            if (mode == MeasureSpec.AT_MOST || mode == MeasureSpec.EXACTLY) {
                return size;
            } else { // (mode == MeasureSpec.UNSPECIFIED)
                return getPreferredSize();
            } 
        }

        // in case there is no size specified
        private int getPreferredSize() {
            return 300;
        }
}

The main.xml:

<?xml version="1.0" encoding="utf-8"?>
<RelativeLayout 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">
  </RelativeLayout>


I'm pretty sure that it's because you're basically piling up your views at the top left corner of your RelativeLayout. So, only the uppermost (the last one added) is touchable.

I think that if you try adding them to a LinearLayout, as a test, you'll see that your view works. Setting LayoutParams for a RelativeLayout programmatically is not very comfy IMHO.

EDIT

I tried your code. The fact is that your views are just made to be drawn one over the other, or else the overall drawing wouldn't come, so my first guess is right (the uppermost covers the others - even in its transparent parts)(btw try Hierarchy Viewer and you can see that yourself). So you need to do your job in a single view, or handle the touches like this:

@Override
public boolean onTouchEvent(MotionEvent event) {
    if (event.getAction() == MotionEvent.ACTION_DOWN) {
        if(!isPetaloTouched()) {// check if the actual drawing was touched
            return false; // discard the event so that it reaches
                          // the underlying view
        }
//......

See this post for an explanation of how events work in Android.

Both ways would need an isPetaloTouched() logic to detect if/which drawing must be moved, but the first would be more efficient of course.

Also, forget about the onMeasure() thing, I thought that could help giving the view a size around which to wrap, so that it wouldn't fill its parent and aligning views aside would make sense. However, be sure that the touch would work if the views were not piled up.

(...allora mPetali stava proprio per petali!)

0

精彩评论

暂无评论...
验证码 换一张
取 消