【问题标题】:Continuously increase integer value as the button is pressed按下按钮时连续增加整数值
【发布时间】:2011-12-17 19:40:39
【问题描述】:

我是 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="&lt;" />

        <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="&gt;" />

     </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);
            }
        });

    }
}

【问题讨论】:

    标签: android events button


    【解决方案1】:

    为此,您需要一个线程来在您长按按钮时更新整数值。

    在您的活动中创建一个处理程序:

    private Handler repeatUpdateHandler = new Handler();
    

    还有 2 个变量将说明:是递增还是递减?一次只能设置一组。

    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 的按钮。

    而 decrement() 将是一个函数,它将像这样设置您的实例 int 变量:

    public void decrement(){
        mValue--;
        _value.setText( ""+mValue );
    }
    

    你计算出增量。哦,REP_DELAY 是一个静态 int 变量,设置为 50。

    我看到这是 Jeffrey Cole 的开源 NumberPicker 的摘录,地址为 http://www.technologichron.net/ 必须添加正确的作者署名。

    【讨论】:

    • 我按照您的指示创建了increment() 函数并声明了REP_DELAY,没有错误但是当我单击增量按钮时,值会增加,但即使我释放它,值仍然是增加并且不会停止。减少按钮也是如此。我错过了什么吗?
    • 抱歉,忘记添加 onTouchListener,它将清除增量标志(减量相同) - 请参阅更新的代码。
    • 添加了 onTouchListener 用于递增和递减,现在它可以工作了。谢谢!不胜感激! :)
    • 感谢您的帮助。当我需要为多个值做这个递增/递减的事情时,有什么想法吗?它会重复很多次。
    • 你不需要另一个线程只需使用handler post runnables...从handler 上的touch up 上删除runnable callbacks
    【解决方案2】:

    虽然接受的答案是完全正确的,但可以稍微简化一下。

    基本上,我们可以优化两件事:

    • 我们不需要 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;
    
        }
    
    });
    

    这里可运行对象被重用。并且当视图不再被按下时,它会停止调用自己。

    可以用类似的方式定义缩小视图或按钮。

    【讨论】:

      【解决方案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】:

        我在长按时增加值的方法是使用 Timer 来定期检查按钮是否仍被按下,而不是增加值,否则取消计时器。要更新 UI,请使用 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;
                }
            });
        

        处理程序:

        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));
                                }
                            }) ;
        }
        

        【讨论】:

          【解决方案5】:

          只想分享我自己的解决方案,对我来说效果很好。

          首先,在您的活动中创建一个处理程序

          private Handler mHandler = new Handler();
          

          然后,创建可递增/递减并显示您的数字的可运行文件。在这里,我们将检查您的按钮是否仍处于按下状态并递增,如果是则重新运行可运行对象。

          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's 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】:

            这个问题似乎没有完美的解决方案,总会涉及一些复杂性。

            这是我的尝试,它结合了 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());
                }
            
            
            }
            

            【讨论】:

              【解决方案7】:

              导入 java.awt.; 导入 java.awt.event.; 公共类 LabelNumber 扩展 Frame 实现 ActionListener {

                  Button badd,bsub;
                  TextField t1;
                  
              void display()
              {
                  setTitle("Label number change");
                  setSize(400,500);
                  setLayout(new FlowLayout());
                  setVisible(true);
              
                  badd=new Button("+");
                  t1=new TextField("0",6);
              
                  bsub= new Button("-");
                  add(bsub);add(t1);add(badd);
                
              
              badd.addActionListener(this);
              bsub.addActionListener(this);
              
              addWindowListener(new WindowAdapter()
              {
                  public void windowClosing(WindowEvent e)
                  {
                      System.exit(0);
                  }
              }
              );
              

              }

              public void actionPerformed(ActionEvent e)
                  {
                  int count=0,add=0,sub,n1,n2;
                      count=Integer.parseInt(t1.getText());
                          
                  if(e.getSource()==badd)
                  {
                      if(count<10)
                      {
                          count=count+1;
                          t1.setText(""+count);
                      }
                      else
                      {
                          t1.setText("limit:10");
                      }               
                  }
                  
                  if(e.getSource()==bsub)
                  {
                      if(count<10)
                      {
                          count=count-1;
                          t1.setText(""+count);
                      }
                      else
                      {
                          t1.setText("limit:10");
                      }               
                  }
              }
              
              
              public static void main(String args[])
              {
                  LabelNumber obj =new  LabelNumber();
                  obj.display();
              
              }
              

              }

              【讨论】:

              • 请不要只发布代码作为答案,还要解释您的代码的作用以及它如何解决问题的问题。带有解释的答案通常更有帮助,质量更高,更有可能吸引投票。
              【解决方案8】:

              对于 kotlin 用户

                  myButton.setOnLongClickListener {
                      val handler = Handler(Looper.myLooper()!!)
                      val runnable : Runnable = object : Runnable {
                          val number = 0
                          override fun run() {
                              handler.removeCallbacks(this)
                              if (myButton.isPressed) {
                                  val newNumber= number + 1
                                  textView.text = "$newNumber Items"
                                  handler.postDelayed(this, 100)
                              }
                          }
                      }
                      handler.postDelayed(runnable,0)
                      true
                  }
              

              【讨论】:

                【解决方案9】:

                初始化并调用方法

                int speed = 0;
                 button = findViewById(R.id.button);
                    button.setOnTouchListener((v, event) -> {
                        if (event.getAction() == MotionEvent.ACTION_DOWN) {
                            v.setPressed(true);
                                    increment();
                        } else if (event.getAction() == MotionEvent.ACTION_UP) {
                            v.setPressed(false);
                            speed = 0;
                         }
                        return true;
                    });
                

                这是增加方法

                    public void increment() {
                        new Handler().postDelayed(() -> {
                            Toast.makeText(FrequencyActivity.this, String.valueOf(speed), Toast.LENGTH_SHORT).show();
                            if (button.isPressed()) {
                                speed += 1;
                                increment();
                            }
                        }, 200); //200 ms for fast incrementing
                    }
                

                【讨论】:

                  【解决方案10】:

                  Kotlin 和 Coroutines 用户的版本(如果您愿意,可以将 GlobalScope 替换为任何其他范围):

                      var job: Job? = null
                  
                      viewClickable.setOnClickListener {
                          // single click
                      }
                  
                      viewClickable.setOnLongClickListener {
                          if (job == null || !job!!.isActive) {
                              job = GlobalScope.launch(Dispatchers.Main.immediate) {
                                  while (it.isPressed) {
                                      // long press
                                      delay(100)
                                  }
                              }
                          }
                          true
                      }
                  

                  【讨论】:

                    【解决方案11】:

                    我创建的最佳和简单的解决方案,看看它对我有用

                    public void increment() {
                        new Handler().postDelayed(new Runnable() {
                            @Override
                            public void run() {
                                check_amount = check_amount + 100;// increment by 100
                                tv_balance.setText("" + check_amount); // show continues incrementing value
                                if (check_amount != 5000) {
                                    increment();
                                }
                            }
                        }, 1); //1 ms for fast incrementing
                    }
                    

                    【讨论】:

                      猜你喜欢
                      • 2023-03-15
                      • 1970-01-01
                      • 1970-01-01
                      • 2023-03-05
                      • 1970-01-01
                      • 2021-10-13
                      • 2010-09-28
                      • 1970-01-01
                      • 1970-01-01
                      相关资源
                      最近更新 更多