I have a Click function and long press on the same button. Implemented the long press event but, I need to find the button UP_EVENT and DOWN_EVENTS separately.
How can I implement by using the OnLongClickListener
View.OnLongClickListener listener = new View.OnLongClickListener() {
#Override
public boolean onLongClick(View view) {
return true;
}
};
Implement a TouchListener within the onLongClickListener:
View.OnLongClickListener listener = new View.OnLongClickListener() {
#Override
public boolean onLongClick(View view) {
view.setOnTouchListener(new View.OnTouchListener() {
#Override
public boolean onTouch(View v, MotionEvent event) {
switch (event.getAction()) {
case MotionEvent.ACTION_DOWN:
// PRESSED
return true; // if you want to handle the touch event
case MotionEvent.ACTION_UP:
// RELEASED
return true; // if you want to handle the touch event
}
return false;
}
});
return true;
}
};
To detect ACTION_UP and ACTION_DOWN events you need to implement OnTouchListener.
to sepate , you can do this way
#Override
public boolean onTouchEvent(MotionEvent ev) {
switch (ev.getAction() & MotionEvent.ACTION_MASK) {
case MotionEvent.ACTION_DOWN:
break;
case MotionEvent.ACTION_CANCEL:
case MotionEvent.ACTION_UP:
if (isOnClick) {
//TODO onClick code
}
break;
case MotionEvent.ACTION_MOVE:
}
break;
default:
break;
}
return true;
}
Related
I am trying to make a simple app: there is one button in the middle which a child would press. As long as that button is held down it would play a certain MP3.
At the moment, I tried with onClick, but, that plays only when the button is released.
Instead of using an onClickListener which exposes nothing more then an interface for press and release, you would need to use an onTouchListener - which exposes all touch events of a view.
myButton.setOnTouchListener( new View.OnTouchListener() {
#Override
public boolean onTouch(View v, MotionEvent event) {
switch ( event.getAction() ) {
MotionEvent.ACTION_DOWN:
// start playing
return true;
MotionEvent.ACTION_UP:
// stop playing
return true;
}
return false;
}
});
Try something like this. Using the boolean "playing" you can create a thread/loop elsewhere to check if still playing and keep audio going.
button.setOnTouchListener(new View.OnTouchListener() {
#Override
public boolean onTouch(View arg0, MotionEvent arg1) {
if (arg1.getAction()==MotionEvent.ACTION_DOWN) {
playing = true;
} else {
playing = false;
}
return true;
}
});
Try the OnFocusChangeListener
Button.setOnFocusChangeListener(new OnFocusChangeListener() {
#Override
public void onFocusChange(View v, boolean hasFocus) {
if (!hasFocus) {
// code to execute when Button loses focus, i.e. stop music
}
}
});
Since a button is a view component you can use View.OnTouchListener event listener with ACTION_BUTTON_PRESS & ACTION_BUTTON_RELEASE MotionEvent.
Here is an example:
yourButton.setOnTouchListener(new OnTouchListener() {
#Override
public boolean onTouch(View v, MotionEvent event) {
if(event.getAction() == MotionEvent.ACTION_BUTTON_PRESS){
// Start Video
return true;
} else if (event.getAction() == MotionEvent.ACTION_BUTTON_RELEASE) {
// End Video
return true;
}
return false;
}
});
This is my code:
public class MainActivity extends AppCompatActivity {
#Override
protected void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
setContentView(R.layout.activity_main);
}
public void start_recording(View view){
MediaPlayer mediaPlayer = MediaPlayer.create(this, R.raw.test1);
mediaPlayer.start();
}
}
I created an onTouchListener for my ImageView "car" and want to do the same for another ImageView, however I can't figure out how. So my question is:
How do you use one onTouchListener that detects the MotionEvents of two separate ImageViews and makes something happen accordingly?
#Override
public boolean onTouch(View view, MotionEvent event) {
//int action = event.getAction();
switch (event.getAction()) {
case MotionEvent.ACTION_DOWN:
carcolor.setBackgroundColor(this.getResources().getColor(R.color.colorPrimary));
car.startAnimation(pressdown);
pressdown.setAnimationListener(new Animation.AnimationListener() {
#Override
public void onAnimationStart(Animation animation) {
carback.setScaleX((float) 0.9);
carback.setScaleY((float) 0.9);
}
#Override
public void onAnimationEnd(Animation animation) {
carback.setVisibility(View.VISIBLE);
car.setVisibility(View.INVISIBLE);
}
#Override
public void onAnimationRepeat(Animation animation) {
}
});
break;
case MotionEvent.ACTION_MOVE:
break;
case MotionEvent.ACTION_UP:
car.startAnimation(release);
carcolor.setBackgroundColor(this.getResources().getColor(R.color.unpressed));
release.setAnimationListener(new Animation.AnimationListener() {
#Override
public void onAnimationStart(Animation animation) {
carback.setVisibility(View.INVISIBLE);
}
#Override
public void onAnimationEnd(Animation animation) {
car.setVisibility(View.VISIBLE);
}
#Override
public void onAnimationRepeat(Animation animation) {
}
});
break;
case MotionEvent.ACTION_CANCEL:
break;
}
return true;
}
You should implement the onTouchListener like:
imageView.setOnTouchListener(this);
and init it like :
#Override
public boolean onTouch(View v, MotionEvent event) {
ImageView view = (ImageView) v;
switch (view.getId()){
case R.id.car1: // example id
switch (event.getAction()) {
case MotionEvent.ACTION_DOWN:
break;
case MotionEvent.ACTION_MOVE:
break;
case MotionEvent.ACTION_UP:
break;
case MotionEvent.ACTION_CANCEL:
break;
}
break;
case R.id.car2: // example id
switch (event.getAction()) {
case MotionEvent.ACTION_DOWN:
break;
case MotionEvent.ACTION_MOVE:
break;
case MotionEvent.ACTION_UP:
break;
case MotionEvent.ACTION_CANCEL:
break;
}
break;
}
return true;
}
If your activity is implementing the onTouchListener event (I'm assuming based on the override), on your other ImageView just do the following
imageView.setOnTouchListener(this);
Where this is the current activity.
EDIT: Based on your comment
public class ImageView1Listener implements OnTouchListener
{
**** OVERRIDES****
}
public class ImageView2Listener implements OnTouchListener{
**** OVERRIDS FOR THIS IMAGE****
}
then in your main remove the implements OnTouchListener and use bind it programatically
imageView1.setOnClickListener(new ImageViewListener1());
imageView2.setOnClickListener(new ImageViewListener2());
Attach the listener to the parent of them.
Than, use gesturesDetector as stated here:
https://developer.android.com/training/gestures/detector.html
public class MainActivity extends Activity implements
GestureDetector.OnGestureListener,
GestureDetector.OnDoubleTapListener{
private static final String DEBUG_TAG = "Gestures";
private GestureDetectorCompat mDetector;
// Called when the activity is first created.
#Override
public void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
setContentView(R.layout.activity_main);
// Instantiate the gesture detector with the
// application context and an implementation of
// GestureDetector.OnGestureListener
mDetector = new GestureDetectorCompat(this,this);
// Set the gesture detector as the double tap
// listener.
mDetector.setOnDoubleTapListener(this);
}
#Override
public boolean onTouchEvent(MotionEvent event){
this.mDetector.onTouchEvent(event);
// Be sure to call the superclass implementation
return super.onTouchEvent(event);
}
#Override
public boolean onSingleTapConfirmed(MotionEvent event) {
Log.d(DEBUG_TAG, "onSingleTapConfirmed: " + event.toString());
return true;
}
....
}
I have an app where you can press on a screen and a method gets executed, and where you can long press and another method gets executed. The problem is, when I long press on the screen the normal onClickListener also gets executed, which I don't want.
They both are simple onClickListeners, the normal one is using the MotionEvent ACTION_UP. Is there any way to prevent that from happening?
So I don't want to execute the ACTION_UP in the normal onTouchListener when the onLongClickListener executed.
Code:
layout.setOnTouchListener(new View.OnTouchListener() {
#Override
public boolean onTouch(View v, MotionEvent event) {
if (event.getAction() == MotionEvent.ACTION_UP) {
}
return false;
}
});
layout.setOnLongClickListener(new View.OnLongClickListener() {
#Override
public boolean onLongClick(View v) {
return true;
}
});
If you still want to onTouch
int flag=0
layout.setOnTouchListener(new View.OnTouchListener() {
#Override
public boolean onTouch(View v, MotionEvent event) {
if (event.getAction() == MotionEvent.ACTION_UP) {
if(flag==0){
//do something
}else{
flag=0;
}
}
return false;
}
});
layout.setOnLongClickListener(new View.OnLongClickListener() {
#Override
public boolean onLongClick(View v) {
flag=1
return true;
}
});
LongClick and Click are in the same level, while Touch isn't (actually LongClick an Click are dispatched from onTouchEvent).
In your code, you always return false in onTouch method, so you don't comsume the event and it will be passed to the next level (LongClick, Click...), this is why when you long press the screen you have the both method called.
Suggestion1:
Use ClickListener instead of TouchListener.
Suggestion2:
Use GestureDetector to handle all events (touch, longclick...). This is an example
Suggestion3:
Use a flag to perform the desired event.
private boolean longClick = false;
layout.setOnTouchListener(new View.OnTouchListener() {
#Override
public boolean onTouch(View v, MotionEvent event) {
if (longClick) {
longClick = false;
}
return false;
}
});
layout.setOnLongClickListener(new View.OnLongClickListener() {
#Override
public boolean onLongClick(View v) {
longClick = true;
return false;
}
});
Suggestion4:
Use a handler with runnable. Example1 and Example2
If onclick does the same as you intended use onclick listner instead of ontouch that way you wont trigger onclick when you longclick.
Im getting the following error when using the below code
The method onKeyDown(int, KeyEvent) is undefined for the type SherlockFragment
public boolean onKeyDown(int KeyCode, KeyEvent event) {
if ((KeyCode == KeyEvent.KEYCODE_BACK) && web.canGoBack()) {
web.goBack();
return true;
}
return super.onKeyDown(KeyCode, event);
}
I would keep this kind of thing out of your fragment. The following code worked for me in my MainActivity with 4 tabs that each have their own web view.
#Override
public void onBackPressed() {
// TODO Auto-generated method stub
int currPage = mPager.getCurrentItem();
WebView wv = null;
switch (currPage) {
case 0:
wv = (WebView) mPager.getChildAt(currPage).findViewById(R.id.webView1);
break;
case 1:
wv = (WebView) mPager.getChildAt(currPage).findViewById(R.id.webView2);
break;
case 2:
wv = (WebView) mPager.getChildAt(currPage).findViewById(R.id.webView3);
break;
case 3:
wv = (WebView) mPager.getChildAt(currPage).findViewById(R.id.webView4);
break;
}
if (wv != null) {
if (wv.canGoBack()) {
wv.goBack();
} else {
super.onBackPressed();
}
} else {
super.onBackPressed();
}
}
edit: I ran into trouble on my 4th tab and the solution for me was to set the webView in my fragment(Tab0.java) static. Then directly referencing it in my main activity.
switch (currPage) {
case 0:
wv = Tab0.webView;
break;
case 1:
wv = Tab1.webView;
break;
case 2:
wv = Tab2.webView;
break;
case 3:
wv = Tab3.webView;
break;
}
The Activity should manage the back button not the fragment. If you want the fragment to manage the onKeyDown, you can attach the OnKeyListener, on the view returned by getView()
#Override
public View onCreateView(LayoutInflater inflater, ViewGroup container,
Bundle savedInstanceState) {
View view = inflater.inflate(R.layout.left, container, false);
view.setOnKeyListener( new OnKeyListener() {
#Override
public boolean onKey( View v, int keyCode, KeyEvent event ) {
// here your code
}
});
return view;
}
After done few research. i found this !
Hopefully its help.
root =(ViewGroup) inflater.inflate(R.layout.setting_f_other, container, false);
root.setOnKeyListener( new OnKeyListener() {
#Override
public boolean onKey(View v, int keyCode, KeyEvent event ) {
if (keyCode == KeyEvent.KEYCODE_BACK){
//Do something
}
return false;
}
});
I don't know the reason of the crash.
package com.tct.soundTouch;
//imports ();;;;;;;
public class Main extends Activity implements OnClickListener{
private MediaPlayer mp;
private MotionEvent event;
public void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
this.requestWindowFeature(Window.FEATURE_NO_TITLE);
this.getWindow().setFlags(WindowManager.LayoutParams.FLAG_FULLSCREEN,
WindowManager.LayoutParams.FLAG_FULLSCREEN);
setContentView(R.layout.main);
final ImageButton zero = (ImageButton) this.findViewById(R.id.button);
zero.setOnClickListener(this);
mp = MediaPlayer.create(this, R.raw.sound);
}
public void onClick(View v) {
switch (event.getAction()) {
case MotionEvent.ACTION_DOWN:
mp.setLooping(true);
mp.start();
break;
case MotionEvent.ACTION_UP:
mp.pause();
break;
}
}
}
the log
thanks
I think the problem is in the line switch (event.getAction()) {. Where did you initialize event? I think this causes the NullPointerException.
Btw... You shouldn't name your class main. Use Main at least.
I'm not seeing event being set to a non-null value in the code you posted. Unfortunately, there is no "up" or "down" to a click event received via an OnClickListener.
If you're looking for a toggle-like effect, you might use MediaPlayer#isPlaying():
public void onClick(View v) {
if (mp.isPlaying()) {
mp.pause();
} else {
mp.setLooping(true);
mp.start();
}
}
If you need to handle MotionEvent.UP and MotionEvent.DOWN then you should implement View.OnTouchListener:
#Override
public boolean onTouch(View v, MotionEvent event) {
switch (event.getAction()) {
case MotionEvent.ACTION_DOWN:
mp.setLooping(true);
mp.start();
return true;
case MotionEvent.ACTION_UP:
mp.pause();
return true;
}
return false;
}
and then set it using setOnTouchListener:
zero.setOnTouchListener(this);