Continuously increase integer value as the button is pressed

后端 未结 9 1284
长情又很酷
长情又很酷 2020-12-04 11:10

I\'m new to Android so sorry if the question is easy to answer. I have two buttons, a decrease and an increase button, and in the middle of them a TextView which displays a

相关标签:
9条回答
  • 2020-12-04 11:24

    Just wanna share my own solution that worked out for me really well.

    First, create a handler in your activity

    private Handler mHandler = new Handler();
    

    Then, create the runnables that will increment/decrement and display your number. In here, we will check if your button is still in its pressed state and increment then re-run the runnable if it is.

    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.
            }
        }
    }
    

    Finally, use it in our button's onLongClickListener

    IncrementButton.setOnLongClickListener(new View.OnLongClickListener() {
        @Override
        public boolean onLongClick(View view) {
            mHandler.postDelayed(incrementRunnable, 0); // initial call for our handler.
            return true;
        }
    });
    

    That's it!


    Another way of doing it is declaring both the handler and runnable inside the OnLongClickListener itself although I myself am not sure if this is a good practice.

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

    When doing this continuous increment, I would suggest to increase the increment value after a certain time/number of increments. E.g. If the number_of_increment made is less than 10, we increment by 1. Otherwise, we increment by 3.

    0 讨论(0)
  • 2020-12-04 11:24

    It seems there is no perfect solution to this question and there will always be some complexity involved.

    This is my attempt, which incorporates Wiktor's answer, but gives a whole MainActivity that you can cut/paste.

    In my example, the complex part is the onLongClickListener, and how deep it goes and how many levels of anonymous classes there are.

    However, on the other hand, the simplicity is that everything is included in one relatively short class (MainActivity), and there is only one major block of code -- the onLongClickListener -- which is defined only once and it's very clear where the "action" code is:

    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());
        }
    
    
    }
    
    0 讨论(0)
  • 2020-12-04 11:26

    for kotlin user

        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
        }
    
    0 讨论(0)
  • 2020-12-04 11:28

    I am late to answer this question but it may help any one who's looking for a better answer.

    I created a CounterHandler class and its insanely easy to use to achieve the above mentioned continuous counter functionality.

    You can find the class in following gist with a "how to use" example. https://gist.github.com/nomanr/d142f4ccaf55ceba22e7f7122b55b9b6

    Sample code

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

    Thats all. :)

    0 讨论(0)
  • 2020-12-04 11:28

    import java.awt.; import java.awt.event.; public class LabelNumber extends Frame implements 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();
    
    }
    

    }

    0 讨论(0)
  • 2020-12-04 11:29

    For that to work, you need a thread that will update the integer value when you long press on a button.

    Create a handler in your activity:

    private Handler repeatUpdateHandler = new Handler();
    

    And 2 vars which will state: is it increment or decrement? Only one set at a time.

    private boolean mAutoIncrement = false;
    private boolean mAutoDecrement = false;
    

    And the present number value

    public int mValue;
    

    And a class that will run in another thread:

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

    Add a long press listener to your button:

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

    In the above case the button is the increment one. Create another button which will set mAutoDecrement to true.

    And decrement() will be a function, which will set your instance int variable like this:

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

    You figure the increment out. Oh and REP_DELAY is a static int variable set to 50.

    I see this is an excerpt from Jeffrey Cole's open source NumberPicker available at http://www.technologichron.net/ Proper author's attribution must be added.

    0 讨论(0)
提交回复
热议问题