Счетчик увеличения / уменьшения при нажатии кнопки - PullRequest
2 голосов
/ 21 октября 2011

Я хочу повернуть картинку (растровое изображение в пределах ImageView) вокруг его центра.Это работает очень хорошо, используя метод preRotate со значениями ширины / 2 и высоты / 2 растрового изображения и 1 или -1 градуса в качестве коэффициента поворота.

Но я реализовал функции поворота в виде кнопок.Каждый раз, когда нажимается кнопка «Повернуть вправо», ImageView поворачивается на один градус вправо и так далее.Было бы неплохо нажать кнопку, и пока кнопка нажата, изображение начинает вращаться до тех пор, пока кнопка не будет отпущена.

Я читал некоторые темы, в которых эта функция реализована как OnTouchListener вместо OnClickListener, ноу меня не работает.Если я реализую циклы в событии MotionEvent.ACTION_DOWN, то они бесконечны.Если я не использую циклы, то событие обрабатывается только один раз (как в OnClickListener).

Так как я могу увеличить / уменьшить коэффициент вращения, пока нажата кнопка?

Ответы [ 3 ]

9 голосов
/ 21 октября 2011

Краткий ответ: Вам нужно реализовать соответствующий MotionEvent.ACTION_UP, чтобы остановить добавление. ACTION_DOWN срабатывает только один раз, когда пользователь нажимает. Вот почему, когда вы не зацикливались, у вас был только один шаг. Что вам нужно, это отдельный поток, чтобы начать делать приращения, когда MotionEvent.ACTION_DOWN сделано, и остановить их, когда MotionEvent.ACTION_UP запущен. Нечто подобное должно работать.

public MyActivity extends Activity{


  private bool continueIncrementing;
  private Runnable incrementerThread;

  //put this OnTouchListener on your button
   View.OnTouchListener downListener = new View.OnTouchListner(){
     public onTouch(View v, MotionEvent event){
       if(event == MotionEvent.ACTION_DOWN){
         startIncrmenting();
       }
       else if(event == MotionEvent.ACTION_UP){
         stopIncrementing();
       }
     }
   };

   private void startIncrmenting(){
     setIsIncrementing(true);
     new Thread(new Runnable() {
       public void run() {
         while(isIncrementing()){
          //do incrementing in here
         }
       }
     }).start();
   }

   sychronized private void stopIncrmenting(){
     setIsIncrementing(false);
   }


   sychronized private bool isIncrmenting(){
     return continueIncrementing;
   }

   synhronized void setIsIncrmenting(bool newSetting){
     continueIncrementing = newSetting;
   }


  //rest of your activity

}
8 голосов
/ 27 сентября 2013

Я расширил ответ Кникеди на более общий случай.Надеюсь, это кому-нибудь поможет.

import android.view.MotionEvent;
import android.view.View;

public abstract class OnTouchContinuousListener implements View.OnTouchListener {

  private final int mInitialRepeatDelay;
  private final int mNormalRepeatDelay;
  private View mView;

  /**
   * Construct listener with default delays
   */
  public OnTouchContinuousListener() {
    this.mInitialRepeatDelay = 500;
    this.mNormalRepeatDelay = 200;
  }

  /**
   * 
   * Construct listener with configurable delays
   * 
   * 
   * @param initialRepeatDelay
   *          delay to the first repeat in millis
   * @param normalRepeatDelay
   *          delay to subsequent repeats in millis
   */
  public OnTouchContinuousListener(int initialRepeatDelay, int normalRepeatDelay) {
    this.mInitialRepeatDelay = initialRepeatDelay;
    this.mNormalRepeatDelay = normalRepeatDelay;
  }

  private final Runnable repeatRunnable = new Runnable() {
    @Override
    public void run() {

      // as long the button is press we continue to repeat
      if (mView.isPressed()) {

        // Fire the onTouchRepeat event
        onTouchRepeat(mView);

        // Schedule the repeat
        mView.postDelayed(repeatRunnable, mNormalRepeatDelay);
      }
    }
  };

  /**
   * Called when a touch event is dispatched to a view. This allows listeners to
   * get a chance to respond before the target view.
   * 
   * @param v
   *          The view the touch event has been dispatched to.
   * @param event
   *          The MotionEvent object containing full information about the
   *          event.
   * @return True if the listener has consumed the event, false otherwise.
   */
  @Override
  public boolean onTouch(View v, MotionEvent event) {
    if (event.getAction() == MotionEvent.ACTION_DOWN) {
      mView = v;

      // Fire the first touch straight away
      onTouchRepeat(mView);

      // Start the incrementing with the initial delay
      mView.postDelayed(repeatRunnable, mInitialRepeatDelay);
    }

    // don't return true, we don't want to disable buttons default behavior
    return false;
  }

  /**
   * Called when the target item should be changed due to continuous touch. This
   * happens at first press, and also after each repeat timeout. Releasing the
   * touch will stop the repeating.
   * 
   */
  public abstract void onTouchRepeat(View view);

}
2 голосов
/ 21 октября 2011

Предположим, button является приватным участником, поэтому вы можете получить к нему доступ в работающем члене. Это то, что я бы попробовал. Вы можете использовать System.currentTimeMillis() для точного и временного расчета значения вращения.

Вот идея (осторожно, не проверена и написана без IDE):

private Runnable rotationRunnable = new Runnable() {
    @Override
    public void run() {
        // perform rotation step here

        // as long the button is press we fire the rotation again
        if (button.isPressed()) {
            button.postDelayed(rotationRunnable, 40);
        }
    }
};

// in onCreate
button.setOnTouchListener(new OnTouchListener() {
    @Override
    public boolean onTouch(View v, MotionEvent event) {
        if (event.getAction() == MotionEvent.ACTION_DOWN) {
            // inital start of rotation
            v.post(rotationRunnable);
        }

        // don't return ture, we don't want to disable buttons default behavior
        return false;
    }
});
Добро пожаловать на сайт PullRequest, где вы можете задавать вопросы и получать ответы от других членов сообщества.
...