I have run into a very strange problem. There is a layout I have with a RecyclerView and a button that switches on animation. The point is if I click the button right after the app executes - say 10 seconds, everything is fine. But if I leave the app running idle for some seconds, without touching anything, then when I click the button again, the animation simply doesn't start at all. And yet if after that I slide RecyclerView about the screen with my finger (in any place!) then the animation triggers all of a sudden. As if it was somehow frozen and "woke up" only after I interacted with the RecyclerView. As if RecyclerView after some seconds puts its animation-related objects to sleep somehow and they "wake-up" only after the RecyclerView is slided?.. Apparently the listener "goes to bed"... Is there a way to keep the animation-related objects "awake" at all times?
Here is the Animation function:
private void recyclerViewAnimate(final RecyclerView recyclerView, LayoutAnimationController controller) {
if(isAnimating){
return;
}
controller = AnimationUtils.loadLayoutAnimation(recyclerView.getContext(), R.anim.layout_recycleview_disappear);
recyclerView.setLayoutAnimation(controller);
recyclerView.setLayoutAnimationListener(new Animation.AnimationListener() {
public void onAnimationStart(Animation animation) {
isAnimating = true;
bt_add.animate().rotationXBy(180).setDuration(400).start();
addButtonLayout.animate().setDuration(400).alpha(0).withEndAction(new Runnable() {
#Override
public void run() {
addButtonLayout.setVisibility(View.INVISIBLE);
}
});
}
public void onAnimationRepeat(Animation animation) {}
public void onAnimationEnd(Animation animation) {
recyclerView.setVisibility(View.GONE);
layoutSettings.setVisibility(View.VISIBLE);
layoutSettings.animate().scaleX(0.95f).setDuration(0).withEndAction(new Runnable() {
#Override
public void run() {
layoutSettings.animate().alpha(1)
.scaleY(1.01f).scaleX(1f).setDuration(400).withEndAction(new Runnable() {
#Override
public void run() {
settingsText.animate().setDuration(300).alpha(1).start();
isAnimating = false;
recyclerView.setLayoutAnimationListener(null);
}
}).start();
}
}).start();
}
});
recyclerView.scheduleLayoutAnimation();
}
Instead of setting scheduleLayoutAnimation(); I needed to use startLayoutAnimation();
Related
I made an animation (ObjectAnimator)for a text view it work correctly but i have a question.
I wanna know is there any method that i can use immediately after animation duration finished ?
(I mean a method like onFinish when we use CountDownTimer)
I want the rest of methods and codes I have in app run when animation finished.Is there a solution for that?
ObjectAnimator deltaXAnimation = ObjectAnimator.ofFloat(winMassage,"scaleX",1f,1.5f);
deltaXAnimation.setDuration(300);
deltaXAnimation.start();
ObjectAnimator deltaYAnimation = ObjectAnimator.ofFloat(winMassage,"scaleY",1f,1.5f);
deltaYAnimation.setDuration(300);
deltaYAnimation.start();
HI there are proper callback methods in which you get Animation Start and end Listeners
ObjectAnimator deltaXAnimation =
ObjectAnimator.ofFloat(winMassage,"scaleX",1f,1.5f);
deltaXAnimation.setDuration(300);
deltaXAnimation.start();
deltaXAnimation.addListener(new Animator.AnimatorListener() {
#Override
public void onAnimationStart(Animator animator) {
}
#Override
public void onAnimationEnd(Animator animator) {
}
#Override
public void onAnimationCancel(Animator animator) {
}
#Override
public void onAnimationRepeat(Animator animator) {
}
});
Below code might be understand well, creating a listener for ObjectAnimator
ObjectAnimator deltaXAnimation =
ObjectAnimator.ofFloat(winMassage,"scaleX",1f,1.5f);
deltaXAnimation.setDuration(300);
deltaXAnimation.start();
anim.setAnimationListener(new Animation.AnimationListener() {
public void onAnimationStart(Animation a) {
//
}
public void onAnimationRepeat(Animation a) {
}
public void onAnimationEnd(Animation a) {
}
});
We can go also to your ObjectAnimator
Handler handler = new Handler();
handler.postDelayed(new Runnable() {
#Override
public void run() {
//stop animation after 5 seconds
deltaXAnimation.cancel();
}
}, 5000); //5000 equals to 5seconds
}
Hope this might help you
I found this Lottie Play/Pause button, but I don't know how to show Play state when my audio player paused, show Pause state and repeat with equalizer animation in it (see the lottie preview) when the player is playing. I've read the document but no example for this case. I don't have any knowledge about After Effect to control the animation too.
According Lottie animation it has frames, so by manupulating this frames you can achieve what you want, sample
AnimationView play_pause = findViewById(R.id.play_pause);
play_pause.cancelAnimation();
play_pause.setMinFrame(90);
play_pause.setMaxFrame(175);
This code will repeat your animation in rage of 90-175 I tested it on you Lottie Play/Pause button, so on clicking to stop you must change MaxFrame to 210 and set loop to 1 after animation finished it will stop in play picture.
And this is whole code to achieve something like that
Boolean isPlaying = false;
play_pause = findViewById(R.id.play_pause);
play_pause.pauseAnimation();
play_pause.setMinFrame(60);
play_pause.setOnClickListener(new View.OnClickListener() {
#Override
public void onClick(View view) {
if (isPlaying){
play_pause.removeAllAnimatorListeners();
play_pause.addAnimatorUpdateListener(new ValueAnimator.AnimatorUpdateListener() {
#Override
public void onAnimationUpdate(ValueAnimator valueAnimator) {
if (valueAnimator.getAnimatedFraction() == 1){
play_pause.setMinFrame(60);
play_pause.pauseAnimation();
}
}
});
play_pause.setMinFrame(175);
play_pause.setMaxFrame(210);
isPlaying = false;
} else {
play_pause.setMaxFrame(175);
play_pause.removeAllUpdateListeners();
play_pause.addAnimatorListener(new Animator.AnimatorListener() {
#Override
public void onAnimationStart(Animator animator) {
}
#Override
public void onAnimationEnd(Animator animator) {
}
#Override
public void onAnimationCancel(Animator animator) {
}
#Override
public void onAnimationRepeat(Animator animator) {
play_pause.setMinFrame(90);
}
});
play_pause.resumeAnimation();
isPlaying = true;
}
}
});
I have a TextView named tvCallToActionBanner that is shown depending on certain events. This method below controls whether said TextView gets shown. This method gets called in the Activity's onResume() and a couple of other methods call it as well.
public void showCallToActionBanner() {
runOnUiThread(new Runnable() {
#Override
public void run() {
if (!mPrefs.getCurrentLiveGameDateId().isEmpty()) {
mPrefs.setCallToActionType(GlobalVars.CTA_IN_GAME);
tvCallToActionBanner.setText(R.string.cta_game_in_progress);
if (!tvCallToActionBanner.isShown()) showCallToActionBanner(true);
}
else if (mPrefs.getLiveGameDateStatus().equals(GlobalVars.LIVE_GAME_DATE_SEARCHING)) {
mPrefs.setCallToActionType(GlobalVars.CTA_LIVE_GAME_DATE_SEARCHING);
tvCallToActionBanner.setText(R.string.cta_live_game_date_searching);
if (!tvCallToActionBanner.isShown()) showCallToActionBanner(true);
}
else if (!mPrefs.getUnratedGameDateIds().isEmpty()) {
mPrefs.setCallToActionType(GlobalVars.CTA_RATE_MATCH);
mPrefs.setCallToActionId(mPrefs.getUnratedGameDateIds().iterator().next());
tvCallToActionBanner.setText(R.string.cta_unrated_match);
if (!tvCallToActionBanner.isShown()) showCallToActionBanner(true);
}
else if (tvCallToActionBanner.isShown()) {
showCallToActionBanner(false);
}
}
});
}
public void showCallToActionBanner(final boolean shouldShow) {
runOnUiThread(new Runnable() {
#Override
public void run() {
if (shouldShow) {
Animation enterAnim = AnimationUtils.loadAnimation(MainActivity.this, R.anim
.banner_slide_down);
enterAnim.setAnimationListener(new Animation.AnimationListener() {
#Override
public void onAnimationStart(Animation animation) {
}
#Override
public void onAnimationEnd(Animation animation) {
int paddingTop = (int) getResources().getDimension(R.dimen
.main_container_top_spacing_for_banner);
mainContainer.setPadding(0, paddingTop, 0, 0);
}
#Override
public void onAnimationRepeat(Animation animation) {
}
});
tvCallToActionBanner.startAnimation(enterAnim);
tvCallToActionBanner.setVisibility(View.VISIBLE);
}
else {
Animation exitAnim = AnimationUtils.loadAnimation(MainActivity.this, R.anim
.banner_slide_up);
exitAnim.setAnimationListener(new Animation.AnimationListener() {
#Override
public void onAnimationStart(Animation animation) {
}
#Override
public void onAnimationEnd(Animation animation) {
mainContainer.setPadding(0, 0, 0, 0);
}
#Override
public void onAnimationRepeat(Animation animation) {
}
});
tvCallToActionBanner.startAnimation(exitAnim);
tvCallToActionBanner.setVisibility(View.GONE);
}
}
});
}
So when I trigger the tvCallToActionBanner to show in Activity A, it shows with no issues.
I create Activity B, and the onResume() gets called and it shows it with no problems.
And then I create Activity C, onResume() gets called and shows tvCallToActionBanner. I call a method which now hides tvCallToActionBanner and it hides with no issues.
I press the back button and it goes back to Activity B, which calls the onResume() and should be hiding the tvCallToActionBanner but it isn't.
I checked the tvCallToActionBanner.isShown() and it is returning false in Activity B after I press the back button from C. But the view is clearly showing and should be returning true.
Is it because the way the order of the Views are drawn? I have tried to move the method call to onPostResume() but that did nothing. How do I get the tvCallToActionBanner.isShown() to return true when it is showing?
Just use a View.getVisibility() method.
if(textView.getVisibility == View.VISIBLE) {
// do stuff
}
isShown() checks also the visibility of its ancestors - so the view itself could be visible but one of its parents isn't (#see here)
textview.viewTreeObserver.addOnGlobalLayoutListener {
Toast.makeText(this,"layout changed "
+textview.isShown
,Toast.LENGTH_LONG)
.show()
Toast.makeText(this,"visible "+
(textView.visibility==View.VISIBLE)
,Toast.LENGTH_LONG)
.show()
}
My question is very similar to this question, except that I need it to work with fragments instead of Views.
As explained in that thread, there seems to be a bug(?) in Android when an AnimationListener is attached to an Animation, which results in the onAnimationEnd() callback getting called before the animation has really completely ended.
I'm using fullscreen fragments which are animated in the FragmentTransaction (v4 support library) to have a horizontal "roll-in" effect. This works smoothly everywhere except in the fragment where I start a camera preview. Therefore I want to only start the camera preview once the animation is finished.
I tried using this method in my Fragment:
#Override
public Animation onCreateAnimation(final int transit,final boolean enter,final int nextAnim)
{
Animation anim=super.onCreateAnimation(transit, enter, nextAnim);
if (anim==null && nextAnim!=0)
anim=AnimationUtils.loadAnimation(getActivity(), nextAnim);
if(anim!=null)
{
anim.setAnimationListener(new AnimationListener() {
#Override
public void onAnimationStart(Animation animation)
{
}
#Override
public void onAnimationRepeat(Animation animation)
{
}
#Override
public void onAnimationEnd(Animation animation)
{
scannerView.startCameraInHandlerThread();
}
});
}
Unfortunately starting the camera is quite an expensive operation and so my animation lags every time right before the animation is over. It looks ugly and my client is complaining about it.
I also thought about a cheap solution like waiting/sleeping on the camera thread, but the main thread actually needs to wait for the camera starting thread for synchronization otherwise it can deadlock in some cases, so sleeping actually makes the issue worse (the lag becomes longer).
Does anyone know how to solve this?
edit: someone asked for more code...
public void startCameraInHandlerThread()
{
if (mThread == null)
mThread = new CameraHandlerThread();
synchronized (mThread) {
mThread.openCamera();
}
}
private class CameraHandlerThread extends HandlerThread
{
Handler mHandler = null;
CameraHandlerThread()
{
super("CameraHandlerThread");
start();
mHandler = new Handler(getLooper());
}
synchronized void notifyCameraActionCompleted() {
notify();
}
void openCamera()
{
mHandler.post(new Runnable() {
#Override
public void run() {
startCamera();
notifyCameraActionCompleted();
}
});
try
{
wait();
}
catch (InterruptedException e)
{
Thread.currentThread().interrupt();
LOG.warn("Waiting for camera opening was interrupted");
}
}
}
I was able to come up with a workaround: Just delay the start of my method for a very short time to give the animation time to run to completion. On the devices that my client is going to use this works fine but I don't feel that it's a general enough solution, therefore I'm not going to mark this as the accepted answer.
#Override
public void onAnimationEnd(Animation animation)
{
new Handler().postDelayed(new Runnable() {
#Override
public void run() {
scannerView.startCameraInHandlerThread();
}
}, 10); // will start after 10ms
}
I am trying to make a page where when the user leaves the page, there will be an animation (eg.: button will slide out) in the page and after that, the user will be sendt to a different activity.
No issue with the animation, but as the code for starting the new activity is written just after the animation code, the animation is not completing for 1 second (as I have set).
I want to execute the animation for 1 second first and then move to another activity.
Please help me.
Use AnimationListener.
private Animation.AnimationListener animListener = new Animation.AnimationListener() {
#Override
public void onAnimationEnd(Animation animation) {
// write code to start new activity.
}
#Override
public void onAnimationRepeat(Animation animation) {
}
#Override
public void onAnimationStart(Animation animation) {
}
};
Assign above listener to your animation
animation.setAnimationListener(animListener);
//Startanimation
new Handler().postDelayed(new Runnable() {
#Override
public void run() {
// TODO Auto-generated method stub
// call Activity
// End animation
}
}, 1000);