Непрерывно увеличивайте целочисленное значение при нажатии кнопки
Я новичок в Android, поэтому извините, если на вопрос легко ответить. У меня есть две кнопки, кнопка уменьшения и увеличения, а посреди них - TextView, который отображает значение.
Когда я нажимаю кнопку уменьшения, значение в TextView уменьшается и увеличивается, когда я нажимаю кнопку увеличения, никаких проблем с этим, я получил эту работу, но проблема в том, что значение только увеличивается/уменьшается на 1 на один клик, То, что я пытаюсь добиться, заключается в том, что, когда я постоянно нажимаю кнопку (например, кнопку увеличения), значение также непрерывно увеличивается и останавливается только при отпускании кнопки увеличения.
Это возможно? Если да, можете ли вы показать пример кода или ссылки о том, как его реализовать? Спасибо!
Вот мой main.xml
<?xml version="1.0" encoding="utf-8"?>
<RelativeLayout xmlns:android="http://schemas.android.com/apk/res/android"
android:layout_width="fill_parent"
android:layout_height="fill_parent"
android:gravity="center" >
<RelativeLayout
android:layout_width="fill_parent"
android:layout_height="44dp"
android:gravity="center_horizontal" >
<Button android:id="@+id/button1"
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:layout_alignParentLeft="true"
android:layout_alignParentTop="true"
android:text="<" />
<TextView android:id="@+id/textView1"
android:layout_width="50dp"
android:layout_height="fill_parent"
android:layout_alignBottom="@+id/button1"
android:layout_toRightOf="@+id/button1"
android:gravity="center"
android:text="45" />
<Button android:id="@+id/button2"
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:layout_alignParentTop="true"
android:layout_toRightOf="@+id/textView1"
android:text=">" />
</RelativeLayout>
</RelativeLayout>
и вот моя Main.java
import android.app.Activity;
import android.os.Bundle;
import android.util.Log;
import android.view.View;
import android.view.View.OnClickListener;
import android.widget.Button;
import android.widget.TextView;
public class Main extends Activity {
private Button _decrease;
private Button _increase;
private TextView _value;
private static int _counter = 45;
private String _stringVal;
@Override
public void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
setContentView(R.layout.main);
_decrease = (Button) findViewById(R.id.button1);
_increase = (Button) findViewById(R.id.button2);
_value = (TextView) findViewById(R.id.textView1);
_decrease.setOnClickListener(new OnClickListener() {
@Override
public void onClick(View v) {
Log.d("src", "Decreasing value...");
_counter--;
_stringVal = Integer.toString(_counter);
_value.setText(_stringVal);
}
});
_increase.setOnClickListener(new OnClickListener() {
@Override
public void onClick(View v) {
Log.d("src", "Increasing value...");
_counter++;
_stringVal = Integer.toString(_counter);
_value.setText(_stringVal);
}
});
}
}
Ответы
Ответ 1
Для этого вам понадобится поток, который будет обновлять целочисленное значение, когда вы долго нажимаете на кнопку.
Создайте обработчик в своей деятельности:
private Handler repeatUpdateHandler = new Handler();
И 2 vars, которые будут указывать: увеличивается ли это или уменьшается? Только один набор за раз.
private boolean mAutoIncrement = false;
private boolean mAutoDecrement = false;
И текущее значение числа
public int mValue;
И класс, который будет работать в другом потоке:
class RptUpdater implements Runnable {
public void run() {
if( mAutoIncrement ){
increment();
repeatUpdateHandler.postDelayed( new RptUpdater(), REP_DELAY );
} else if( mAutoDecrement ){
decrement();
repeatUpdateHandler.postDelayed( new RptUpdater(), REP_DELAY );
}
}
}
Добавьте кнопку длинного нажатия на кнопку:
mBTIncrement.setOnLongClickListener(
new View.OnLongClickListener(){
public boolean onLongClick(View arg0) {
mAutoIncrement = true;
repeatUpdateHandler.post( new RptUpdater() );
return false;
}
}
);
mBTIncrement.setOnTouchListener( new View.OnTouchListener() {
public boolean onTouch(View v, MotionEvent event) {
if( (event.getAction()==MotionEvent.ACTION_UP || event.getAction()==MotionEvent.ACTION_CANCEL)
&& mAutoIncrement ){
mAutoIncrement = false;
}
return false;
}
});
В приведенном выше случае кнопка является инкрементальной. Создайте еще одну кнопку, которая установит mAutoDecrement в true.
И декремент() будет функцией, которая будет устанавливать вашу переменную типа int следующим образом:
public void decrement(){
mValue--;
_value.setText( ""+mValue );
}
Вы указываете прирост. Oh и REP_DELAY - статическая переменная int, равная 50.
Я вижу, что это выдержка из Jeffrey Cole с открытым исходным кодом NumberPicker, доступная по адресу http://www.technologichron.net/ Должна быть добавлена правильная атрибуция автора.
Ответ 2
Мой способ увеличить значение при длительном нажатии - использовать таймер, используемый для периодической проверки, если кнопка все еще нажата, и чем увеличивает значение, в противном случае отменяет таймер. Для обновления пользовательского интерфейса используйте Handler.
vh.bttAdd.setOnLongClickListener(new View.OnLongClickListener() {
@Override
public boolean onLongClick(View v) {
final Timer timer = new Timer();
timer.schedule(new TimerTask() {
@Override
public void run() {
if(vh.bttAdd.isPressed()) {
final int track = ((ChannelAudioTrack) channels.get(vh.getAdapterPosition())).goToNextTrack();
updateUI(vh,track);
}
else
timer.cancel();
}
},100,200);
return true;
}
});
Handler:
private void updateUI(final TrackViewHolder vh, final int track)
{
new Handler(Looper.getMainLooper()).post(new Runnable() {
@Override
public void run() {
vh.tvTrackNumber.setText(Integer.toString(track));
}
}) ;
}
Ответ 3
Я опаздываю, чтобы ответить на этот вопрос, но это может помочь любому, кто ищет лучший ответ.
Я создал класс CounterHandler
и его безумно прост в использовании для достижения вышеупомянутых функций непрерывного счетчика.
Вы можете найти класс в следующем примере с примером "как использовать".
https://gist.github.com/nomanr/d142f4ccaf55ceba22e7f7122b55b9b6
Пример кода
new CounterHandler.Builder()
.incrementalView(buttonPlus)
.decrementalView(buttonMinus)
.minRange(-50) // cant go any less than -50
.maxRange(50) // cant go any further than 50
.isCycle(true) // 49,50,-50,-49 and so on
.counterDelay(200) // speed of counter
.counterStep(2) // steps e.g. 0,2,4,6...
.listener(this) // to listen counter results and show them in app
.build();
Вот и все.:)
Ответ 4
Кажется, что нет идеального решения этого вопроса, и всегда будут некоторые сложности.
Это моя попытка, которая включает в себя ответ Wiktor, но дает целый MainActivity, который вы можете вырезать/вставить.
В моем примере, сложная часть - это onLongClickListener, и насколько она глубока и сколько существует уровней анонимных классов.
Однако, с другой стороны, простота состоит в том, что все включено в один относительно короткий класс (MainActivity), и существует только один основной блок кода - onLongClickListener - который определяется только один раз, и очень ясно, где " код действия:
package com.example.boober.aalongclickoptimizationunit;
import android.support.v7.app.AppCompatActivity;
import android.os.Bundle;
import android.view.View;
import android.widget.Button;
import android.widget.TextView;
import java.util.Timer;
import java.util.TimerTask;
public class MainActivity extends AppCompatActivity {
TextView valueDisplay;
Button minusButton;
Button plusButton;
Button[] arrayOfControlButtons;
Integer currentDisplayValue = 500;
@Override
protected void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
setContentView(R.layout.activity_main);
valueDisplay = findViewById(R.id.value);
minusButton = findViewById(R.id.minusButton);
plusButton = findViewById(R.id.plusButton);
arrayOfControlButtons = new Button[]{plusButton, minusButton}; // this could be a large set of buttons
updateDisplay(); // initial setting of display
for (Button b : arrayOfControlButtons) {
b.setOnLongClickListener(new View.OnLongClickListener() {
@Override
public boolean onLongClick(final View v) {
final Timer timer = new Timer();
timer.schedule(new TimerTask() {
@Override
public void run() {
if (v.isPressed()) { // important: checking if button still pressed
runOnUiThread(new Runnable() {
@Override
public void run() {
// --------------------------------------------------
// this is code that runs each time the
// long-click timer "goes off."
switch (v.getId()) {
// which button was pressed?
case R.id.plusButton: {
currentDisplayValue = currentDisplayValue + 10;
break;
}
case R.id.minusButton: {
currentDisplayValue = currentDisplayValue - 10;
break;
}
}
updateDisplay();
// --------------------------------------------------
}
});
} else
timer.cancel();
}
}, 100, 200);
// if set to false, then long clicks will propagate into single-clicks
// also, and we don't want that.
return true;
}
});
}
}
// ON-CLICKS (referred to from XML)
public void minusButtonPressed(View ignored) {
currentDisplayValue--;
updateDisplay();
}
public void plusButtonPressed(View ignored) {
currentDisplayValue++;
updateDisplay();
}
// INTERNAL
private void updateDisplay() {
valueDisplay.setText(currentDisplayValue.toString());
}
}
Ответ 5
Просто хочу поделиться своим собственным решением, которое сработало для меня очень хорошо.
Сначала создайте обработчик в своей активности
private Handler mHandler = new Handler();
Затем создайте runnables, которые будут увеличивать/уменьшать и отображать ваш номер. Здесь мы проверим, находится ли ваша кнопка все еще в нажатом состоянии и увеличиваем ее, а затем повторно запустим исполняемый файл, если он есть.
private Runnable incrementRunnable = new Runnable() {
@Override
public void run() {
mHandler.removeCallbacks(incrementRunnable); // remove our old runnable, though I'm not really sure if this is necessary
if(IncrementButton.isPressed()) { // check if the button is still in its pressed state
// increment the counter
// display the updated value here, if necessary
mHandler.postDelayed(incrementRunnable, 100); // call for a delayed re-check of the button state through our handler. The delay of 100ms can be changed as needed.
}
}
}
Наконец, используйте его в нашей кнопке onLongClickListener
IncrementButton.setOnLongClickListener(new View.OnLongClickListener() {
@Override
public boolean onLongClick(View view) {
mHandler.postDelayed(incrementRunnable, 0); // initial call for our handler.
return true;
}
});
Вот оно!
Еще один способ сделать это - объявить как обработчик, так и работоспособный внутри самого OnLongClickListener, хотя я сам не уверен, является ли это хорошей практикой.
IncrementButton.setOnLongClickListener(new View.OnLongClickListener() {
private Handler mHandler = Handler();
private Runnable incrementRunnable = new Runnable() {
@Override
public void run() {
mHandler.removeCallbacks(incrementRunnable);
if(IncrementButton.isPressed()) {
// increment the counter
// display the updated value here, if necessary
mHandler.postDelayed(incrementRunnable, 100);
}
}
};
@Override
public boolean onLongClick(View view) {
mHandler.postDelayed(incrementRunnable, 0);
return true;
}
});
При выполнении этого непрерывного приращения я бы предложил увеличить значение приращения после определенного времени/числа приращений.
Например. Если значение number_of_increment меньше 10, мы увеличиваем на 1. В противном случае мы увеличиваем на 3.
Ответ 6
Хотя принятый ответ является полностью правильным, его можно немного упростить.
По сути, мы можем оптимизировать две вещи:
- Нам не нужен OnTouchListener.
- Мы можем создать исполняемый объект только один раз вместо создания нескольких объектов.
Так что это моя версия:
// global variables
Handler handler = new Handler();
Runnable runnable;
increaseView.setOnLongClickListener(new View.OnLongClickListener() {
@Override
public boolean onLongClick(View v) {
runnable = new Runnable() {
@Override
public void run() {
if (!increaseView.isPressed()) return;
increaseValue();
handler.postDelayed(runnable, DELAY);
}
};
handler.postDelayed(runnable, DELAY);
return true;
}
});
Здесь работающий объект используется повторно. И когда представление больше не нажимается, оно перестает вызывать себя.
Вид или кнопку уменьшения можно определить аналогичным образом.