Android: одновременное нажатие кнопок - PullRequest
1 голос
/ 25 декабря 2010

Я видел это на других платформах (особенно на iPhone / iPad), но не смог найти-выяснить-выяснить для Android, и другие платформы, похоже, не намного продвинулись, чем задавать вопрос.

У меня есть игра, в которой есть многопользовательский компонент, в котором два игрока должны одновременно нажимать кнопки на одном экране.Все, кроме одновременного нажатия кнопок, выполняется.

На данный момент кажется, что Android вызывает кнопку onTouchEvent и, поскольку она обрабатывается, она не вызывает другую кнопку.Как вы думаете, что-то вроде вызова обеих кнопок (если касание находится внутри области кнопки) будет работать?Есть ли какой-нибудь другой способ, которым это могло бы быть реализовано?

Спасибо за ваше время.


Anwser:
В итоге я реализовал две различные точки касания в функции onTouchEvent в Activity.

Базовая реализация:

public class MainClass extends Activity { 
// ...
btn1 = (CustomButton)findViewById(R.id.button_one);
btn2 = (CustomButton)findViewById(R.id.button_one);
btn1.ignoreMotionEvent(true);
btn2.ignoreMotionEvent(true);
// ...

@Override
public boolean onTouchEvent(MotionEvent event)
{
    if(r1 == null)
    {
        //r1 and r2 are Rect that define the absolute region of the button.
        //They are both defined here to ensure that the everything will be layed out (didn't always work so just for extra "sure-ness" did it here)
    }
    CustomButton btn = null;
    MotionEvent mevent = null;
    switch(event.getAction())
    {
        case MotionEvent.ACTION_DOWN:
        case MotionEvent.ACTION_UP:
            int x = (int)event.getX();
            int y = (int)event.getY();
            if(r1.contains(x, y))
            {
                btn = btn1;
            }
            else if(r2.contains(x, y))
            {
                btn = btn2;
            }
            if(btn != null)
            {
                mevent = event;
            }
            break;
    }
    if(btn != null)
    {
        btn.ignoreMotionEvent(false);
        btn.onTouchEvent(mevent);
        btn.ignoreMotionEvent(true);
    }
    return super.onTouchEvent(event);
}
}

CustomButton - это просто расширенная версия Button, где существует метод ignoreMotionEvent, он просто устанавливает логическое значение, определяющее, должна ли функция onTouchEvent CustomButton немедленно возвращать false или вызывать super.onTouchEvent.

К сожалению, если вы попробуете этот код, он не будет работать.Так зачем это упоминать?Это основной набросок кода.Проблема, с которой я столкнулся, заключалась в том, что в Android 1.6 и более ранних версиях этой функции не было.Эклер и выше требуются, чтобы сделать эту работу.

Теперь просто, чтобы выручить любого, кто нашел это, потому что у них была та же самая проблема, вот почти точная копия того, что я бегу:

