I have a ViewOverlay that I use to show a Drawable on the screen. When I want to add or remove the overlay drawable on top of my view I do something like this:
ViewOverlay overlay = mView.getOverlay();
overlay.add(mDrawable);
...sometime later...
ViewOverlay overlay = mView.getOverlay();
overlay.remove(mDrawable);
However, this instantly removes my drawable from the screen. Is there a way to fade away the drawable in the overlay instead of just instantly removing it?
You have to apply the animation directly to the Drawable first and as soon as the animation is done you can call remove() to remove the overlay.
ValueAnimator animator = ValueAnimator.ofInt(255, 0);
animator.setInterpolator(new LinearInterpolator());
animator.setDuration(ANIMATION_DURATION);
animator.addUpdateListener(new ValueAnimator.AnimatorUpdateListener() {
#Override
public void onAnimationUpdate(ValueAnimator animation) {
int alpha = (int) animation.getAnimatedValue();
mDrawable.setAlpha(alpha);
mViewThatHasOverlay.invalidate();
}
});
animator.addListener(new AnimatorListenerAdapter() {
#Override
public void onAnimationEnd(Animator animation) {
ViewOverlay overlay = mViewThatHasOverlay.getOverlay();
overlay.remove(mDrawable);
}
});
animator.start();
Related
I have an ImageView with alpha=0 by default. So it acts as an invisible overlay on another image.
On click, I want to create an animation that shows the overlay image for 200ms, and then hides it again.
The following does work in general, but only a single time! Why?
final ImageView flash = (ImageView) view.findViewById(R.id.flash);
flash.animate()
.alpha(255) //make visible
.setDuration(200)
.setListener(new AnimatorListenerAdapter() {
#Override
public void onAnimationEnd(Animator animation) {
super.onAnimationEnd(animation);
flash.setImageAlpha(0); //hide again
}
});
you're setting 2 different alpha values, the first one is View's alpha, but when you end the animation you set the ImageView class alpha to 0, so if you start the animation again, the View alpha is 1.0f but the image alpha will be 0 and you see nothing.
change it to
flash.animate()
.alpha(1.f)
.setDuration(200)
.setListener(new AnimatorListenerAdapter() {
#Override
public void onAnimationEnd(Animator animation) {
super.onAnimationEnd(animation);
flash.setAlpha(0.f);
}
});
View (and therefore ImageView) has a method setAlpha(float), ImageView adds also another method setAlpha(int), which is deprecated because it's confusing as hell and now it's been renamed to setImageAlpha(int). the animation will call View's setAlpha(float)
I placed an ImageView in the centre of the screen. I then wanted to animate it from the bottom to the centre. I reasoned to move it without delay out of the screen and then back the same value which would end in the centre. However, the animation makes it so the view will exit from top.
mLogoIV.animate().translationY(1000f).setListener(new AnimatorListenerAdapter() {
#Override
public void onAnimationEnd(Animator animation) {
super.onAnimationEnd(animation);
mLogoIV.animate().translationY(-1000f).setDuration(3000);
}
});
use translationYBy( to animate relative to the current position
https://developer.android.com/reference/android/view/ViewPropertyAnimator.html#translationYBy(float)
mLogoIV.animate().translationYBy(1000f).setListener(new AnimatorListenerAdapter() {
#Override
public void onAnimationEnd(Animator animation) {
super.onAnimationEnd(animation);
mLogoIV.animate().translationYBy(-1000f).setDuration(3000);
}
});
From the docs:
The amount to be animated by, as an offset from the current value.
vs what you are doing now:
The value to be animated to.
Use Object animator.
ObjectAnimator objectAnimator= ObjectAnimator.ofFloat(mLogoIV, "translationY", -750, 0);
objectAnimator.setDuration(1000);
objectAnimator.start();
i am making an android app and i am a newbie in development.
I created a startup animation for the app, using the app icon that is scaled from O% size to 100% size and rotated at the same time. This works allright. But i have a problem with it. In xml, the view visibility is set to gone initially. In code, i call image.setVisibility(View.VISIBLE) and then image.startAnimation(iconAnimation) . But the result is that i can see a flash of the ImageView before it starts animating, for like half a second or so. You can see the gif.
Gif:
see the gif
Can you help me with this? Thanks in advance.
My code:
runOnUiThread(new Runnable() {
#Override
public void run() {
// here
image.setVisibility(View.VISIBLE);
image.startAnimation(imageAnim);
//also found this somewhere, didn't help.
image.invalidate();
}
});
Layout xml:
<TextView
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:textSize="35sp"
android:text="Kytky"
android:layout_centerInParent="true"
android:id="#+id/welcome_text"
android:visibility="gone"/>
<ImageView
android:layout_width="200dp"
android:layout_height="200dp"
android:src="#mipmap/ic_launcher"
android:layout_centerInParent="true"
android:id="#+id/welcome_image"
android:visibility="gone"/>
You can use value animator instead, You can hack through the animation
imageView.setPivotX(viewCenterX);
imageView.setPivotY(viewCenterY);
imageView.setScaleX(0);
imageView.setScaleY(0);
final FloatEvaluator scaleEvaluator = new FloatEvaluator();
final FloatEvaluator rotationEvaluator = new FloatEvaluator();
ValueAnimator valueAnimator = ValueAnimator.ofFloat(0, 1f);
valueAnimator.setDuration(TimeUnit.SECONDS.toMillis(1));
valueAnimator.setInterpolator(new DecelerateInterpolator());
valueAnimator.addUpdateListener(new ValueAnimator.AnimatorUpdateListener() {
#Override
public void onAnimationUpdate(ValueAnimator animation) {
float fraction = animation.getAnimatedFraction();
float scale = scaleEvaluator.evaluate(fraction, 0f, 1f);
float rotation = rotationEvaluator.evaluate(fraction, 0f, 360f);
imageView.setScale(scale);
imageView.setRotation(rotation);
}
});
valueAnimator.start();
Start one more animator or use this same animator to slide the logo up. Using this animators you will have full control over your animation.
you can switch the view visibility when the animations starts
imageAnim.setAnimationListener(new Animation.AnimationListener() {
#Override
public void onAnimationStart(Animation animation) {
image.setVisibility(View.VISIBLE);
}
#Override
public void onAnimationEnd(Animation animation) {
}
#Override
public void onAnimationRepeat(Animation animation) {
}
});
image.startAnimation(imageAnim);
the blink happens because the view visibility far from starting the animations, so in the first frame it will have its real size, and after that starts the animation
You need to work with alpha as well...make it visible and set alpha to minimum value than set alpha gradually to maximum value with in handler.
I'm trying to swap two images in separate Imageviews with a fade-out/fade-in. The first image fades out, then the other image fades out, then the second image fades in while replaced with the first image, then the first image fades back in while being replaced with the second image (swap images with fade out/in). The code is below. The swap is occurring okay but there is no fade out or in. What am I missing to get the alpha fade to occur? Also, if I use an integer (such as 1500) instead of mShortAnimationDuration, the animationlistener does not get triggered. setDuration argument is type long. I based my code on the example from here: https://developer.android.com/training/animation/crossfade.html
Drawable target_draw = target.getDrawable();
Drawable dragged_draw = dragged.getDrawable();
final Bitmap targetBitmap = ((BitmapDrawable)target_draw).getBitmap();
final Bitmap draggedBitmap = ((BitmapDrawable)dragged_draw).getBitmap();
//SWAP and CROSSFADE ANIMATION
dragged.setAlpha(1f);
target.setAlpha(1f);
int mShortAnimationDuration = getResources().getInteger(android.R.integer.config_shortAnimTime);
dragged.animate()
.alpha(0f)
.setDuration(mShortAnimationDuration)
.setListener(new AnimatorListenerAdapter() {
#Override
public void onAnimationEnd(Animator animation) {
dragged.setImageBitmap(targetBitmap);
dragged.invalidate();
}
});
target.animate()
.alpha(0f)
.setDuration(mShortAnimationDuration)
.setListener(new AnimatorListenerAdapter() {
#Override
public void onAnimationEnd(Animator animation) {
target.setImageBitmap(draggedBitmap);
target.invalidate();
}
});
//fade in with new images
target.animate()
.alpha(1f)
.setDuration(1500);
dragged.animate()
.alpha(1f)
.setDuration(1500);
UPDATE:
I finally came up with the following code which basically works, but due to the fact that Android is not a real-time OS, and that fact that I am swapping images and calling invalidate() during the fade transitions, makes the timing of the fades somewhat unpredictable.
dragged.animate()
.alpha(0f)
.setDuration(1000)
//.setInterpolator(new DecelerateInterpolator()) //optional
.setListener(new AnimatorListenerAdapter() {
#Override
public void onAnimationEnd(Animator animation) {
dragged.setImageBitmap(targetBitmap);
dragged.invalidate();
dragged.animate()
.alpha(1f)
//.setInterpolator(new AccelerateInterpolator())
.setDuration(1000);
//.setStartDelay(500); //also optional for timing
}
});
target.animate()
.alpha(0f)
.setDuration(1000)
.setStartDelay(500)
//.setInterpolator(new DecelerateInterpolator())
.setListener(new AnimatorListenerAdapter() {
#Override
public void onAnimationEnd(Animator animation) {
target.setImageBitmap(draggedBitmap);
target.invalidate();
target.animate()
.alpha(1f)
//.setInterpolator(new AccelerateInterpolator())
//.setStartDelay(500)
.setDuration(1000);
}
});
...update continued:
Since the timing of the fades were inconsistent due to image swapping during them, I simplified and eliminated the fade-out, and just kept the image swap and fade-in. This is the code I ended up with. I am looking for more interesting ways to animate Imageview swapping if anyone has any ideas on that.
// swap
dragged.setImageBitmap(targetBitmap);
dragged.invalidate();
target.setImageBitmap(draggedBitmap);
target.invalidate();
// then fade-in with delay
Animation fadeIn = new AlphaAnimation(0, 1);
fadeIn.setInterpolator(new DecelerateInterpolator());
Animation fadeIn2 = new AlphaAnimation(0, 1);
fadeIn2.setInterpolator(new DecelerateInterpolator());
fadeIn2.setStartOffset(300);
fadeIn.setDuration(2000);
fadeIn2.setDuration(2000);
target.startAnimation(fadeIn);
dragged.startAnimation(fadeIn2);
In android 5.0 i am trying to work with circular reveal animation
Problem
When i click on button to start reveal animation, on first click animation doesn't start
Second Click onwards it works normally
My Code
public class MainActivity extends ActionBarActivity {
Animator a;
#Override
protected void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
setContentView(R.layout.activity_main);
final View cardType = findViewById(R.id.cardtype);
cardType.setVisibility(View.GONE);
if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.LOLLIPOP) {
a = ViewAnimationUtils.createCircularReveal(cardType,
cardType.getWidth(),
cardType.getHeight(),
0,
cardType.getHeight() * 2)
.setDuration(2500);
a.addListener(new AnimatorListenerAdapter() {
#Override
public void onAnimationStart(Animator animation) {
super.onAnimationStart(animation);
cardType.setVisibility(View.VISIBLE);
}
});
a.addListener(new AnimatorListenerAdapter() {
#Override
public void onAnimationEnd(Animator animation) {
super.onAnimationEnd(animation);
cardType.setVisibility(View.GONE);
}
});
findViewById(R.id.icon_first_activity).setOnClickListener(new View.OnClickListener() {
#Override
public void onClick(View v) {
a.start();
}
});
}
}}
I haven't tried your code, but I think you have a small ordering problem. I think you just need to set the cardType visible before you start the animation.
Edited to add:
... and you should be setting your button View.INVISIBLE, not View.GONE.
Here: This code works.
Edited once more to add:
Yes. Your problem is that you set the view GONE initially. That means it has 0 size. Then you use cardType.getHeight and cardType.getWidth as reveal coordinates. They are 0. You are going to want to set the view INVISIBLE, initially, and then use width/2 and height/2 as the center of the reveal.
Basically what others answers say, it's correct, but the problem is if you want visibility GONE (because your layout requires it GONE!) you have to set visibility INVISIBLE in the xml with height 0dp (and/or width 0dp as well) and programmatically set the correct LayoutParams even inside the click event it will work. For example my code:
...
expandButton.setOnClickListener(new View.OnClickListener() {
#Override
public void onClick(View view) {
//To not have empty scroll, the container is INVISIBLE with 0dp height.
//Otherwise the Reveal effect will not work at the first click.
//Here I set the parameters programmatically.
viewContainer.setLayoutParams(new LinearLayout.LayoutParams(
ViewGroup.LayoutParams.MATCH_PARENT,
ViewGroup.LayoutParams.WRAP_CONTENT));
if (viewContainer.getVisibility() == View.VISIBLE) {
expandButton.animate().rotation(0f).setDuration(duration).start();
Utils.unReveal(viewContainer, 0, 0);
} else {
expandButton.animate().rotation(180f).setDuration(duration).start();
Utils.reveal(viewContainer, viewContainer.getWidth(), 0);
}
}
});
...
#TargetApi(VERSION_CODES.LOLLIPOP)
public static void reveal(final View view, int cx, int cy) {
if (!hasLollipop()) {
view.setVisibility(View.VISIBLE);
return;
}
//Get the final radius for the clipping circle
int finalRadius = Math.max(view.getWidth(), view.getHeight());
//Create the animator for this view (the start radius is zero)
Animator animator =
ViewAnimationUtils.createCircularReveal(view, cx, cy, 0, finalRadius);
//Make the view VISIBLE and start the animation
view.setVisibility(View.VISIBLE);
animator.start();
}
#TargetApi(VERSION_CODES.LOLLIPOP)
public static void unReveal(final View view, int cx, int cy) {
if (!hasLollipop()) {
view.setVisibility(View.GONE);
return;
}
//Get the initial radius for the clipping circle
int initialRadius = view.getWidth();
//Create the animation (the final radius is zero)
Animator animator =
ViewAnimationUtils.createCircularReveal(view, cx, cy, initialRadius, 0);
//Make the view GONE when the animation is done
animator.addListener(new AnimatorListenerAdapter() {
#Override
public void onAnimationEnd(Animator animation) {
super.onAnimationEnd(animation);
view.setVisibility(View.GONE);
}
});
//Start the animation
animator.start();
}
If you set only GONE in the xml, the first time will never work because height/width/x/y/etc.. are 0. Also, if you just set INVISIBLE before the call to the animation it will not work as well, but if you start with visibility INVISIBLE it will initialize the layout params.
what i did is, Like i have two view with same height,As we now visibility gone returns 0 {height and width} than i am giving visible view height every time and its work for me.
The solution is don't get values directly into code
Either put the animation code on click and the values outside onclick
or get the values from other activity
By values i mean cardType.getWidth() and cardType.getHeight()