SeekBar.setProgress won't update the view - android

I am trying to make an Android application with two seekbars that can be controlled at the same time (multi-touch). The full source code can be found here
The app is a robot controller, each seekbar controls a motor so to move forward you slide both bars up and so on (speed is controlled by how far you push it up or down) where 50 is the stop state, 100 is the maximum speed forward and 0 is maximum speed backward.
What I am trying to implement is that after you let go of the seekbar it will go back to the stop state (progress 50), however, even though the value is actually set to 50 (using setProgress) but the view won't update to reflect that.
I tried using .invalidate(), .requestLayout() and some old solutions here and here but couldn't get it to work.
Here are parts of the code: (for full code check the github link above)
public class MainActivity extends ActionBarActivity {
...
...
public static void ResetSeekBar(View v) {
if ( v.getId() == R.id.sb1) {
Log.d("before", "Progress = " + Integer.toString(sb1.getProgress()));
sb1.setProgress(50);
Log.d("after", "Progress = " + Integer.toString(sb1.getProgress()));
sb1.invalidate();
//sb1.requestLayout();
} else if ( v.getId() == R.id.sb2) {
sb2.setProgress(50);
}
}
}
public class MySeekBar extends SeekBar {
public MySeekBar(Context context, AttributeSet attrs) {
super(context, attrs);
}
public boolean onTouchEvent(final MotionEvent event) {
if (event.getAction() == MotionEvent.ACTION_UP) {
Log.d("tag", "UP");
MainActivity.ResetSeekBar(this);
} else if (event.getAction() == MotionEvent.ACTION_MOVE) {
Log.d("tag", Integer.toString(getProgress()));
MainActivity.UpdateText(this, Integer.toString(getProgress()));
} else if (event.getAction() == MotionEvent.ACTION_DOWN) {
Log.d("tag", "DOWN ");
MainActivity.UpdateText(this, Integer.toString(getProgress()));
}
return super.onTouchEvent(event);
}
}
Using a regular button onClick works and do update the view but not after MotionEvent up. So what am I doing wrong?
Also how can I make it reset to 50 but with a fast transition instead of suddenly jumping to the middle?

Of course the solution comes after you ask poeple! anyways, it is much simpler than I thought.
super.onTouchEvent(event) should be called before processing the event, i think I was trying to change it before it actually processed the change, so it was overriding what i did! (not sure just guessing based on the behaviour that I saw)
and here is the function after the fix:
public boolean onTouchEvent(final MotionEvent event) {
super.onTouchEvent(event);
if (event.getAction() == MotionEvent.ACTION_UP) {
Log.d("tag", "UP");
MainActivity.ResetSeekBar(this);
} else if (event.getAction() == MotionEvent.ACTION_MOVE) {
Log.d("tag", Integer.toString(getProgress()));
MainActivity.UpdateText(this, Integer.toString(getProgress()));
} else if (event.getAction() == MotionEvent.ACTION_DOWN) {
Log.d("tag", "DOWN ");
MainActivity.UpdateText(this, Integer.toString(getProgress()));
}
return true;
}

Related

Why onTouchEvent getPointerCount() method always returning 1?

I'm trying just trying to make this function work but I am having troubles. When I have touch on View, getPointerCount() method always returns 0 pointers, when I touch the screen with one finger, 1. When I touch the screen with two or more fingers, it's always return 1. Have you any ideas ?
i have trying to this code,
#Override
public boolean onTouch(View view, MotionEvent me) {
// No dragging during animation at the moment.
// TODO: Stop animation on touch event and return to drag mode.
if (me.getPointerCount() >= 2) {
mAnimate = false;
mEnableTouchPressure = false;
mRenderLeftPage = false;
startCurl(CURL_NONE);
mCurlState = CURL_NONE;
mPageRight.setFlipTexture(false);
mPageLeft.setFlipTexture(false);
return false;
} else {
if (me.getAction() == MotionEvent.ACTION_DOWN) {
Log.e("TAG_EVENT", me.getPointerCount() + "");
} else {
Log.e("TAG_EVENT - 2", me.getPointerCount() + "");
}
}
}
I think is because you should return true for the touch event to be processed.
You can read the about MotionEvent.ACTION_MASK. For catching the action of multiTouch you can use the following code :
int action = (motionEvent.getAction() & MotionEvent.ACTION_MASK) % 5
switch(action) {
case MotionEvent.ACTION_DOWN:
System.out.println(motionEvent.getPointerCount());
break;
}

Detect ongoing touch event