public class MainClass extends Activity { 
// ...
btn1 = (CustomButton)findViewById(R.id.button_one);
btn2 = (CustomButton)findViewById(R.id.button_one);
btn1.ignoreMotionEvent(true);
btn2.ignoreMotionEvent(true);
// ...

@Override
public boolean onTouchEvent(MotionEvent event)
{
    if(r1 == null)
    {
        //r1 and r2 are Rect that define the absolute region of the button.
        //They are both defined here to ensure that the everything will be layed out (didn't always work so just for extra "sure-ness" did it here)
    }
    if(Utils.isEclairOrLater())
    {
        //Eclair and later
        boolean froyo = Utils.isFroyoOrLater();
        int action = froyo ? event.getActionMasked() : event.getAction();
        CustomButton btn = null;
        MotionEvent mevent = null;
        switch(action & MotionEvent.ACTION_MASK)
        {
            case MotionEvent.ACTION_DOWN:
            case MotionEvent.ACTION_UP:
                int x = (int)event.getX();
                int y = (int)event.getY();
                if(r1.contains(x, y))
                {
                    btn = btn1;
                }
                else if(r2.contains(x, y))
                {
                    btn = btn2;
                }
                if(btn != null)
                {
                    mevent = event;
                }
                break;
            case MotionEvent.ACTION_POINTER_DOWN:
            case MotionEvent.ACTION_POINTER_UP:
                int index = froyo ? event.getActionIndex() : ((action & MotionEvent.ACTION_POINTER_ID_MASK) >> MotionEvent.ACTION_POINTER_ID_SHIFT);
                x = (int)event.getX(index);
                y = (int)event.getY(index);
                if(r1.contains(x, y))
                {
                    btn = btn1;
                }
                else if(r2.contains(x, y))
                {
                    btn = btn2;
                }
                if(btn != null)
                {
                    mevent = MotionEvent.obtain(event.getDownTime(), event.getEventTime(), (action & MotionEvent.ACTION_MASK) == MotionEvent.ACTION_POINTER_DOWN ? MotionEvent.ACTION_DOWN : MotionEvent.ACTION_UP, event.getX(index), event.getY(index), 0);
                }
                break;
        }
        if(btn != null)
        {
            btn.ignoreMotionEvent(false);
            btn.onTouchEvent(mevent);
            btn.ignoreMotionEvent(true);
        }
    }
    else
    {
        //Earlier then Eclair
        CustomButton btn = null;
        MotionEvent mevent = null;
        switch(event.getAction())
        {
            case MotionEvent.ACTION_DOWN:
            case MotionEvent.ACTION_UP:
                int x = (int)event.getX();
                int y = (int)event.getY();
                if(r1.contains(x, y))
                {
                    btn = btn1;
                }
                else if(r2.contains(x, y))
                {
                    btn = btn2;
                }
                if(btn != null)
                {
                    mevent = event;
                }
                break;
        }
        if(btn != null)
        {
            btn.ignoreMotionEvent(false);
            btn.onTouchEvent(mevent);
            btn.ignoreMotionEvent(true);
        }
    }
    return super.onTouchEvent(event);
}
}

Utils - это простой служебный класс, который для целей данного примера получает значение Build.VERSION.SDK_INT и сравнивает его с Eclair (5) и Froyo (8) для соответствующих функций.

Также требуется компиляция с 2.2 или выше.Если вы не знаете, Android совместим в обратном направлении, если вы проверяете отсутствие функций из-за различий в версиях.Это означает, что, хотя вы компилируете с 2.2, он будет работать до 1.0.

Это то, что я использую, и, надеюсь, это поможет другим.

Ответы [ 2 ]

0 голосов
/ 24 августа 2012

Попробуйте мой MultitouchActivity http://www.passsy.de/multitouch-for-all-views/

0 голосов
/ 25 декабря 2010

Если у вас есть две разные кнопки, вы можете прикрепить onTouchListeners к каждой, а затем сделать так, чтобы вызов onTouch отправлял сообщение в вашу основную деятельность, указывающее, что кнопка была нажата. Грубо говоря:

public class MainClass extends Activity implements Handler.Callback {
handler = new Handler(this);
// ...
((Button) findViewById(R.id.button_one)).setOnTouchListener(new OnTouchListener() {
  @Override
  public boolean onTouch(View v, MotionEvent event) {
    handler.sendEmptyMessage(BUTTON_ONE);
    return true;
  }
});
((Button) findViewById(R.id.button_two)).setOnTouchListener(new OnTouchListener() {
  @Override
  public boolean onTouch(View v, MotionEvent event) {
    handler.sendEmptyMessage(BUTTON_TWO);
    return true;
  }
});

public boolean handleMessage(Message msg) {
  if (msg.what == BUTTON_ONE) {
    mButtonOnePressed = System.nanoTime();
    checkIfBothPressed();
  } else if (msg.what == BUTTON_TWO) {
    mButtonTwoPressed = System.nanoTime();
    checkIfBothPressed();
  }
}

public void checkIfBothPressed() {
  if (Math.abs(mButtonOnePressed - mButtonTwoPressed) < 1000000) {
    // They pressed the buttons within one second
  }
}
}

(приведенный выше код не протестирован или не завершен.)

Если они касаются двух разных точек в одном представлении, вы можете перебирать события с помощью event.getX (index) и event.getY (i). Смотрите event.getPointerCount (). (Извините, для этого примера нет кода, в основном потому, что я думаю, что подход с двумя разными кнопками лучше. :))

...