I'd like to have two onTouchEvents on my app. One event would only work on the top half of the screen and the other event would only work on the bottom half of the screen. Is this possible?
//top
public boolean onTouchEvent(MotionEvent event){
this.mDetector.onTouchEvent(event);
// my logic
return super.onTouchEvent(event);
}
//bottom
public boolean onTouchEvent(MotionEvent event){
this.mDetector.onTouchEvent(event);
// my logic
return super.onTouchEvent(event);
}
Since the only provided solutions require you to use multiple Views, I figured I would provide one for a single View that encompasses the entire screen:
public boolean onTouch(View view, MotionEvent event) {
if(event.getY() < activity.getResources().getDisplayMetrics().heightPixels / 2){
//top
}
else{
//bottom
}
return true; //handle the touch
}
This was me just assuming you were only using a single View...
Something like this:
topLayout = (LinearLayout) findViewById(R.id.topLayout);
bottomLayout = (LinearLayout) findViewById(R.id.bottomLayout);
topLayout.setOnTouchListener(new View.OnTouchListener()
{
#Override
public boolean onTouch(View v, MotionEvent event)
{
Log.d(TAG, "top was touched");
return false;
}
});
bottomLayout.setOnTouchListener(new View.OnTouchListener()
{
#Override
public boolean onTouch(View v, MotionEvent event)
{
Log.d(TAG, "bottom was touched");
return false;
}
});
Or you could move those anonymous classes to their own respective classes and use them:
topLayout = (LinearLayout) findViewById(R.id.topLayout);
bottomLayout = (LinearLayout) findViewById(R.id.bottomLayout);
topLayout.setOnTouchListener(new TopOnTouchListener());
bottomLayout.setOnTouchListener(new BottomOnTouchListener());
This is assuming you have some view that spans the top and bottom of your layout. In the above example I'm using two LinearLayouts to do so, but feel free to choose your own.
Related
I am trying to Pause video on touch and play on release touch like as instagram reels, I had searched in google but I didn't get the solution, can anyone help me to find out the solution
binding.Video.setOnTouchListener(new View.OnTouchListener() {
boolean show = true;
#Override
public boolean onTouch(View view, MotionEvent motionEvent) {
if (show) {
binding.fullVideo.pause();
show = false;
} else {
binding.fullVideo.start();
show = true;
}
return false;
}
});
I have two views which are siblings of each other. They both cover the full screen. So one is behind the other. If the upper one gets touched (onTouch), I delegate the touch events to the one underneath it (with dispatchTouchEvent).
But sometimes I want to delay that delegation, till the next time onTouch gets called. But somehow that does not work.
An example to clarify:
To viewA - which is in front of viewB - I have applied the following (simplified) code:
viewA.setOnTouchListener(new View.OnTouchListener() {
#Override
public boolean onTouch(View view, MotionEvent event) {
int touchType = event.getActionMasked();
if (touchType == MotionEvent.ACTION_DOWN) {
savedEvent = event;
return true; // I also tried returning false here
} else {
if (savedEvent != null) {
viewB.dispatchTouchEvent(savedEvent);
savedEvent = null;
}
viewB.dispatchTouchEvent(event);
return true; // I also tried returning false here
}
}
});
To test the dispatchTouchEvent call, I have the following code for viewB
viewB.setOnTouchListener(new View.OnTouchListener() {
#Override
public boolean onTouch(View arg0, MotionEvent event) {
Log.d("test", "test"); // this code gets logged, so it is being called, but the view seems to not execute any of the touch events
return true;
}
});
When I change to code for viewA to this:
viewA.setOnTouchListener(new View.OnTouchListener() {
#Override
public boolean onTouch(View view, MotionEvent event) {
viewB.dispatchTouchEvent(event);
return true;
}
});
everything works just fine.
But the thing is that for my use case, I sometimes have to call the dispatchTouchEvent method with the event parameter outside its originating onTouch method, so to speak.
Is this even possible? And if yes, how?
So I found out what prevents it from working. If you manually call dispatchTouchEvent you should pass through an event that you created yourself with MotionEvent.obtain().
Working example:
viewA.setOnTouchListener(new View.OnTouchListener() {
#Override
public boolean onTouch(View view, MotionEvent event) {
int touchType = event.getActionMasked();
if (touchType == MotionEvent.ACTION_DOWN) {
// do not do this, somehow passing on a reference of the event directly does not work:
// savedEvent = event;
// this works though:
savedEvent = MotionEvent.obtain(event);
return true;
} else {
if (savedEvent != null) {
viewB.dispatchTouchEvent(savedEvent);
savedEvent = null;
}
viewB.dispatchTouchEvent(event);
return true;
}
}
});
Although I don't understand why that does work and just passing the event reference directly does not, I tested this and it does work perfectly.
I want to make a button change a seekbar's progress back to a specific value slowly while the button is pressed. It's like, say, the seekbar's curent progress is 150, it's standard value is 100, and I want to decrease the progress back to 100 while a buttons is pressed, and to move 1 unit on the seekbar takes 0.1 sec.
I'm trying to do this using a ValueAnimator
main_seekbar_speed_reset.setOnTouchListener(new View.OnTouchListener() {
#Override
public boolean onTouch(View v, MotionEvent event) {
ValueAnimator animator = ValueAnimator.ofInt(main_seekbar_speed.getProgress(), 100);;
switch(event.getAction()) {
case MotionEvent.ACTION_DOWN:
animator = ValueAnimator.ofInt(main_seekbar_speed.getProgress(), 100);
animator.setDuration(Math.abs(main_seekbar_speed.getProgress() - 100)*100);
animator.start();
animator.addUpdateListener(new ValueAnimator.AnimatorUpdateListener() {
#Override
public void onAnimationUpdate(ValueAnimator valueAnimator) {
main_seekbar_speed.setProgress((int)valueAnimator.getAnimatedValue());
}
});
case MotionEvent.ACTION_UP:
animator.end();
}
return false;
}
});
But this code resets it immediately.
EDIT
I forgot about adding break; to the end of each case.
It means that switch has gone through every case, thus animator.end() was always called for last, which set the progress of seekbar to the final animated value (100) everytime.
Additionally, animator.end() means that the animator ends immediately; it jumps to the last value it should be at the end of the animation.
MotionEvent.ACTION_DOWN and MotionEvent.ACTION_UP both created a new ValueAnimator, so releasing the button couldn't affect the ValueAnimator which was created when touching the button. It should be declared outside the listener.
So the working code:
`
final ValueAnimator animator = ValueAnimator.ofInt(main_seekbar_speed.getProgress(), 100);
main_seekbar_speed_reset.setOnTouchListener(new View.OnTouchListener() {
#Override
public boolean onTouch(View v, MotionEvent event) {
switch(event.getAction()) {
case MotionEvent.ACTION_DOWN:
animator.setIntValues(main_seekbar_speed.getProgress(), 100);
animator.setDuration(Math.abs(main_seekbar_speed.getProgress() - 100)*100);
animator.start();
animator.addUpdateListener(new ValueAnimator.AnimatorUpdateListener() {
#Override
public void onAnimationUpdate(ValueAnimator valueAnimator) {
main_seekbar_speed.setProgress((int)valueAnimator.getAnimatedValue());
}
});
break;
case MotionEvent.ACTION_UP:
animator.pause();
break;
}
return false;
}
});`
I have successfully implemented the on scroll toolbar Hide/Show but i am stuck at onTouch Hide/Show toolbar. i have researched many related questions but nothing works for me. I want my toolbar to hide when user touches on screen and again shows when the screen is touched again, please help
I am using Android Studio
below is my OnScrollListener java class
this.mrecyclerView.addOnScrollListener(new RecyclerView.OnScrollListener() {
int mLastFirstVisibleItem = 0;
#Override
public void onScrollStateChanged(RecyclerView recyclerView, int newState) {
}
#Override
public void onScrolled(RecyclerView recyclerView, int dx, int dy) {
super.onScrolled(recyclerView, dx, dy);
final int currentFirstVisibleItem = layout.findFirstVisibleItemPosition();
if (currentFirstVisibleItem > this.mLastFirstVisibleItem) {
HomePage.this.getSupportActionBar().hide();
} else if (currentFirstVisibleItem < this.mLastFirstVisibleItem) {
HomePage.this.getSupportActionBar().show();
}
this.mLastFirstVisibleItem = currentFirstVisibleItem;
}
});
Updated
mrecyclerView.setOnTouchListener(new View.OnTouchListener() {
#Override
public boolean onTouch(View v, MotionEvent event) {
ActionBar actionBar = getSupportActionBar();
if(actionBar.isShowing()) {
actionBar.hide();
} else
actionBar.show();
return false;
}
});
this code works, but the problem now is that whenever i touch the screen it shows the toolbar and when i pick up my finger it hide itself, and as i am using RecyclerView it is getting difficult to scroll with all that showing and hiding. please help to make it stable so that if i touch once it stays shown and on another touch it hides itself.
here you go. This should work :)
layout.setOnTouchListener(new View.OnTouchListener() {
#Override
public boolean onTouch(View v, MotionEvent event) {
if (event.getAction() == MotionEvent.ACTION_DOWN) {
if (actionBar.isShowing()) {
actionBar.hide();
} else {
actionBar.show();
}
return true;
} else return false;
}
});
Use onTouchListener to your root layout. And write your code inside callback.
I'm relatively a rookie/beginner with Java/Android programming. I've been trying to make it so while I press a given button in my application it produces a DTMF tone, but when I try to use setOnTouchListener the Android Studio shows me that error. It also gives me an error for MotionEvent which states Expression expected
Here are the important parts of the code:
boolean pressedCCW = false;
class SendCCWTone extends AsyncTask<Void,Void,Void>{
#Override
protected Void doInBackground(Void... arg0){
ToneGenerator toneGen;
toneGen = new ToneGenerator(AudioManager.STREAM_DTMF,100);
while(pressedCCW){
toneGen.startTone(ToneGenerator.TONE_DTMF_1);
}
toneGen.stopTone();
toneGen.release();
createLog("CCW");
return null;
}
}
final Button buttonCCW = (Button) findViewById(R.id.counter_clockwise);
buttonCCW.setOnTouchListener(new View.OnTouchListener(){// Where the error is
#Override
public boolean onTouch(View v, MotionEvent event){// Where the other error is located
switch (event.getAction()){
case MotionEvent.ACTION_DOWN:
if(pressedCCW == false){
pressedCCW = true;
new SendCCWTone().execute();
}
break;
case MotionEvent.ACTION_UP:
pressedCCW = false;
}
return true;
}
});
You are creating OnTouchListener inside of setOnClickListener. If you need TouchListener then you should register using setOnTouchListener instead of setOnClickListener
buttonCCW.setOnTouchListener(new View.OnTouchListener(){
#Override
public boolean onTouch(View v, MotionEvent event){
switch (event.getAction()){
case MotionEvent.ACTION_DOWN:
if(pressedCCW == false){
pressedCCW = true;
new SendCCWTone().execute();
}
break;
case MotionEvent.ACTION_UP:
pressedCCW = false;
}
return true;
}
});
This problem can be solved if you place setOnTouchListener inside the onCreate() method of your activity.
Rather than use setOnClickListener, you can set onClick in the XML and point to a method (it does the same thing and looks nicer). In this case, you'd have a method like produceSound:
public void produceSound(View view) {
// your onClick method
}
and in the activity's XML, find where that button, counter_clockwise, is and add: android:onClick="produceSound" to the button's XML.
More here if you're curious: How exactly does the android:onClick XML attribute differ from setOnClickListener?
However, if you're using onTouch, then you will have to stick with what everyone else is suggesting. XML does not support an android:onTouch attribute.
Try to add this to your code :
implements View.OnTouchListener
and use setOnTouchListner instead of setOnClickListener.
buttonCCW.setOnListener(new View.OnTouchListener(){// Where the error is
#Override
public boolean onTouch(View v, MotionEvent event){// Where the other error is located
switch (event.getAction()){
case MotionEvent.ACTION_DOWN:
if(pressedCCW == false){
pressedCCW = true;
new SendCCWTone().execute();
}
break;
case MotionEvent.ACTION_UP:
pressedCCW = false;
}
return true;
}
});