I am currently trying to detect an ongoing touch event in my Android app.
In detail I want to recognize within a fragment whether the user touches any part of the app's screen.
Android's OnTouchListener works as expected except if the touch event lasts longer than a few seconds without moving.
For example the first 1-2 seconds of touch are being detected but everything after won't.
Is there something like an "OnPressListener" or a workaround?
If it's a well defined gesture you are trying to detect, have a look at GestureDetector.
http://developer.android.com/reference/android/view/GestureDetector.html
You can use
aButton.setOnLongClickListener(new OnLongClickListener() {
public boolean onLongClick(View arg0) {
Toast.makeText(getApplicationContext(), "Long Clicked " ,
Toast.LENGTH_SHORT).show();
return true; // <- set to true
}
});
on your aButton and if you are using API < 19 you have to add
android:longClickable="true"
Attribute to your aButton in layout xml.
I finally found it out.
The solution is to use a simple OnTouchListener:
private boolean pressed = false;
#Override
public boolean onTouch(View v, MotionEvent event) {
int action = event.getAction();
if (action == MotionEvent.ACTION_DOWN) {
pressed = true;
} else if ((action == MotionEvent.ACTION_UP)
|| (action == MotionEvent.ACTION_CANCEL)) {
pressed = false;
}
return true;
}

MotionEvent.ACTION_CANCEL is not triggered during onTouch

I am having this problem where ACTION_CANCEL is not triggered, I have implemented it in my other project and it's working fine. It seems that ACTION_UP is the only MotionEvent that is called after ACTION_DOWN. I wanted to trigger ACTION_CANCEL once my finger is not anymore in the view or outside the screen.
Sample scenario: I click on the view which is a LinearLayout btw, on ACTION_DOWN its background is changed to a "clicked/dimmed" version of the image and when ACTION_UP is triggered its background changes back to the default image only if the finger is within the LinearLayout. Now the problem is when I press it and kept my finger on the screen, and drag my finger outside the LinearLayout, ACTION_UP is still triggered where it shouldn't have.
Here's my code:
dimView.setOnTouchListener(new OnTouchListener() {
public boolean onTouch(final View view,
final MotionEvent motionEvent) {
if (motionEvent.getAction() == MotionEvent.ACTION_DOWN) {
Log.d("TAG", "DOWN");
return true;
} else if (motionEvent.getAction() == MotionEvent.ACTION_UP) {
Log.d("TAG", "UP");
return true;
} else if (motionEvent.getAction() == MotionEvent.ACTION_CANCEL) {
Log.d("TAG", "CANCEL");
return true;
}
return false;
}
});
where: dimView is a LinearLayout
I've been debugging this for a really long time and it bothered me a lot since this came up very randomly. I then tested my code on different devices and realized the API implementation changed with Android 4.2.
The expected behaviour and code work absolutely fine with Android 4.1.2 (tested on Galaxy Tab 2) but the bug you describe can be seen on a Nexus 7 (Android 4.2).
Apparently Android changed the way MotionEvents are handled in API 17.
One particular case when the bug does not occur is when the view is located in a GroupLayout under a ScrollView. When scrolling is possible the ACTION_CANCEL gets fired. However when no scrolling is possible the bug persists.
At first I tried combining an OnClickListener and OnTouchListener so that the last can handle just the animations but to no avail. Dispatching the Events from parents also doesn't work.
One workaround is to capture ACTION_MOVE events and check if the finger is located outside of the view's boundaries using v.getX() and v.getY() and comparing them to event.getX() and event.getY() respectably. A global boolean variable (isOutside) can be used to store the most current information. Before firing up the ACTION_UP you can check the latest state of isOutside and perform your animations and action accordingly. You can also return true or false depending on whether you captured the event or not.
Update: After digging a bit here i found this solution:
Android: Detect if user touches and drags out of button region? and compiled this code. The idea is the same except that it creates a rectangle and checks if the event boundaries are within the rectangle of the view.
someView.setOnTouchListener(new View.OnTouchListener() {
private Rect rect;
#Override
public boolean onTouch(View v, MotionEvent event) {
Log.d(TAG,"Touched: "+event.getAction());
if (event.getAction() == MotionEvent.ACTION_DOWN) {
Log.d(TAG,"ACTION_DOWN");
animateImageButtonOnClick(v, event);
rect = new Rect(v.getLeft(), v.getTop(), v.getRight(), v.getBottom());
}
if (event.getAction() == MotionEvent.ACTION_UP) {
Log.d(TAG,"ACTION_UP");
if (!rect.contains(v.getLeft() + (int) event.getX(), v.getTop() + (int) event.getY())) {
Log.d(TAG,"ACTION_UP - outside");
animateImageButtonOnRelease(v, event);
} else {
Log.d(TAG,"ACTION_UP - inside");
// do your stuff here
}
}
if(event.getAction() == MotionEvent.ACTION_MOVE){
if(!rect.contains(v.getLeft() + (int) event.getX(), v.getTop() + (int) event.getY())){
animateImageButtonOnReleaseWithLowDuration(v, event);
}
}
if (event.getAction() == MotionEvent.ACTION_CANCEL){
Log.d(TAG,"ACTION_CANCEL");
animateImageButtonOnRelease(v, event);
return true;
}
return true;
}
});
Override dispatchTouchEvent method maybe deal with it;
dimView.setOnTouchListener(new OnTouchListener() {
#Override
public boolean onTouch(View v, MotionEvent event) {
// TODO Auto-generated method stub
// to call super touch method
return false;
}
});
#Override
public boolean dispatchTouchEvent(MotionEvent motionEvent) {
// TODO Auto-generated method stub
if (motionEvent.getAction() == MotionEvent.ACTION_DOWN) {
Log.d("TAG", "DOWN");
return true;
} else if (motionEvent.getAction() == MotionEvent.ACTION_UP) {
Log.d("TAG", "UP");
return true;
} else if (motionEvent.getAction() == MotionEvent.ACTION_CANCEL) {
Log.d("TAG", "CANCEL");
return true;
}
return super.dispatchTouchEvent(motionEvent);
}

