I have a seemingly simple question that I need help with. I have a button. I want it so when I click on the button quickly it adds one to a total. I also want it to be so that when I hold down this same button for about 2 seconds, it removes one from the total. The only part I am having trouble with is the motion event part. I have been experimenting with ACTION_UP and ACTION_DOWN with no luck. Is there an easy way to do this?
switch (event.getAction())
{
case MotionEvent.ACTION_DOWN:
{
total ++;
return true;
}
case MotionEvent.ACTION_UP:
{
if(total >0){
total--;
}
return true;
}
}
Thanks for the help!
Why not use the Button's setOnClickListener and setOnLongClickListener?
The only limitation with this approach is that you cannot set the the timeout value, which is somewhat over 1,5 seconds, if I remember correctly.
If you're persistent about the two seconds (or some other value), then I suppose you could use an onTouchListener and keep track of the pressed time yourself. In that case, the MotionEvent's getDownTime might be of interest to you.
Related
I'm working on a tile memory game.
A user can press any one of the tiles on a 9x9 board.
However, I want to limit the user to being only to press one at a time.
I've tried researching using a TableLayout, setting beforeAscendants=true, and having that try to manage where a user's click goes, but that proves tedious and saving all those coordinates seems inefficient to the possibility of an easier solution existing.
Right now, I call .setOnClickListener on each of those tiles and setting them to the same onClickListener, but there's no way to limit how many tiles can be pressed at once. I've tried A) setting a synchronized() section around the code inside the anonymous onClickListener code, B) having a boolean to set to true if one tile is already in the onClickListener code but it's simply ignored and C) banging my head against the wall, didn't help
Thanks!
This is the most straightforward and simplest way I can come out with. You should optimize the logic too, it's pretty lengthy here.
onClick(View v) {
switch (v.getId()) {
case R.id.tile1:
// Tile 1 is clicked
// Disable other tiles (try setClickable(false))
break;
...
default:
break;
}
}
Wondering how can I change my button background programmatically by setting onClickListener.
I mean that when I firstly pressed my button it changes its background image and save it even if I release finger from it. And then if i press it the second time it must change background image again. I know that I must check what background is there at the moment but can't understand how to do it.
I've tried use getBackground method but it wasn't helpful for me. I even tried to create an XML file with selector which contains three state of my button, but it worked only until the moment I release finger from button.
You could have a global variable storing the background int:
private int backgroundNumber = 0;
Then, in onClick() you could do something like this:
backgroundNumber++;
switch (backgroundNumber % numberOfBackgrounds) { // numberOfBackgrounds is a constant of how many backgrounds there are
case 1:
button.setBackgroundResource(R.drawable.background1);
break;
// Do cases for all the backgrounds
}
I think that should work.
Try like this.
You know how many states you have. Use an int variable (lest say buttonState) to save button state (ex. states 1,2,3. MAX_STATE = 3).
On click just change state and replace background depending on the current buttonState variable value.
#Click(R.id.button_action)
void onButtonActionClicked() {
buttonState = ++buttonState % BTN_STATE_MAX;
switch (buttonState){
case BTN_SAVE:
button.setBackgroundResource(R.drawable.button_save);
break;
case BTN_LOAD:
button.setBackgroundResource(R.drawable.button_load);
break;
case BTN_DELETE:
button.setBackgroundResource(R.drawable.button_delete);
break;
}
}
I thought pinch would always trigger MotionEvent.ACTION_POINTER_UP, but it happens only about 50% of the time (it varies a lot) for an app on at least two tested tablet devices. It appears to be random. I do not know how to pinch to make it happen consistently.
The code is very straightforward as the following overridden method of the activity in question:
#Override
public boolean onTouchEvent(MotionEvent event) {
switch (event.getAction())
{
...
case MotionEvent.ACTION_POINTER_UP:
Log.d("Debug", "ACTION_POINTER_UP triggered");
default:
break;
}
...
}
Could anyone shed some light on this?
You may change your code to use getActionMasked().
#Override
public boolean onTouchEvent(MotionEvent event) {
switch (event.getActionMasked())
{
//...
case MotionEvent.ACTION_POINTER_UP:
Log.d("Debug", "ACTION_POINTER_UP triggered");
default:
break;
}
//...
}
MotionEven getAction() reports an integer which consists of both ACTION_whatever and
the pointer index left-shifted by ACTION_POINTER_INDEX_SHIFT (8) bits.
Return the kind of action being performed. Consider using getActionMasked() and getActionIndex() to retrieve the separate masked action and pointer index.
Returns
The action, such as ACTION_DOWN or the combination of ACTION_POINTER_DOWN with a shifted pointer index.
getAction() can be quite confusing to work with in multi-touch situations. If you want to get the kind of action (ACTION_DOWN, ACTION_POINTER_DOWN, and so on), which your case most likely is, you may use getActionMasked() instead of getAction().
getActionMasked() always returns ACTION_whatever, without the pointer index bits.
getAction() returns (getActionIndex() << 8 | ACTION_whatever).
(pointer indexes are very counter-intuitive, with Android trying to re-use the lowest indices available giving strange behavior if you use them directly, but that's another story, here better use getActionMasked() and not worry about indices). This is numerically equal to getActionMasked() only when the pointer has index=0, therefore you will see the "random" behavior: As you complete each pinch "naturally",
sometimes you may have released pointer 0 first, then pointer 1 last,
you get 2 events that getAction() returns ACTION_POINTER_UP followed by 1<<8 | ACTION_UP respectively, and hits the case ACTION_POINTER_UP label on the first event.
The other time you may have released pointer 1 first, then pointer 0 last,
you get 2 events that getAction() return 1<<8 | ACTION_POINTER_UP followed by ACTION_UP.
There is no case label for these, all get down to the default.
If you use getActionMasked(), you get ACTION_POINTER_UP followed by ACTION_UP, in both cases consistently.
I cant found the topic, perhaps someone can teach me some about android effectivity when the topis is about onclicklistener for buttons.
Lets say I got 10 buttons on a page (just an example now)
What's the best thing to do?
A switch that switch id for the buttons?
A onClickListener for each button?
What method is the faster one, and why?
Is there any different at all?
Best practice is to go with 1st option: A switch that switch id for the butttons.
As per my experience, i would suggest you to assign android:onClick attribute with same value, say for example: android:onClick="btnClicker"
And now you have to implement the same method inside the activity class as:
public void btnClicker(View v)
{
switch(v.getId())
{
case R.id.btn1:
break;
case R.id.btn2:
break;
case R.id.btn3:
break;
}
}
About 2nd option:
I don't prefer it because it increase number of code lines because just think you are having 10 buttons and you assign separate click listener for each buttons. And now compare it with the above 1st option, you will realize it.
So i would suggest you to go with 1st option i have suggested with example above, main reason is it decrease number of code lines and better readability of code.
Why there is better readability in 1st option i have suggested above?
Because you know you just have to check this particular function only for the code for every buttons, because everything is here inside a function.
I would be surprised if there is any significant difference. I would go with #2 because I think it leads to clearer code.
I think answer 1 is effectivity.
because create object will slow down the app.
and the RAM limit in mobile phone should be considered.
I'm porting an iPhone app into android app and one of the difficulties is recreating functionalities that are native to iPhone.
I found a native functionality of iPhone:
When user execute slide touch on a listed item in list view, a delete button appears.
Is there a version for this in android?
Can it be used and reused/customized?
This is just a bit more complicated to achieve. This is what I would do talking from a higher level.
Create a custom ViewGroup/Layout to hold a list item. Inside this layout you have your text lines images or what ever you have and also the delete button. You also here listen for gestures to hide or unhide the delete button.
In your list adapter you are going to need to keep track of which item is showing the delete button and which is not. Also, you are going to need to apply a click listener to each of the list item delete buttons. Every time you assign these states on the list item you should setTag(...) and store the list item position so that when it's clicked you can tell which item number must be deleted.
After deleting you must refresh the list in order for it to take effect. Depending on what type of adapter you are using that's going to determine how you refresh the adapter.
Hopefully this makes some sense. But I definitely think this is the easiest way since I've done this a couple times with similar functionality.
I guess you could either try to implement gesture listener over the listview itself but it might be hard to get the correct id. Since I haven't done it myself I can not answer exactly.
Otherwise you might be able to your own view as the item in the listview and the have a gesture listener on all the childs.
Fling gesture detection on grid layout
For some basic reading and code examples
I dont think there is any built-in API function to do this.
However, a workaround would be to use the onFling function on the view in listitem. You might be able to use this to accomplish what you want.
This is how I realize this effect. We have a ListView lvSimple and we add onTouchListener to our lvSimple. This is my working code.
float historicX = Float.NaN, historicY = Float.NaN;
static final int DELTA = 50;
enum Direction {LEFT, RIGHT;}
...
ListView lvSimple = (ListView) findViewById(R.id.linLayout);
...
lvSimple.setOnTouchListener(new OnTouchListener() {
#Override
public boolean onTouch(View v, MotionEvent event)
{
// TODO Auto-generated method stub
switch (event.getAction())
{
case MotionEvent.ACTION_DOWN:
historicX = event.getX();
historicY = event.getY();
break;
case MotionEvent.ACTION_UP:
if (event.getX() - historicX < -DELTA)
{
FunctionDeleteRowWhenSlidingLeft();
return true;
}
else if (event.getX() - historicX > DELTA)
{
FunctionDeleteRowWhenSlidingRight();
return true;
} break;
default: return false;
}
return false;
}
});
where function FunctionDeleteRowWhenSlidingLeft() is calling when when we sliding to the left, FunctionDeleteRowWhenSlidingRight - to the right respectively. In this function you need paste code for animation.
ps. I'm sorry for my bad english. Always glad to help.