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;
}
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;
}
Situation : I have a BottomSheet that expands on a button click (fig. 1), on the upper right corner of the BottomSheet I put an ImageView that works as a closing button, in other words when the ImageView is clicked the Bottomsheet state will be changed to HIDDEN
what I tried :
I tried to assign the imageview an onTouchListener (check code take #1) but I got a NullPointerException mainly because the bottomsheet was hidden and the imageview is not visible to user so I tried adding an if to check if the bottomsheet state is expanded and if so do the closing stuff (check code take #2)
Code take #1
//this is where I got the NullPointerException
CloseSheet.setOnTouchListener(new View.OnTouchListener() {
#Override
public boolean onTouch(View v, MotionEvent event) {
if(event.getAction() == MotionEvent.ACTION_DOWN){
}
else if(event.getAction() == MotionEvent.ACTION_UP){
bottomSheetBehavior.setState(BottomSheetBehavior.STATE_HIDDEN);
}
else if(event.getAction() == MotionEvent.ACTION_CANCEL){
}
return true;
}
});
Code take #2
//this is where I dont get a response on click
if(bottomSheetBehavior.getState() == BottomSheetBehavior.STATE_EXPANDED ){
CloseSheet.setOnTouchListener(new View.OnTouchListener() {
#Override
public boolean onTouch(View v, MotionEvent event) {
if(event.getAction() == MotionEvent.ACTION_DOWN){
}
else if(event.getAction() == MotionEvent.ACTION_UP){
bottomSheetBehavior.setState(BottomSheetBehavior.STATE_HIDDEN);
}
else if(event.getAction() == MotionEvent.ACTION_CANCEL){
}
return true;
}
});
}
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)
I would like to start a timer that begins when a button is first pressed and ends when it is released (basically I want to measure how long a button is held down). I'll be using the System.nanoTime() method at both of those times, then subtract the initial number from the final one to get a measurement for the time elapsed while the button was held down.
(If you have any suggestions for using something other than nanoTime() or some other way of measuring how long a button is held down, I'm open to those as well.)
Thanks!
Andy
Use OnTouchListener instead of OnClickListener:
// this goes somewhere in your class:
long lastDown;
long lastDuration;
...
// this goes wherever you setup your button listener:
button.setOnTouchListener(new OnTouchListener() {
#Override
public boolean onTouch(View v, MotionEvent event) {
if(event.getAction() == MotionEvent.ACTION_DOWN) {
lastDown = System.currentTimeMillis();
} else if (event.getAction() == MotionEvent.ACTION_UP) {
lastDuration = System.currentTimeMillis() - lastDown;
}
return true;
}
});
This will definitely work:
button.setOnTouchListener(new OnTouchListener() {
#Override
public boolean onTouch(View v, MotionEvent event) {
if(event.getAction() == MotionEvent.ACTION_DOWN) {
increaseSize();
} else if (event.getAction() == MotionEvent.ACTION_UP) {
resetSize();
}
return true;
}
});
In onTouchListener start the timer.
In onClickListener stop the times.
calculate the differece.
brown = (Button) findViewById(R.id.brownButton);
brown.setOnTouchListener(new OnTouchListener() {
public boolean onTouch(View v, MotionEvent event) {
if (event.getAction() == MotionEvent.ACTION_DOWN) {
count++;
Log.d("count", "" + count);
return true;
} else if (event.getAction() == (MotionEvent.ACTION_UP)) {
count--;
Log.d("count", "" + count);
return true;
}
return false;
}
});
When my finger presses and holds the button my count will only increment ONCE. When I let go it will decrement accordingly. Please can someone show me how I can get my code to increment as long as my finger is holding the button down. Thanks.
A touch listener works like this:
It receives a ACTION_DOWN event (the user touches)
It then receives all the following events (if true is returned) and treats all the following events as ACTION_MOVE events
The touch lisetener keeps receiving ACTION_MOVE events until it receives an ACTION_UP or ACTION_CANCEL event.
So ACTION_DOWN is only triggered once, then any number of ACTION_MOVE events, then either a single ACTION_UP or ACTION_CANCEL.
If you want your counter to increment you need to check for ACTION_MOVE events.
#Override
public boolean onTouch(View v, MotionEvent event) {
switch(event.getAction()){
case MotionEvent.ACTION_DOWN:
//do something on DOWN
break;
case MotionEvent.ACTION_MOVE:
//do something on MOVE
break;
case MotionEvent.ACTION_UP:
//do something on UP
break;
}
return true;
}
I also needed to do this, but this question was never adequately answered, even though it is fairly old. However, a good solution can be found here: android repeat action on pressing and holding a button
I am adapting that solution to this problem. I tested it and it works for me.
Button brown = (Button) findViewById(R.id.brownButton);
brown.setOnTouchListener(new View.OnTouchListener() {
private Handler mHandler;
private int count = 0;
#Override
public boolean onTouch(View v, MotionEvent event) {
switch (event.getAction()) {
case MotionEvent.ACTION_DOWN:
if (mHandler != null)
return true;
mHandler = new Handler();
mHandler.postDelayed(mAction, 500);
break;
case MotionEvent.ACTION_UP:
if (mHandler == null)
return true;
mHandler.removeCallbacks(mAction);
mHandler = null;
break;
}
return true; // before I had written false
}
Runnable mAction = new Runnable() {
#Override
public void run() {
Log.d("count: ", "" + count);
count++;
mHandler.postDelayed(this, 500);
}
};
});
In the future I will apply this solution to a custom soft keyboard to allow the space and delete keys to continue working when being held down.
Update: Today I finally got around to making the continuous delete key. I thought I had tested my above code before, but today when I was doing it I had to return true from the onTouch method in order to get it to work.