I want to make some views in my app visible and some other views invisible when some animated value of those views is more than a specific value (say, 0.5f).
Something like this:
#Override
public void onAnimationUpdate(ValueAnimator animation) {
if((float)animation.getAnimatedValue() >= 0.2){
(View)animation.setVisibility(View.GONE); //Something like this
}
}
As you know, setVisibility() function doesn't work!
How can I achieve this?
Here you are trying to set visibility of ValueAnimator. This wont work.
Try changing the visibility of actual views instead of ValueAnimator.
#Override
public void onAnimationUpdate(ValueAnimator animation) {
if((float)animation.getAnimatedValue() >= 0.2){
viewToBeMadeInvisible.setVisibility(View.GONE); //Like this
}
}
Update: You could add AnimatorListenerAdapter to listen for animation end.
animation.addListener(new AnimatorListenerAdapter()
{
#Override
public void onAnimationEnd(Animator animation)
{
//set your visibility code here.
}
});
Related
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 created two short methods to help me to show or hide a view when a certain checkbox is checked.
I have a Init method, in which I initialize a checkbox and a view, and a toggle method that is called from inside the checkbox status change listener and toggle the view status with an animation.
void toggleViewVisibility(final boolean b, final View v) {
v.setAlpha(b ? 0.0f : 1.0f);
v.setTranslationY(b ? v.getHeight() : 0);
if (b) {
v.setVisibility(View.VISIBLE);
v.animate().alpha(1.0f).translationY(0).setDuration(400);
} else {
v.animate().alpha(0.0f).translationY(v.getHeight()).setDuration(400).setListener(new Animator.AnimatorListener() {
#Override public void onAnimationStart(Animator animator) {}
#Override public void onAnimationEnd(Animator animator) { v.setVisibility(View.GONE); }
#Override public void onAnimationCancel(Animator animator) {}
#Override public void onAnimationRepeat(Animator animator) {}
});
}
}
void toggleViewVisibilityInit(final boolean b, final View v, final AnimateCheckBox c) {
v.setAlpha(b ? 1.0f : 0.0f);
v.setTranslationY(b ? 0 : v.getHeight());
v.setVisibility(b ? View.VISIBLE : View.GONE);
c.setChecked(b);
}
It works fine with the alpha animation, but has a small problem with the translation animation, although they are treated and initialized in the exact same way. Why?
In particular, the translation works fine whenever the checkbox status changes, but when the checkbox starts off, so the view is invisible, only at the VERY FIRST status change the view appears with alpha animation but does not perform the translation animation.
It looks like that when the view has been just created, it's translation status is not initialized, while alpha status is, although it is done in the toggleViewVisibilityInit() method.
Does anybody know why this should happen? It looks like as soon as the view is created the translation is not taken into consideration.
The view is not yet drawn so it's height is unknown (thus equals 0).
If you know this, it is easy to look for solutions, eg. getWidth() and getHeight() of View returns 0
Hope this helps!
probably another rhetorical question.
In iOS when we set a view's (any any UIView subclass such as UIButton) alpha to 0, iOS by default disables all user interaction on that view.
I got an Android app where I animate fade out the view by:
ObjectAnimator fadeOut = ObjectAnimator.ofFloat(buttonSelectionContainer, "alpha", 1, 0);
fadeOut.setDuration(500);
fadeOut.start();
However, I am noticing that when I tap the screen, the animation starts again, leading me to believe, in Android, even when a button alpha is set to 0, it is still tappable, is this true?
Is there a way to globally tell Android to disable user interaction for a view (and all its subviews) when its alpha is set to 0, either explicitly through using:
view.setAlpha(0.0f);
or through the ObjectAnimator like the above code block I used ?
A temporary work around for my problem would probably be to schedule this code to run after 500 ms:
// psuedocode: after 500ms
dispatch_doSomethingAfter(500)
{
myButton.setEnabled(false);
}
Not the ideal solution but might be my only solution, unless some bright Android developers out there has a better solution ?
Use addListener on your ObjectAnimator to control what happens after the animation has finished.
fadeOut.addListener(new Animator.AnimatorListener() {
#Override
public void onAnimationStart(Animator animation) {
}
#Override
public void onAnimationEnd(Animator animation) {
button.setEnabled(false);
}
#Override
public void onAnimationCancel(Animator animation) {
}
#Override
public void onAnimationRepeat(Animator animation) {
}
});
You can create an Animator.AnimatorListener that automatically disables the target View when the animation ends.
Declare your custom DisableViewOnEndAnimatorListener class:
public class DisableViewOnEndAnimatorListener extends AnimatorListenerAdapter {
#Override
public void onAnimationEnd(Animator animation) {
if (animation instanceof ObjectAnimator) {
final Object target = ((ObjectAnimator) animation).getTarget();
if (target instanceof View) {
((View) target).setEnabled(false);
}
}
}
}
Then, in your code:
DisableViewOnEndAnimatorListener endAnimatorListener = new DisableViewOnEndAnimatorListener();
ObjectAnimator button1FadeOut = ObjectAnimator.ofFloat(button1, "alpha", 1, 0);
button1FadeOut.setDuration(500);
button1FadeOut.addListener(endAnimatorListener);
button1FadeOut.start();
ObjectAnimator button2FadeOut = ObjectAnimator.ofFloat(button2, "alpha", 1, 0);
button2FadeOut.setDuration(500);
button2FadeOut.addListener(endAnimatorListener);
button2FadeOut.start();
I have a ViewPager which has 4 pages and I want it scroll automatically.
What I am doing is viewPager.setCurrentItem(index); bound with a TimerTask where index is a precomputed integer.
The logic works fine but when it scroll (triggered by setCurrentImte) the animation is too fast.
How can I control the scroll speed of it? Please note I am talking about the scrolling animation speed, instead of the interval of 2 successive scroll.
Why not use a ViewFlipper instead? A ViewFlipper has built in functionality to handle auto-scrolling between views, which means you can dump the timer. Also, it implements ViewAnimator which gives you full control over the animations. It is relatively simple to create custom animations, and you have control over the time it takes to animate. A simple tutorial for a slide animation can be found here. Take note of the duration attribute of the animation xml files.
Looks like ViewPager doesn't provide such an API. I would suggest to do any of the following:
Take VieWPager code (it's under Your android sdk extras folder) and twek it the way you need (e.g. add necessary API). Now it seems to use internal constant (MAX_SETTLE_DURATION);
Intercept touches by yourself and call fakeDragBy() (not sure if its what You're looking for);
Why not try something like this? Use a value animator to animate the scroll values, then update the positioning so the fragment loading is correctly handled. Works fine for me :).
if(pager != null){
ValueAnimator scrollAnimator = ValueAnimator.ofInt(pager.getScrollX(), pager.getScrollX()+2560);
final int virtualPage = pager.getCurrentItem();
scrollAnimator.setDuration(1000);
scrollAnimator.addUpdateListener(new ValueAnimator.AnimatorUpdateListener() {
#Override
public void onAnimationUpdate(ValueAnimator animation) {
pager.setScrollX((Integer)animation.getAnimatedValue());
}
});
scrollAnimator.addListener(new Animator.AnimatorListener() {
#Override
public void onAnimationStart(Animator animation) {
}
#Override
public void onAnimationEnd(Animator animation) {
pager.setCurrentVirtualItem(virtualPage, false);
}
#Override
public void onAnimationCancel(Animator animation) {
}
#Override
public void onAnimationRepeat(Animator animation) {
}
});
scrollAnimator.start();
}
I have the same requirement on an app i am developing and my solution was this.
Observable.range(1, vpAdapter.getCount() - 1)
.concatMap(i-> Observable.just(i).delay(5000, TimeUnit.MILLISECONDS))
.observeOn(AndroidSchedulers.mainThread())
.subscribe(integer -> {
currentAutoPage = integer;
binding.vpTour.beginFakeDrag();
lastFakeDrag = 0;
ValueAnimator va = ValueAnimator.ofInt(0, binding.vpTour.getWidth());
va.setDuration(1000);
va.addUpdateListener(animation -> {
if (binding.vpTour.isFakeDragging()) {
int animProgress = (Integer) animation.getAnimatedValue();
binding.vpTour.fakeDragBy(lastFakeDrag - animProgress);
lastFakeDrag = animProgress;
}
});
va.addListener(new AnimatorListenerAdapter() {
#Override
public void onAnimationEnd(Animator animation) {
super.onAnimationEnd(animation);
if (binding.vpTour.isFakeDragging()) {
binding.vpTour.endFakeDrag();
}
}
});
va.start();
}, Throwable::printStackTrace, () -> {
if (autoPageChangeDisposable != null && !autoPageChangeDisposable.isDisposed()) {
autoPageChangeDisposable.dispose();
}
});
In case you also want to stop the automatic swiping when user manually changes the page than just get the disposable from this code that i wrote, like this : "Disposable autoPageChangeDisposable = Observable.range(1, vpAdapter...." and than register and OnPageChangedListener and do this :
vpTour.addOnPageChangeListener(new ViewPager.SimpleOnPageChangeListener() {
#Override
public void onPageSelected(int position) {
if (position != currentAutoPage) {
if (autoPageChangeDisposable != null && !autoPageChangeDisposable.isDisposed()) {
autoPageChangeDisposable.dispose();
}
}
}
});
I have a simple LinearLayout with two Buttons side by side. They are supposed to slide into and out of view from the right side of the screen when needed. I have the animation working and the rest of the work is done, but I have one last problem to solve.
How can I set the LinearLayout's visibility to View.GONE after the slide out animation is complete? I need it to disappear once it's of screen.
Grab a reference of your Animation object doing the animation. Call Animation#setAnimationListener and in the listener's onAnimationEnd method set the visibility to View.GONE.
Duplicate : https://stackoverflow.com/a/7606533/3717188
anim.setAnimationListener(new Animation.AnimationListener(){
#Override
public void onAnimationStart(Animation arg0) {
}
#Override
public void onAnimationRepeat(Animation arg0) {
}
#Override
public void onAnimationEnd(Animation arg0) {
}
});
LinearLayout al = (LinearLayout) findViewById(R.id.layoutid);
al.setVisibility(view.INVISIBLE);
Add the above code in your
onAnimationEnd(){
}