android repeat action on pressing and holding a button
There are multiple ways to accomplish this, but a pretty straightforward one would be to post a Runnable
on a Handler
with a certain delay. In it's most basic form, it will look somewhat like this:
Button button = (Button) findViewById(R.id.button);
button.setOnTouchListener(new View.OnTouchListener() {
private Handler mHandler;
@Override public boolean onTouch(View v, MotionEvent event) {
switch(event.getAction()) {
case MotionEvent.ACTION_DOWN:
if (mHandler != null) return true;
mHandler = new Handler();
mHandler.postDelayed(mAction, 500);
break;
case MotionEvent.ACTION_UP:
if (mHandler == null) return true;
mHandler.removeCallbacks(mAction);
mHandler = null;
break;
}
return false;
}
Runnable mAction = new Runnable() {
@Override public void run() {
System.out.println("Performing action...");
mHandler.postDelayed(this, 500);
}
};
});
The idea is pretty simple: post a Runnable
containing the repeated action on a Handler
when the 'down' touch action occurs. After that, don't post the Runnable
again until the 'up' touch action has passed. The Runnable
will keep posting itself to the Handler
(while the 'down' touch action is still happening), until it gets removed by the touch up action - that's what enables the 'repeating' aspect.
Depending on the actual behaviour of the button and its onclick/ontouch you're after, you might want to do the initial post without a delay.
Android - Hold Button to Repeat Action
This is more independent implementation, usable with any View, that supports touch event:
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 View touchedView;
private Runnable handlerRunnable = new Runnable() {
@Override
public void run() {
if(touchedView.isEnabled()) {
handler.postDelayed(this, normalInterval);
clickListener.onClick(touchedView);
} else {
// if the view was disabled by the clickListener, remove the callback
handler.removeCallbacks(handlerRunnable);
touchedView.setPressed(false);
touchedView = null;
}
}
};
/**
* @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);
touchedView = view;
touchedView.setPressed(true);
clickListener.onClick(view);
return true;
case MotionEvent.ACTION_UP:
case MotionEvent.ACTION_CANCEL:
handler.removeCallbacks(handlerRunnable);
touchedView.setPressed(false);
touchedView = null;
return true;
}
return false;
}
}
Usage:
Button button = new Button(context);
button.setOnTouchListener(new RepeatListener(400, 100, new OnClickListener() {
@Override
public void onClick(View view) {
// the code to execute repeatedly
}
}));
Android - Repeat Function While Button Held
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()
Android - How to hold a button for some time to repeat an action?
You need to use onTouchListener
button.setOnTouchListener(new View.OnTouchListener() {
@Override
public boolean onTouch(View v, MotionEvent event) {
switch(event.getAction()) {
case MotionEvent.ACTION_DOWN:
// PRESSED
// You can call a thread here which will keep increasing the time
return true;
case MotionEvent.ACTION_UP:
// RELEASED
// Stop the thread here
return true;
}
return false;
}
});
Repeat a callback on Button Hold down
First we need a way to check if the Button
is still pressed. For that purpose define a new boolean field called buttonPressed
:
private boolean buttonPressed = false;
Next we define the Runnable
we want to run as long as the Button
is pressed:
private final Runnable buttonPressedRunnable = new Runnable() {
@Override
public void run() {
// Check if the Button is pressed
if(buttonPressed) {
// Insert whatever you want to do while the Button is pressed here
...
// Repost the Runnable with an appropriate delay
button.postDelayed(this, 100);
}
}
};
Finally in your OnTouchListener
you need to set buttonPressed
to true
in ACTION_DOWN
and again to false
in ACTION_UP
. You also need to post the buttonPressedRunnable
once, as long as the Button
is pressed it will repost itself.
button.setOnTouchListener(new OnTouchListener() {
@Override
public boolean onTouch(View v, MotionEvent event) {
switch(event.getAction()) {
case MotionEvent.ACTION_DOWN:
mCamera.setPreviewCallback(previewCallback);
buttonPressed = true;
button.post(buttonPressedRunnable);
break;
case MotionEvent.ACTION_UP:
buttonPressed = false;
break;
}
return false;
}
});
How can I repeat/retrigger onLongClick in Android
Here's the solution that I cobbled together thats working well for me. I would have accepted the previous answers but they didn't take into account moving outside of the button's view. I hope the below code helps somebody else out in the same predicament. 90% of this code is not mine - so many thanks to the other stackoverflow posting that provided this.
EDIT: Actually, this is not perfect either - it doesn't animate button touches.
import android.content.Context;
import android.graphics.Rect;
import android.util.AttributeSet;
import android.view.MotionEvent;
import android.view.View;
import android.widget.Button;
public class AutoRepeatButton extends Button
{
private long initialRepeatDelay = 500;
private long repeatIntervalInMilliseconds = 1000;
private boolean mRepeatStarted = false;
private Runnable repeatClickWhileButtonHeldRunnable = new Runnable()
{
@Override
public void run()
{
// Perform the present
// repetition of the
// click action
// provided by the
// user
// in
// setOnClickListener().
mRepeatStarted = true;
performLongClick();
// Schedule the next
// repetitions of the
// click action, using
// a faster repeat
// interval than the
// initial repeat
// delay interval.
postDelayed( repeatClickWhileButtonHeldRunnable, repeatIntervalInMilliseconds );
}
};
private void commonConstructorCode()
{
mRepeatStarted = false;
this.setOnTouchListener( new OnTouchListener()
{
@Override
public boolean onTouch( View v, MotionEvent event )
{
int action = event.getAction();
if( action == MotionEvent.ACTION_DOWN )
{
// Just to be sure that we removed all callbacks,
// which should have occurred in the ACTION_UP
removeCallbacks( repeatClickWhileButtonHeldRunnable );
// Schedule the start of repetitions after a one half second delay.
postDelayed( repeatClickWhileButtonHeldRunnable, initialRepeatDelay );
}
else
if( action == MotionEvent.ACTION_UP )
{
// Cancel any repetition in progress.
removeCallbacks( repeatClickWhileButtonHeldRunnable );
if( mRepeatStarted == false )
{
// PDS: I put this here..
performClick();
}
mRepeatStarted = false;
return true;
}
else
if( action == MotionEvent.ACTION_MOVE )
{
int[] l = new int[2];
v.getLocationOnScreen( l );
Rect rect = new Rect( l[0], l[1], l[0] + v.getWidth(), l[1] + v.getHeight() );
if( ! rect.contains( v.getLeft() + (int) event.getX(),
v.getTop() + (int) event.getY()))
{
// User moved outside bounds
removeCallbacks( repeatClickWhileButtonHeldRunnable );
mRepeatStarted = false;
}
}
else
if( action == MotionEvent.ACTION_CANCEL )
{
removeCallbacks( repeatClickWhileButtonHeldRunnable );
mRepeatStarted = false;
}
// Returning true here prevents performClick() from getting called
// in the usual manner, which would be redundant, given that we are
// already calling it above.
return true;
}
} );
}
public AutoRepeatButton( Context context, AttributeSet attrs, int defStyle )
{
super( context, attrs, defStyle );
commonConstructorCode();
}
public AutoRepeatButton( Context context, AttributeSet attrs )
{
super( context, attrs );
commonConstructorCode();
}
public AutoRepeatButton( Context context )
{
super( context );
commonConstructorCode();
}
}
set button pressed and keep executing same task in Android
I think onTouchListerner
will best suits for your requirement. Use thread for doing the work. On event ACTION_DOWN
start the thread and on event ACTION_UP
stop the thread.
((Button) findViewById(R.id.leftBtn)).setOnTouchListener(new OnTouchListener() {
@Override
public boolean onTouch(View arg0, MotionEvent event) {
if(event.getAction() == MotionEvent.ACTION_DOWN){
// start the thread
return true;
} else if(event.getAction() == MotionEvent.ACTION_UP){
// stop the thread
return true;
}
return false;
}
});
Hope this will help for you.
Repeat task while button is pressed (from adapter)
When you press the button and use the notifyDataSetChanged() method it will cause the MotionEvent.ACTION_UP fail.
Please use the viewHolder.tbCount.setText() method to replace notifyDataSetChanged() and don't forget to update SizeCount(item) object value.
public class ItemAdapter extends ArrayAdapter<SizeCount> {
private static final String LOG_TAG = "MemoListAdapter";
private Collection<SizeCount> list;
public ItemAdapter(Context context, List<SizeCount> list) {
super(context, 0, list);
this.list = list;
}
public Collection<SizeCount> getList() {
return list;
}
@SuppressLint("ClickableViewAccessibility")
@Override
public View getView(int position, View convertView, ViewGroup parent) {
final SizeCount item = getItem(position);
if (item == null) return convertView;
final ViewHolder viewHolder;
if (convertView == null) {
convertView = LayoutInflater.from(getContext()).inflate(R.layout.entry_size_count, parent, false);
viewHolder = new ViewHolder();
viewHolder.tbCount = (EditText) convertView.findViewById(R.id.tbCount);
viewHolder.tvSize = (TextView) convertView.findViewById(R.id.tvSize);
viewHolder.btAdd = convertView.findViewById(R.id.btAdd);
viewHolder.btAdd.setOnTouchListener(new View.OnTouchListener() {
private Handler mHandler = new Handler();
@Override
public boolean onTouch(View v, MotionEvent event) {
switch (event.getAction()) {
case MotionEvent.ACTION_DOWN:
mHandler.postDelayed(mAction, 500);
break;
case MotionEvent.ACTION_UP:
mHandler.removeCallbacks(mAction);
break;
}
return false;
}
Runnable mAction = new Runnable() {
@Override
public void run() {
float currentCount = item.getCount();
float nextCount = currentCount + 1;
item.setModified(true);
// update SizeCount value
item.setCount(nextCount);
// set value to tbCount
viewHolder.tbCount.setText(String.valueOf(item.getCount()));
// this will cause the MotionEvent.ACTION_UP fail
// notifyDataSetChanged();
mHandler.postDelayed(this, 500);
}
};
});
convertView.setTag(viewHolder);
} else {
viewHolder = (ViewHolder) convertView.getTag();
}
viewHolder.tvSize.setFocusable(false);
viewHolder.tvSize.setText(item.getArticles().getSize());
viewHolder.tbCount.setText(item.getCount() + "");
return convertView;
}
private class ViewHolder {
TextView tvSize;
TextView tbCount;
Button btAdd;
}
}
I think it is not good to call notifyDataSetChanged() method for this case. It is wrong to refresh the whole View just to change value on single item.
Related Topics
Stopping an Android App from Console
How to Add New Column to Android SQLite Database
How to Add APKs in an Aosp Build
Android Material: Status Bar Color Won't Change
Cancel Notification on Remove Application from Multitask Panel
Adb Is Not Recognized as Internal or External Command on Windows
Retrofit - Multipart Request: Required Multipartfile Parameter 'File' Is Not Present
Is It Possible Query Data That Are Not Equal to the Specified Condition
How to Exclude Certain Messages by Tag Name Using Android Adb Logcat
Android - Activity VS Fragmentactivity
Android:Inapp Purchase Receipt Validation Google Play
How to Attach the Android Support Library Source in Eclipse
Android: Automatically Choose Debug/Release Maps API Key
How to Limit the Height of Spinner Drop Down View in Android
What's Wrong with Debugging in Eclipse on Android
App Not Run in Visual Studio Emulator for Android in Visual Studio 2015
Android Actionbar How to Add Supporting Library V7 Appcompat for Eclipse