OnTouch with multitouch in android

I am havig troubles counting how much touches are being made in each "half" of the screen.
When I touch in the upper side it counts correctly, and the same with the lower side. BUT, when I touch the upper side, dont release it, and touch the lower side, then it counts the wrong side, what is wrong in my implementation?
myView.setOnTouchListener(new OnTouchListener() {
public boolean onTouch(View v, MotionEvent event) {
// TODO Auto-generated method stub
int action = event.getAction() & MotionEvent.ACTION_MASK;
if (action == MotionEvent.ACTION_DOWN) {
if(event.getY()<400)
{
}
else
{
}
}
if (action == MotionEvent.ACTION_UP) {
if(event.getY()<400)
{
zenbat=zenbat+1;
tv.setText(String.valueOf(zenbat));
}
if(event.getY()>400)
{
zenbat1=zenbat1+1;
tv1.setText(String.valueOf(zenbat1));
}
}
if (action == MotionEvent.ACTION_POINTER_DOWN) {
if(event.getY()<400)
{
}
else
{
}
}
if (action == MotionEvent.ACTION_POINTER_UP) {
if(event.getY()<400)
{
zenbat=zenbat+1;
tv.setText(String.valueOf(zenbat));
}
if(event.getY()>400)
{
zenbat1=zenbat1+1;
tv1.setText(String.valueOf(zenbat1));
}
}
return true;
}
});
If you want to correctly handle multitouch events you need to use the pointer index to correctly identify the finger generating the event.
I've answered a similar question in Android multi-touch interference where I posted a code example how to do it.
To correctly identify the finger, you should refer to the fingerId in the code posted.
Regards.

Issue with Android's onTouchEvent()

I am creating my first Android app using this guide as a reference. Currently, I have a red button on my canvas and when the user clicks the button a boolean (green) will be set to true in order for the button's bitmap to a green button.
That part of the application works, however it works regardless where the user clicks on the canvas. I only want the boolean to be changed when the user clicks on the button's bitmap. Here is what I currently have in my code:
The onTouchEvent() method
#Override
public boolean onTouchEvent(MotionEvent event) {
if (event.getAction() == MotionEvent.ACTION_DOWN) {
button.handleActionDown((int)event.getX(), (int)event.getY());
if (button.isTouched()) {
green = true;
}
} if (event.getAction() == MotionEvent.ACTION_MOVE) {
} if (event.getAction() == MotionEvent.ACTION_UP) {
if (button.isTouched()) {
green = false;
button.setTouched(false);
}
}
return true;
}
The handleActionDown() Method
public void handleActionDown(int eventX, int eventY) {
if (eventX >= (x - bitmap.getWidth() / 2) && (eventX <= (x + bitmap.getWidth()/2))) {
if (eventY >= (y - bitmap.getHeight() / 2) && (eventY <= (y + bitmap.getHeight()/2))) {
setTouched(true);
} else {
setTouched(false);
}
} else {
setTouched(false);
}
}
Can anybody see what I am missing in order for the ACTION_DOWN event to make it so it only triggers when the bitmap's bitmap is touched?
Regards
Avoid using onTouchEvent with buttons, it is better to use onClick because the OS detects whether or not a specific button is clicked instead of you having to calculate the position of a button
First, set the onClickListener
btn.setOnClickListener(this);
This assumes the current class implements View.OnClickListener, so if you don't implement it you either have to use a different class or create an anonymous inner class.
Then, in the onClick method, make sure the ID matches and add whatever action you want to do inside an if-statement (or alternatively a switch statement)
#Override
public void onClick(View v) {
if(v.getId() == R.id.btn1){
//do whatever you want on press
}
}

Categories

Resources