2

In my Android project, I am trying to repeat this code (a function in my MainActivity.class file):

public void positionChange(View v)
{
    findViewById(R.id.player1).setX(findViewById(R.id.player1).getX() - 30);
    findViewById(R.id.player2).setX(findViewById(R.id.player2).getX() + 30);

}

when a button is held.

Currently, this code gets called once per click when the button is pressed using:

android:onClick="positionChange"

in my activity_main.xml file. As I am new to Android programming, I have no idea how to do this, and the existing code that I have found do not seem to work properly, so how could I get this to work?

Thanks.

HF1
  • 385
  • 1
  • 2
  • 14

2 Answers2

2

first of all you must know that every call to findViewById() can waste a big time of your application so you'd better get them once and use them multiple times.

to repeat this code while button is holding you must use below link and use the custom listener this link provides:

Android - Hold Button to Repeat Action

i copy the code for your ease :

import android.os.Handler;
import android.view.MotionEvent;
import android.view.View;
import android.view.View.OnClickListener;
import android.view.View.OnTouchListener;

/**
* A class, that can be used as a TouchListener on any view (e.g. a Button).
* It cyclically runs a clickListener, emulating keyboard-like behaviour. First
* click is fired immediately, next one after the initialInterval, and subsequent
* ones after the normalInterval.
*
* <p>Interval is scheduled after the onClick completes, so it has to run fast.
* If it runs slow, it does not generate skipped onClicks. Can be rewritten to
* achieve this.
*/
public class RepeatListener implements OnTouchListener {

private Handler handler = new Handler();

private int initialInterval;
private final int normalInterval;
private final OnClickListener clickListener;

private Runnable handlerRunnable = new Runnable() {
    @Override
    public void run() {
        handler.postDelayed(this, normalInterval);
        clickListener.onClick(downView);
    }
};

private View downView;

/**
 * @param initialInterval The interval after first click event
 * @param normalInterval The interval after second and subsequent click 
 *       events
 * @param clickListener The OnClickListener, that will be called
 *       periodically
 */
public RepeatListener(int initialInterval, int normalInterval, 
        OnClickListener clickListener) {
    if (clickListener == null)
        throw new IllegalArgumentException("null runnable");
    if (initialInterval < 0 || normalInterval < 0)
        throw new IllegalArgumentException("negative interval");

    this.initialInterval = initialInterval;
    this.normalInterval = normalInterval;
    this.clickListener = clickListener;
}

public boolean onTouch(View view, MotionEvent motionEvent) {
    switch (motionEvent.getAction()) {
    case MotionEvent.ACTION_DOWN:
        handler.removeCallbacks(handlerRunnable);
        handler.postDelayed(handlerRunnable, initialInterval);
        downView = view;
        downView.setPressed(true);
        clickListener.onClick(view);
        return true;
    case MotionEvent.ACTION_UP:
    case MotionEvent.ACTION_CANCEL:
        handler.removeCallbacks(handlerRunnable);
        downView.setPressed(false);
        downView = null;
        return true;
    }

    return false;
}

}

and then use it like below in your onCreate() :

View player1 =  findViewById(R.id.player1);
View player2 =  findViewById(R.id.player2);
button.setOnTouchListener(new RepeatListener(400, 100, new OnClickListener() {
@Override
public void onClick(View view) {
  // the code to execute repeatedly
  player1.setX(player1.getX() - 30);
  player2.setX(player2.getX() + 30);
}
}));

for better code you can define player1 and player2 public (out of your onCreate) then initiate them in onCreate()

Community
  • 1
  • 1
Amir Ziarati
  • 14,248
  • 11
  • 47
  • 52
  • 1
    Thanks for your help, but when I tried running my project with your code, I get an error on setOnTouchListener saying "int cannot be dereferenced". I've already tried importing android.view.View.OnTouchListener and that didn't fix it. Do you know why this error is occurring? – HF1 Dec 31 '16 at 19:10
  • there is an error with your code inside the onclick . show me what you exactly added to your code. – Amir Ziarati Jan 01 '17 at 05:58
  • this error happens when you try to call a method from int (primitive-type) You cannot call methods on a primitive as you may be doing. – Amir Ziarati Jan 01 '17 at 06:01
  • error: int cannot be dereferenced mainButton.setOnTouchListener(new RepeatListener(400, 100, new View.OnClickListener() – HF1 Jan 01 '17 at 06:02
  • I didn't change anything within the onClick from what you had posted other than changing the names of player1 and player2 – HF1 Jan 01 '17 at 06:04
  • 1
    use Long's, dudes! – demogorgorn Jul 27 '19 at 21:05
  • yea i think that fixes it ;) – Amir Ziarati Jul 30 '19 at 12:25
0

You don't actually want to constantly repeat that- doing so would happen thousands of times a second. What you want to do is set a timer when the button it touched. When the timer fires, call that function, then set another timer. When the button is released, cancel the timer. To tell when the button is pressed/released, set an OnTouchEvent listener on it, and respond to the TOUCH_DOWN and TOUCH_UP events.

Oh, and just fyi- you should not call findViewById like that. Call it once in onCreate and save the result in a variable. Calling it constantly is inefficient.

Gabe Sechan
  • 90,003
  • 9
  • 87
  • 127