i'm having troubles creating a scanning animation on my android application.For instance, i have come across this application 'Fingerprint love scanner prank' which has the scanning animation and i would like to implement the same on my android app. I have tried to implement the same on my android application but in vain. This is my android code snippet.
Animation.Java Activity
scan.setOnTouchListener(new View.OnTouchListener() {
#Override
public boolean onTouch(View view, MotionEvent motionEvent) {
final CountDownTimer start = new CountDownTimer(4000, 1000) {
public void onTick(long millisUntilFinished) {
scanner.setVisibility(View.VISIBLE);
anim1 = AnimationUtils.loadAnimation(getApplicationContext(), R.anim.progress);
scanner.startAnimation(anim1);
}
public void onFinish() {
scanner.setVisibility(View.INVISIBLE);
}
}.start();
return false;
}
});
Animation.xml
Contains the scanner image defined by the imageView as shown below
<LinearLayout
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:layout_marginTop="40dp"
android:id="#+id/scan"
android:background="#drawable/bgscanner">
<ImageView
android:layout_width="100dp"
android:layout_height="wrap_content"
android:src="#drawable/scanner"
android:id="#+id/scanner1"
android:layout_marginTop="20dp"
android:visibility="invisible"
/>
</LinearLayout>
My Animation drawable
<?xml version="1.0" encoding="utf-8"?>
<set xmlns:android="http://schemas.android.com/apk/res/android"
android:interpolator="#android:anim/linear_interpolator"
android:fillAfter="true">
<translate
android:fromYDelta="0%p"
android:toYDelta="75%p"
android:duration="800"
/>
</set>
My big issue is, on touch event, the animation does not execute. That is, the image bar does not oscillate along the vertical axis. I kindly request any assistance from stackoverflow
Edited
This problem can be solved with a very small code.
First, change your XML animation code to this:
<set xmlns:android="http://schemas.android.com/apk/res/android"
android:interpolator="#android:anim/accelerate_decelerate_interpolator"
android:fillAfter="false">
<translate
android:fromYDelta="0%p"
android:toYDelta="100%p"
android:duration="1000"
android:repeatCount="infinite"
android:repeatMode="restart"
/>
</set>
Your layout should be something like this:
<LinearLayout
android:id="#+id/image"
android:layout_width="200dp"
android:layout_height="200dp"
android:background="#mipmap/ic_launcher">
<View
android:id="#+id/bar"
android:layout_width="200dp"
android:layout_height="6dp"
android:visibility="gone"
android:background="#android:color/black"
android:src="#mipmap/ic_launcher"/>
</LinearLayout>
And in your activity, the code can be like this:
LinearLayout imageView = (LinearLayout) findViewById(R.id.image);
final View bar = findViewById(R.id.bar);
final Animation animation = AnimationUtils.loadAnimation(MainActivity.this, R.anim.anim);
animation.setAnimationListener(new Animation.AnimationListener() {
#Override
public void onAnimationStart(Animation animation) {}
#Override
public void onAnimationEnd(Animation animation) {
bar.setVisibility(View.GONE);
}
#Override
public void onAnimationRepeat(Animation animation) {}
});
imageView.setOnTouchListener(new View.OnTouchListener() {
#Override
public boolean onTouch(View view, MotionEvent motionEvent) {
bar.setVisibility(View.VISIBLE);
bar.startAnimation(animation);
return false;
}
});
And this way you are going to have this result:
I used a View instead of a ImageView to make the scan bar, but you can change the code to your needs.
I hope it helps!
EDIT 2:
If you want the animation to happen only if your image is pressed, change the code to this:
imageView.setOnTouchListener(new View.OnTouchListener() {
#Override
public boolean onTouch(View view, MotionEvent motionEvent) {
if(motionEvent.getAction() == MotionEvent.ACTION_DOWN){
bar.setVisibility(View.VISIBLE);
bar.startAnimation(animation);
} else if(motionEvent.getAction() == MotionEvent.ACTION_UP){
bar.setVisibility(View.GONE);
animation.cancel();
}
return false;
}
});
It you trigger the animation when the image is pressed (MotionEvent.ACTION_DOWN) and it is going to stop the animation when the image is released (MotionEvent.ACTION_UP)
Instead of countDownTimer use value animator for the animation in onTouch listner.
scan.setOnTouchListener(new View.OnTouchListener() {
#Override
public boolean onTouch(View view, MotionEvent motionEvent) {
if(motionEvent.getAction==MotionEvent.ACTION_DOWN){
ValueAnimator valueAnimator=ValueAnimator.ofFloat(0,75);
valueAnimator.setDuration(4000);
valueAnimator.setInterpolator(new DecelerateInterpolator());
valueAnimator.addListener(new Animator.AnimatorListener() {
#Override
public void onAnimationStart(Animator animation) {
scanner.setVisibilty(View.VISIBLE);
}
#Override
public void onAnimationEnd(Animator animation) {
scanner.setVisibilty(View.INVISIBLE);
}
#Override
public void onAnimationCancel(Animator animation) {
scanner.setVisibilty(View.INVISIBLE);
}
#Override
public void onAnimationRepeat(Animator animation) {
}
});
valueAnimator.addUpdateListener(new ValueAnimator.AnimatorUpdateListener() {
#Override
public void onAnimationUpdate(ValueAnimator animation) {
float translate= (float) animation.getAnimatedValue();
scanner.setTranslationY(translate);//translate scanner in Y direction
}
});
valueAnimator.start();
}
return true;
}
For animation on android , i advice you to use Animation Drawable , it's simple to implement : https://developer.android.com/reference/android/graphics/drawable/AnimationDrawable.html
First steps to display a animation (Gif by example) , we split it to pngs (online by example i have use http://ezgif.com/ , then i apply the initialisation on xml drawable :
<!-- Animation frames are wheel0.png through wheel5.png
files inside the res/drawable/ folder -->
<animation-list android:id="#+id/selected" android:oneshot="false">
<item android:drawable="#drawable/wheel0" android:duration="50" />
<item android:drawable="#drawable/wheel1" android:duration="50" />
<item android:drawable="#drawable/wheel2" android:duration="50" />
<item android:drawable="#drawable/wheel3" android:duration="50" />
<item android:drawable="#drawable/wheel4" android:duration="50" />
<item android:drawable="#drawable/wheel5" android:duration="50" />
</animation-list>
Finally i load it on my defined class :
// Load the ImageView that will host the animation and
// set its background to our AnimationDrawable XML resource.
ImageView img = (ImageView)findViewById(R.id.spinning_wheel_image);
img.setBackgroundResource(R.drawable.spin_animation);
// Get the background, which has been compiled to an AnimationDrawable object.
AnimationDrawable frameAnimation = (AnimationDrawable) img.getBackground();
// Start the animation (looped playback by default).
frameAnimation.start();
change your animation to this
<set xmlns:android="http://schemas.android.com/apk/res/android"
android:interpolator="#android:anim/linear_interpolator"
duration="4000"
android:repeatMode="reverse"
android:fillAfter="false">
<translate
android:fromYDelta="0%p"
android:toYDelta="75%p"
android:duration="800"/>
</set>
and your code
scan.setOnTouchListener(new View.OnTouchListener() {
#Override
public boolean onTouch(View view, MotionEvent motionEvent) {
scanner.setVisibility(View.VISIBLE);
anim1 = AnimationUtils.loadAnimation(getApplicationContext(), R.anim.progress);
anim1.setAnimationListener(new Animation.AnimationListener() {
#Override
public void onAnimationStart(Animation animation) {
}
#Override
public void onAnimationEnd(Animation animation) {
scanner.setVisibility((View.INVISIBLE)
}
#Override
public void onAnimationRepeat(Animation animation) {
}
});
scanner.startAnimation(anim1);
}
});
Try this:
#Override
public boolean onTouch(View view, MotionEvent motionEvent) {
final CountDownTimer start = new CountDownTimer(4000, 1000) {
anim1 = AnimationUtils.loadAnimation(getApplicationContext(),
R.anim.progress);
// set animation listener
anim1.setAnimationListener(this);
// button click event
scan.setOnClickListener(new View.OnClickListener() {
#Override
public void onTick(View v) {
scanner.setVisibility(View.VISIBLE);
// start the animation
scanner.startAnimation(anim1);
}
});
}
#Override
public void onAnimationEnd(Animation animation) {
// Take any action after completing the animation
// check for fade in animation
if (animation == anim1) {
Toast.makeText(getApplicationContext(), "Animation Stopped",
Toast.LENGTH_SHORT).show();
}
}
Related
I need to create animation where I will display 3 images. Each image should completely fade in and fade out (slow blink) and then next image should be shown. I have done it by creating 3 animations. Each animation starts the next animation in onAnimationEnd listener:
private void startAnimation() {
final Animation aniIn = AnimationUtils.loadAnimation(this,
R.anim.fade_in_out);
final Animation aniIn1 = AnimationUtils.loadAnimation(this,
R.anim.fade_in_out);
final Animation aniIn2 = AnimationUtils.loadAnimation(this,
R.anim.fade_in_out);
aniIn.setAnimationListener(new Animation.AnimationListener() {
#Override
public void onAnimationStart(Animation animation) {
ivRandom0.setVisibility(View.VISIBLE);
}
#Override
public void onAnimationEnd(Animation animation) {
ivRandom0.setVisibility(View.INVISIBLE);
ivRandom1.startAnimation(aniIn1);
}
#Override
public void onAnimationRepeat(Animation animation) {
}
});
aniIn1.setAnimationListener(new Animation.AnimationListener() {
#Override
public void onAnimationStart(Animation animation) {
ivRandom1.setVisibility(View.VISIBLE);
}
#Override
public void onAnimationEnd(Animation animation) {
ivRandom1.setVisibility(View.INVISIBLE);
ivRandom2.startAnimation(aniIn2);
}
#Override
public void onAnimationRepeat(Animation animation) {
}
});
aniIn2.setAnimationListener(new Animation.AnimationListener() {
#Override
public void onAnimationStart(Animation animation) {
ivRandom2.setVisibility(View.VISIBLE);
}
#Override
public void onAnimationEnd(Animation animation) {
showFinal();
}
#Override
public void onAnimationRepeat(Animation animation) {
}
});
ivRandom0.startAnimation(aniIn);
}
For that animation I have this xml which sets alhpa from 0 to 1 and back to 0:
fade_in_out.xml:
<?xml version="1.0" encoding="utf-8"?>
<set xmlns:android="http://schemas.android.com/apk/res/android"
android:fillAfter="true">
<alpha
android:duration="300"
android:fromAlpha="0"
android:interpolator="#android:anim/accelerate_decelerate_interpolator"
android:toAlpha="1"
android:repeatCount="1"
android:repeatMode="reverse"
/>
</set>
here is my layout:
<RelativeLayout
android:id="#+id/images_wrapper"
android:layout_width="match_parent"
android:layout_height="wrap_content"
>
<ImageView
android:id="#+id/iv_image_random_0"
android:layout_width="match_parent"
android:layout_height="wrap_content"
android:layout_centerInParent="true"
android:src="#drawable/img_generator0"
android:visibility="visible" />
<ImageView
android:id="#+id/iv_image_random_1"
android:layout_width="match_parent"
android:layout_height="wrap_content"
android:layout_centerInParent="true"
android:src="#drawable/img_generator1"
android:visibility="invisible" />
<ImageView
android:id="#+id/iv_image_random_2"
android:layout_width="match_parent"
android:layout_height="wrap_content"
android:layout_centerInParent="true"
android:src="#drawable/img_generator2"
android:visibility="invisible" />
</RelativeLayout>
Although this is working, I don't like the nested callbacks. It is also causing memory leak as it is holding reference to imageviews in calbacks.
Is there a better way how to create this kind of animation? Or at least avoid the memory leak? I was trying imageswitcher, but it is causing cross fading of images which I don't want.
Thank you!
you can use ObjectAnimator , it has methods to setDuration and start delays , which you can calculate according to your need.
ObjectAnimator objectAnimator = ObjectAnimator.ofFloat(imageView, "alpha",0, 1);
objectAnimator.setDuration(DEFAULT_ANIMATION_DURATION);
objectAnimator.setStartDelay(milliseconds);
objectAnimator.start();
you can create three different object animators to set accordinglt . for more refer this link
You can use viewswitcher to implement this behaviour. Please see the code below:
layout
<ViewSwitcher
android:id="#+id/switcher"
android:layout_width="match_parent"
android:layout_height="wrap_content"
android:layout_alignParentTop="true"
android:layout_centerHorizontal="true"
android:inAnimation="#anim/fade_in"
android:outAnimation="#anim/fade_out" >
<ImageView
android:layout_width="match_parent"
android:layout_height="wrap_content"
android:scaleType="fitCenter"
android:src="#drawable/sunset" />
<ImageView
android:layout_width="match_parent"
android:layout_height="wrap_content"
android:scaleType="fitCenter"
android:src="#drawable/clouds" />
</ViewSwitcher>
code
((ViewSwitcher) findViewById(R.id.switcher)).setOnClickListener(new View.OnClickListener() {
#Override
public void onClick(View v) {
ViewSwitcher switcher = (ViewSwitcher) v;
if (switcher.getDisplayedChild() == 0) {
switcher.showNext();
} else {
switcher.showPrevious();
}
}
});
Please refer this link
I'm having a trouble with animations in android. I have my animation_char.xml:
<set xmlns:android="http://schemas.android.com/apk/res/android">
<alpha
android:duration="300"
android:fromAlpha="0.0"
android:interpolator="#android:anim/accelerate_interpolator"
android:toAlpha="1.0"/>
</set>
That is ok, but in my MainActivity I want to start an animation one after one. So I created a method to make it more easy and just change the ImageView
public void animation(ImageView imageView){
animation = AnimationUtils.loadAnimation(getApplicationContext(),R.anim.animation_char);
imageView.startAnimation(animation);
}
And for make consecutives animations, I'm trying to use AnimatorSet. But as I read AnimatorSet works with Animator, not with Animation. So my question is:
is there a way to load an animation in a animator?? Or should I use another way in order to achieve what I want to do? Thanks in advance!
EDIT
I changed my method and now Im trying with this but the problem is that all the images appear at the same time, how can I add some delay between animations?
public void animation() {
animation= AnimationUtils.loadAnimation(getApplicationContext(),R.anim.animation_char);
w.startAnimation(animation);
a.startAnimation(animation);
r.startAnimation(animation);
}
Actually I've answered on this question here. You should start your second animation in onAnimationEnd of AnimationListener of first animations. The same for second one.
You should use AnimationSet class instead of AnimatorSet.
For instance
AnimationSet as = new AnimationSet(true);
as.setFillEnabled(true);
as.setInterpolator(new BounceInterpolator());
as.addAnimation(firstAnim);
as.addAnimation(secondAnim);
as.setDuration(1000);
imageView.startAnimation(as);
I put this here maybe it helps someone...
I did something like this. I have 3 images that I want to fall one after the other.
note1 = findViewById(R.id.note1);
note1.setVisibility(View.INVISIBLE);
note2 = findViewById(R.id.note2);
note2.setVisibility(View.INVISIBLE);
note3 = findViewById(R.id.note3);
note3.setVisibility(View.INVISIBLE);
Setting visibility so that they are not shown initially
And then create 3 animations
Animation slideDown = AnimationUtils.loadAnimation(this, R.anim.slide_down);
note1.startAnimation(slideDown);
final Animation slideDown2 = AnimationUtils.loadAnimation(SplashScreen.this, R.anim.slide_down);
final Animation slideDown3 = AnimationUtils.loadAnimation(SplashScreen.this, R.anim.slide_down);
Next step is to add the event listeners that #Divers added:
slideDown.setAnimationListener(new Animation.AnimationListener() {
#Override
public void onAnimationStart(Animation animation) {
}
#Override
public void onAnimationEnd(Animation animation) {
note1.setVisibility(View.VISIBLE);
note2.startAnimation(slideDown2);
slideDown2.setAnimationListener(new Animation.AnimationListener() {
#Override
public void onAnimationStart(Animation animation) {
}
#Override
public void onAnimationEnd(Animation animation) {
note3.startAnimation(slideDown3);
note2.setVisibility(View.VISIBLE);
slideDown3.setAnimationListener(new Animation.AnimationListener() {
#Override
public void onAnimationStart(Animation animation) {
}
#Override
public void onAnimationEnd(Animation animation) {
note3.setVisibility(View.VISIBLE);
}
#Override
public void onAnimationRepeat(Animation animation) {
}
});
}
#Override
public void onAnimationRepeat(Animation animation) {
}
});
}
#Override
public void onAnimationRepeat(Animation animation) {
}
});
And that's all
My animation xml is something like
<?xml version="1.0" encoding="utf-8"?>
<set xmlns:android="http://schemas.android.com/apk/res/android">
<translate
android:duration="800"
android:fromXDelta="0%"
android:fromYDelta="-50%p"
/>
<alpha
android:duration="500"
android:fromAlpha="0.1"
android:toAlpha="1.0"
/>
</set>
If you use Kotlin, you can use this way:
doOnEnd {startDelay = 1000L
start() }
Where repeatCount = 1
look at this example:
val animations = arrayOf(-140f).map { translation ->
ObjectAnimator.ofFloat(binding.viewYatch, "translationX", translation).apply {
//Update
duration = 800
repeatCount = 1
repeatMode = ObjectAnimator.RESTART
doOnEnd {
startDelay = 1000L
start()
}
}
}
val set = AnimatorSet()
set.playTogether(animations)
set.start()
I'm doing some translate animations with a view. I'm trying both ways: By xml and programmatically.
This is how I have defined the translation by xml:
<set xmlns:android="http://schemas.android.com/apk/res/android">
<translate android:fromYDelta="0%" android:toYDelta="-70%" android:duration="1000"/>
</set>
This way it works fine, but I've realized that I better need the programmatically way as using the animationListener I can define actions to occurr when the animation finishes.
This is how I do it programmatically:
slide_up = new TranslateAnimation(valuesContainer.getX(),
valuesContainer.getX(),
valuesContainer.getY(),
valuesContainer.getY() - 70);
slide_up.setDuration(1000);
slide_up.setAnimationListener(new AnimationListener() {
#Override
public void onAnimationStart(Animation animation) {
// TODO Auto-generated method stub
}
#Override
public void onAnimationRepeat(Animation animation) {
}
#Override
public void onAnimationEnd(Animation animation) {
//SOMETHING HAPPENS
}
});
The problem comes when defining the fromYDelta and toYDelta values (the image just moves in the Y axis). In the xml, I do it using percentages (%) and it works the way I need, but I don't know how to set the values this same way but programmatically.
I have come to a solution combining both of this methods.
I define the animation in a xml like this, called f.e. slide_up_anim.xml
<set xmlns:android="http://schemas.android.com/apk/res/android">
<translate android:fromYDelta="0%" android:toYDelta="-70%" android:duration="1000"/>
</set>
And then, I set the AnimationListener for this animation this way:
slide_up = AnimationUtils.loadAnimation(getActivity(), R.anim.slide_up_anim);
slide_up.setAnimationListener(new AnimationListener() {
#Override
public void onAnimationStart(Animation animation) {
}
#Override
public void onAnimationRepeat(Animation animation) {
}
#Override
public void onAnimationEnd(Animation animation) {
}
});
This way I can define the fromYDelta and toYDelta in percentage, and also listen for animation events.
In my activity, I have a start button, and when that's clicked it should fade out and finally disappear by setVisibility(View.GONE)
The problem is setting visibility to GONE doesn't disappear the view, it's still visible. I've purposefully made the view animation fade out to 0.1 (instead of 0) and I can see it in the background even after I've called setVisibility(View.GONE) on it.
The fadeout animation anim_fade_out.xml is:
<?xml version="1.0" encoding="utf-8"?>
<set
xmlns:android="http://schemas.android.com/apk/res/android"
android:interpolator="#android:anim/linear_interpolator"
android:fillAfter="true" android:fillEnabled="true">
<alpha
android:fromAlpha="1.0"
android:toAlpha="0.1"
android:duration="200" />
</set>
The method is showTimer():
private void showTimer() {
final LinearLayout startButtonArea = (LinearLayout)findViewById(R.id.startButtonArea);
Animation animFadeOut = AnimationUtils.loadAnimation(getApplicationContext(), R.anim.anim_fade_out);
startButtonArea.startAnimation(animFadeOut);
animFadeOut.setAnimationListener(new AnimationListener() {
#Override
public void onAnimationEnd(Animation animation) {
startButtonArea.setVisibility(View.GONE);
Log.d("Animation ended","startButtonArea SHOULD BE GONE BUT IT ISN'T");
}
#Override
public void onAnimationRepeat(Animation animation) {}
#Override
public void onAnimationStart(Animation animation) {}
});
}
To reiterate, I know that the end alpha of the animation is 0.1 (it would be 0 usually) but I want to confirm that the view is really GONE and it isn't.
Because your fillAfter is true, the animation sets the properties after your onAnimationEnd is called. You can either change fillAfter to false, or do it like this:
#Override
public void onAnimationEnd(Animation animation) {
new Handler().postDelayed(new Runnable() {
#Override
public void run() {
startButtonArea.setVisibility(View.GONE);
Log.d("Animation ended","startButtonArea SHOULD BE GONE BUT IT ISN'T");
}
}, 0);
}
I am working on a project that must work on Android 2.2 onwards, and I just realized I was using a 3.0+ method from View.
I have a menu that animates vertically sliding in/out when a button is pressed. When the animation finishes I update the View position with setY() method.
I tried to change it to getTop/setTop but it's not working properly, I suspect because getY is actually taking into account transformations and getTop is not (I guess animations are handled as transformations).
Any easy alternative for Froyo without modifying too much code?
This is the animation part:
animationSlideInDown = AnimationUtils.loadAnimation(this, R.anim.slide_out_down);
animationSlideOutUp = AnimationUtils.loadAnimation(this, R.anim.slide_in_up);
animationSlideInDown.setDuration(200);
animationSlideOutUp.setDuration(200);
animationSlideInDown.setAnimationListener(new AnimationListener() {
#Override
public void onAnimationStart(Animation animation) {
if (menuInitialPosition == -1) {
menuInitialPosition = menu.getY();
menuHeight = menu.getHeight();
} else {
menu.setY(menuInitialPosition);
}
}
#Override
public void onAnimationRepeat(Animation animation) {}
#Override
public void onAnimationEnd(Animation animation) {
menu.setY(menuInitialPosition);
}
});
animationSlideOutUp.setAnimationListener(new AnimationListener() {
#Override
public void onAnimationStart(Animation animation) {}
#Override
public void onAnimationRepeat(Animation animation) {}
#Override
public void onAnimationEnd(Animation animation) {
menu.setY(-menuHeight);
}
});
This is the slide_out transition:
<translate
xmlns:android="http://schemas.android.com/apk/res/android"
android:fromYDelta="-100%"
android:toYDelta="0"
android:fillAfter="true"
android:fillEnabled="true"
android:duration="#android:integer/config_longAnimTime" />
Thanks!
If you want to get position of particular view on the screen than you can use :
int[] locationOnScreen = new int[2];
menu.getLocationOnScreen(locationOnScreen);
And for setting view to particular position you can use LayoutParams and set left and top margin for the view.