События большего количества экземпляров одного и того же пользовательского представления

#android

#Android

Вопрос:

Я новичок в Android. В моем проекте у меня есть пользовательский вид MyView со следующим кодом

 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;
    }
  

В своей деятельности я много раз создаю экземпляр MyView, а затем добавляю их в основной макет. Это его код:

 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;
            }
      }                               
}
  

Во время выполнения, когда я касаюсь любого элемента MyView, я всегда получаю последний. С помощью « System.out.println("--------->" this.getId()); » я вижу, что идентификатор затронутого элемента всегда является последним, даже если я указываю первый или любой другой элемент. На самом деле, я просто могу переместить последний элемент.
Кто-нибудь знает, почему я не могу получить событие правильного изменения MyView?
(Надеюсь, мой вопрос понятен)
Спасибо


Я изменил код, добавив метод onMeasure. Я использовал код из руководства, размеры не являются специфичными для моего изображения. Представления отображаются, и результат тот же, к сожалению, с той же проблемой. Я также публикую XML-макет, возможно, это может быть полезно.

     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);
                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>
  

Ответ №1:

Я почти уверен, что это потому, что вы в основном размещаете свои представления в верхнем левом углу своего RelativeLayout . Таким образом, можно коснуться только самого верхнего (последнего добавленного).

Я думаю, что если вы попытаетесь добавить их в LinearLayout в качестве теста, вы увидите, что ваше представление работает. Программная настройка LayoutParams для RelativeLayout не очень удобна, ИМХО.

Редактировать

Я попробовал ваш код. Дело в том, что ваши представления просто созданы для рисования одно поверх другого, иначе общий рисунок не отображался бы, так что мое первое предположение верно (самый верхний покрывает остальные — даже в его прозрачных частях) (кстати, попробуйте Hierarchy Viewer, и вы сможете убедиться в этом сами). Итак, вам нужно выполнять свою работу в одном представлении или обрабатывать касания следующим образом:

 @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
        }
//......
  

Смотрите этот пост для объяснения того, как события работают в Android.

Для обоих способов потребуется isPetaloTouched() логика, чтобы определить, нужно ли перемещать чертеж, но первый, конечно, был бы более эффективным.

Кроме того, забудьте об onMeasure() этом, я подумал, что это могло бы помочь придать представлению размер, вокруг которого можно обернуть, чтобы оно не заполняло своего родительского элемента, и имело бы смысл выравнивать представления в сторону. Однако убедитесь, что касание сработало бы, если бы представления не были скоплены.

(…allora mPetali stava proprio per petali!)

Комментарии:

1. Используя LinearLayout, я получаю только первое представление, поэтому я попытался использовать RelativeLayout. LayoutParams , поэтому я попытался использовать RelativeLayout. Параметры layout отображаются следующим образом RelativeLayout. LayoutParams параметры = новый RelativeLayout. Параметры компоновки (LayoutParams. FILL_PARENT,LayoutParams. WRAP_CONTENT); if(i>0){ params.addRule(RelativeLayout. ALIGN_LEFT,i-1); } MyView.setLayoutParams (параметры); mainLayout.addView(MyView, i); Но это все еще не работает.

2. @vilandra: в params.addRule() вам нужно передать идентификатор представления (тот, который вы получаете с getId() помощью), а не его индекс в качестве дочернего элемента макета. Возможно, LinearLayout не сработал, потому что вы забыли установить android:orientation="vertical" . Однако, если это все еще не работает, не могли бы вы проверить с помощью Hierarchy Viewer, занимает ли ваше представление все пространство? Затем вам может потребоваться переопределить onMeasure() в вашем пользовательском представлении.

3. @bigstones: Невозможно использовать LinearLayout и вертикальную ориентацию, невозможно переопределить onMeasure(), невозможно сохранить предыдущий объект MyView внутри while и вызвать getId вместо использования индекса (это то же самое, потому что я использую индекс для setId, я полагаю). Я действительно не знаю, в чем может быть проблема. Может быть полезно опубликовать код, включающий метод onMeasure?

4. @vilandra (it's the same thing 'cause I use the index for setId, I suppose) о, извините, я этого не видел. Да, пожалуйста, опубликуйте и этот код, я надеюсь, что смогу помочь.

5. @bigstones: хорошо, мне стыдно за разработчиков! Теперь проблема заключается в том, чтобы узнать фактическое затронутое представление. Я заставил свой View реализовать View. Класс OnTouchListener в конструкторе View установил code this.setOnTouchListener(this) code и в методе onTouch ( code onTouch(View v, событие MotionEvent) code ) проверил полученное представление. Представление всегда является текущим, то есть в моей проблеме представление, переданное в onTouch, всегда является последним, поэтому сравнение между code v.getId() code и code this.getId() code всегда верно. Таким образом, проблема сохраняется. Затем я использовал ViewGroup, который …