Trying to get functionality for an image preview working, where holding the finger over a thumbnail displays the full image. Releasing the finger will make the full image disappear.
This was easy enough to implement, but if the user moves their finger off the ImageView before release, the ACTION_UP will not fire.
#Override
public boolean onTouch(View v, MotionEvent e)
{
if (v.getId() == R.id.gallery_iv_pose_thumb)
{
// This works fine
if (e.getAction() == MotionEvent.ACTION_DOWN)
{
preview.setImageBitmap(galleryAdapter.getGalleryItemFromChildView(v).getImage());
preview.setVisibility(View.VISIBLE);
return true;
}
// This only fires if a finger is released over the initial view
else if (e.getAction() == MotionEvent.ACTION_UP)
{
preview.setVisibility(View.INVISIBLE);
return true;
}
}
I attempted to simply listen to the ACTION_UP event for the entire layout, but this requires to have handled the ACTION_DOWN for the layout as well... which stops me from listening for the ACTION_DOWN event for the thumbnail.
Any help would be appreciated!
If you move outside of the bounds, ACTION_CANCEL will be called.
So this should work:
else if (e.getAction() == MotionEvent.ACTION_UP || e.getAction() == MotionEvent.ACTION_CANCEL)
Related
I'm banging my head with this problem which probably is simple but since I'm new to this topic I somehow haven't been able to figure it out yet.
I've successfully implemented dragging a view with onTouch method. I've also successfully implemented onLongClick and onClick methods. But both of these functionalities were implemented separately.
The problem, like the title says is when I want to join these functionalities. I want the onTouch method to be called when a user long clicks a view and I want a new activity to start when a user clicks a view.
Here is the pseudo code:
public class Website extends AppCompatActivity implements View.OnTouchListener{
TextView longpress;
#Override
public void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
setContentView(R.layout.activity_website);
longpress = (TextView) findViewById(R.id.longpress);
longpress.setOnLongClickListener(new View.OnLongClickListener() {
#Override
public boolean onLongClick(View view){
//I don't really know how to do this part
onTouch(View view, Motion Event event);
return true;
}
});
longpress.setOnClickListener(new View.OnClickListener(){
#Override
public void onClick(View v){
//Code for new activity comes here (I know how to do this part)
}
});
}
public boolean onTouch(View view, MotionEvent event) {
switch(event.getAction(){
case MotionEvent.ACTION_DOWN:
//Save initial coordinates of view <-- view.getX(), view.getY()
break;
case MotionEvent.ACTION_MOVE:
//Calculate dX and dY and setX and Y of the view (move view)
break;
case MotionEvent.ACTION_UP:
//If view is certain distance away from initial points do something
break;
}
}
}
Like I said, onTouch works on itself if I don't try to call it from onLongClick method. If I try to call onTouch(View view, MotionEvent event) from onLongClick method the problem occurs because onLongClick only receives one out of two arguments onTouch method should receive (onLongClick only receives view argument but it should also receive event argument).
Maybe I'm trying to do this in a totally wrong way but I have been looking at some documentation e.g. https://developer.android.com/training/gestures/ but still won't get an idea what to do.
(I would like to have a similar functionality to notifications on android phones)
So I've come to a solution which might or might not be a good one but for now it serves my functionality. If someone has a better solution and thinks mine is bad in some way please say so.
Here is the code:
boolean flag;
public boolean onTouch(View view, MotionEvent event){
int action = event.getAction() & MotionEvent.ACTION_MASK;
if(action == MotionEvent.ACTION_DOWN){
//do something on a down press
flag = true;
return true;
}
if(action == MotionEvent.ACTION_UP && flag == true){
//do something if we move finger away from screen we
//didn't move the view first
return true;
}
if(action == MotionEvent.ACTION_UP && flag == false){
//do something if we move finger away from screen and we moved
//the view before we moved the finger away from screen
}
if(action == MotionEvent.ACTION_MOVE){
//do something when moving the view
flag = false;
}
I have created a button that fades in when it is being touched and fades out when it isn't. I was able to achieve this by using setAlpha in java. The code and the problem is shown below:
buttonPressed.getBackground().setAlpha(0);
buttonPressed.setOnTouchListener(new View.OnTouchListener() {
public boolean onTouch(View view, MotionEvent event) {
if (event.getAction() == MotionEvent.ACTION_DOWN) {
buttonPressed.getBackground().setAlpha(255);
buttonPressed.startAnimation(animationFadeIn);
return true;
} else if (event.getAction() == MotionEvent.ACTION_UP) {
buttonPressed.startAnimation(animationFadeOut);
return true;
}
return false;
}
});
The issue I have is whenever I release the button, the alpha is set to 0 before animationFadeOut is able to fully play, so the button does not fade back.
If I remove the line:
buttonPressed.getBackground().setAlpha(0);
then animationFadeOut will play but it will immediately go back to setAlpha(255).
How can I get animationFadeOut to play fully and have the button alpha be 0 when the user stops touching the button?
I think using setInterpolator() for fadeIn and fadeOut animation solves your problem.
eg:
Animation animationFadeIn = new AlphaAnimation(0, 1);
animationFadeIn.setInterpolator(new DecelerateInterpolator());
animationFadeIn.setDuration(1000);
Animation animationFadeOut = new AlphaAnimation(1, 0);
animationFadeOut.setInterpolator(new AccelerateInterpolator());
animationFadeOut.setDuration(1000);
I got his solution from this link and you can know more about AccelerateInterpolator here.
Currently unable to test it. But seems to be promising. Hope this helps!
Better not to set the alpha manually, use animators to set the alpha
// Define the animators
Animation fadeInAnimation = new AlphaAnimation(0.0f, 1.0f);
Animation fadeOutAnimation = new AlphaAnimation(1.0f, 0.0f);
// Duration of animation
fadeInAnimation.setDuration(1000);
fadeOutAnimation.setDuration(1000);
public boolean onTouch(View view, MotionEvent event) {
if (event.getAction() == MotionEvent.ACTION_DOWN) {
buttonPressed.startAnimation(fadeInAnimation);
return true;
} else if (event.getAction() == MotionEvent.ACTION_UP) {
buttonPressed.startAnimation(fadeOutAnimation);
return true;
}
return false;
}
I know that if you want to check if someone clicked on something, you would do
if(event.getAction() == MotionEvent.ACTION_DOWN)
But I want to check if the screen hasn't been clicked at all.
What is the code I would produce in order to do this?
Also, as a side note, would it be a good idea to have all the classes in an Android app extend the View classes?
Create a boolean variable called istouched and use onTouchLisener on your top most View actually its a Window that's where your Views are, quick sample
getWindow().getDecorView().setOnTouchListener(new OnTouchListener() {
#Override
public boolean onTouch(View arg0, MotionEvent event) {
if(event.getAction() == MotionEvent.ACTION_UP){
// i have been touched
istouched = true;
Toast.makeText(getBaseContext(), "you touched me?!! - i will tell my mom", Toast.LENGTH_SHORT).show();
return true;
}
if(event.getAction() == MotionEvent.ACTION_DOWN){
// you can implement this
Toast.makeText(getBaseContext(), "shhh; i am touching", Toast.LENGTH_SHORT).show();
return true;
}
return false;
}
});
so the logic here is if istouched is false your device is not telling her mom, which means it has not being touched..
hope it helps
One way is to add android:onClick="method" to the root layout in your layout xml.
in the method you can change a boolean variable to true (screenClicked = true).
So I want to create buttons that play music as long as it is pressed, but once it is released, the music stops.
In my createListeners(), I have the following:
b1.setOnTouchListener(new View.OnTouchListener() {
#Override
public boolean onTouch(View v, MotionEvent event) {
if(event.getAction() == MotionEvent.ACTION_DOWN) {
startBeat(1, m1);
return true;
} else if (event.getAction() == MotionEvent.ACTION_UP) {
m1.stop();
}
return false;
}
});
m1 is a MediaPlayer, and in the method startBeat, m1.start() has been called.
When running the app, the music plays fine, as long as I don't release the button. However, the moment I release the button, the app says it stopped unexpectedly. What could be causing this problem?
Is there another way I could go about implementing this feature?
Maybe you try play again the MediaPlayer ??
Calling stop() stops playback and causes a MediaPlayer in the Started, Paused, Prepared or PlaybackCompleted state to enter the Stopped state.
Once in the Stopped state, playback cannot be started until prepare() or prepareAsync() are called to set the MediaPlayer object to the Prepared state again.
If you don't, try m1.pause(); and m1.seekTo(0) to simulate the stop...
public boolean onTouch(View v, MotionEvent event) {
if(event.getAction() == MotionEvent.ACTION_DOWN) {
startBeat(1, m1);
return true;
} else if (event.getAction() == MotionEvent.ACTION_UP) {
m1.pause();
m1.seekTo(0);
return true;
}
return false;
}
EDIT: I found out what I was doing wrong. I was initializing and starting the MediaPlayer in my startBeat method, and stopping the player in the onTouch method. Once I moved it all into onTouch, it worked. So I guess something weird was happening before. Thanks for the answers!
I wrote a service class which creates a transparent view (LinearLayout).
If the user is holding down, some music starts to play.
This runs fine, but the problem is that if I am in the android menu or in another app, I am not able to press any buttons. (My view seems to don't let the TouchEvents pass)
I have tried a lot of things like returning false or stopping the interception, but I am still not able to press any gui controls when the service is running.
How do I correctly pass the TouchEvent back to the System?
#Override
public boolean onTouch(View v, MotionEvent event) {
v.getParent().requestDisallowInterceptTouchEvent(true);
if(event.getAction() == MotionEvent.ACTION_DOWN || event.getAction() ==
MotionEvent.ACTION_UP)
Log.i(TAG, "Action :" + event.getAction() + "\t X :" + event.getRawX()
+ "\t Y :" + event.getRawY());
if(event.getAction() == MotionEvent.ACTION_DOWN) {
if(!mp.isPlaying())
mp.start();
}
if(event.getAction() == MotionEvent.ACTION_UP) {
mp.pause();
}
//View parent = (View) v.getParent().getParent();
//parent.onTouchEvent(event);
v.onTouchEvent(event);
return false;
}
This runs fine, but the problem is that if I am in the android menu or in another app, I am not able to press any buttons. (My view seems to don't let the TouchEvents pass)
This is by design.
How do I correctly pass the TouchEvent back to the System?
You don't. If you have the ability to see a touch event via a system window, that touch event will not be dispatched to another app. This prevents "tapjacking" attacks.