Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

Custom view animation isn't smooth during activity first launched

I have a custom view, which will perform animation during

  1. Activity first time launched.
  2. Selection changes on action bar drop down navigation.

The code looks like

DividendBarChartFragment .java

public class DividendBarChartFragment extends SherlockFragment {

    @Override
    public View onCreateView(LayoutInflater inflater, ViewGroup container,
            Bundle savedInstanceState) {
        View v = inflater.inflate(R.layout.dividend_bar_chart_fragment, container, false);

        // barChartCompositeViewByYear is custom view.
        this.barChartCompositeViewByYear = (BarChartCompositeView)v.findViewById(R.id.bar_chart_composite_view_by_year);

        final ViewTreeObserver viewTreeObserver0 = this.barChartCompositeViewByYear.getViewTreeObserver();

        // Only perform animation when view is ready?!
        viewTreeObserver0.addOnGlobalLayoutListener(new ViewTreeObserver.OnGlobalLayoutListener() {

            @SuppressLint("NewApi")
            @Override
            public void onGlobalLayout() {
                if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.JELLY_BEAN) {
                    DividendBarChartFragment.this.barChartCompositeViewByYear.getViewTreeObserver().removeOnGlobalLayoutListener(this);
                } else {
                    DividendBarChartFragment.this.barChartCompositeViewByYear.getViewTreeObserver().removeGlobalOnLayoutListener(this);
                }

                DividendBarChartFragment.this.barChartCompositeViewByYear.animateCurrentBarHeight();
            }

        });  

I wish to start animation (animateCurrentBarHeight), only when the Fragment is ready.

I use addOnGlobalLayoutListener. However, as you can see in my video, seems like animation has happened even before Fragment is visible to user.

https://www.youtube.com/watch?v=87_DOuZw88w&feature=youtu.be

If I only perform animation during onNavigationItemSelected of Activity (Using the same animation code, which is animateCurrentBarHeight), thing went much more smoother.

https://www.youtube.com/watch?v=yvJqtOSKKok&feature=youtu.be

May I know, what is the best time I can trigger my animation code, when activity first launched, so that the animation appears natural and smooth to users?

Code for animateCurrentBarHeight

public void animateCurrentBarHeight() {
    PropertyValuesHolder barHeightScalePropertyValuesHolder = PropertyValuesHolder.ofFloat("barHeightScale", barHeightScale, 1.0f);        
    ValueAnimator valueAnimator = ObjectAnimator.ofPropertyValuesHolder(this, barHeightScalePropertyValuesHolder);
    valueAnimator.setDuration(getResources().getInteger(android.R.integer.config_mediumAnimTime));
    valueAnimator.setRepeatCount(0);
    valueAnimator.setInterpolator(new DecelerateInterpolator());
    valueAnimator.start();        
}

Finalized answer after reading all suggested answers

@Override
public View onCreateView(LayoutInflater inflater, ViewGroup container,
        Bundle savedInstanceState) {
    View v = inflater.inflate(R.layout.dividend_bar_chart_fragment, container, false);

    // barChartCompositeViewByYear is custom view.
    this.barChartCompositeViewByYear = (BarChartCompositeView)v.findViewById(R.id.bar_chart_composite_view_by_year);

    final ViewTreeObserver viewTreeObserver0 = this.barChartCompositeViewByYear.getViewTreeObserver();

    viewTreeObserver0.addOnGlobalLayoutListener(new ViewTreeObserver.OnGlobalLayoutListener() {

        @SuppressLint("NewApi")
        @Override
        public void onGlobalLayout() {
            if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.JELLY_BEAN) {
                DividendBarChartFragment.this.barChartCompositeViewByYear.getViewTreeObserver().removeOnGlobalLayoutListener(this);
            } else {
                DividendBarChartFragment.this.barChartCompositeViewByYear.getViewTreeObserver().removeGlobalOnLayoutListener(this);
            }

            final int activityTransitionDuration = getResources().getInteger(android.R.integer.config_mediumAnimTime);
            final BarChartCompositeView barChartCompositeView = DividendBarChartFragment.this.barChartCompositeViewByYear;

            // Key to the solution!
            barChartCompositeView.postDelayed(new Runnable() {
                @Override
                public void run() {
                    barChartCompositeView.animateCurrentBarHeight();
                }
            }, activityTransitionDuration);
        }

    });        
like image 597
Cheok Yan Cheng Avatar asked Dec 04 '14 14:12

Cheok Yan Cheng


2 Answers

I don't believe there is a way to set an end listener on activity transitions like this, so one possible solution would be to simply set a start delay on the animation. This will ensure that the animation does not begin while the second activity is still animating/fading in to the screen.

The default activity transition duration can be obtained by calling:

getResources().getInteger(android.R.integer.config_mediumAnimTime);
like image 100
Alex Lockwood Avatar answered Oct 05 '22 06:10

Alex Lockwood


Generally animations can be controlled with messages on the UI thread. Without knowing the exact implementation of that view, I would give a try in posting a runnable to be ran when all current messagese are already delivered,

Instead of ...animateCurrentBarHeight();, Do:

    new Handler().post(new Runnable(){
        @Override
        public void run() {
            DividendBarChartFragment.this.barChartCompositeViewByYear.animateCurrentBarHeight();
        }
    });
like image 20
Sean Avatar answered Oct 05 '22 07:10

Sean