首次启动活动时,自定义视图动画不流畅

时间:2014-12-04 14:52:32

标签: android animation

我有一个自定义视图,它将在

期间执行动画
  1. 活动首次推出。
  2. 操作栏上的选择更改下拉导航。
  3. 代码看起来像

    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();
                }
    
            });  
    

    我希望在animateCurrentBarHeight准备就绪时开始动画(Fragment)。

    我使用addOnGlobalLayoutListener。但是,正如您在我的视频中看到的那样,即使在Fragment对用户可见之前,动画也似乎已经发生。

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

    如果我只在onNavigationItemSelected的{​​{1}}期间执行动画(使用相同的动画代码,Activity),事情会变得更加顺畅。

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

    我可以知道,当活动首次启动时,我可以触发动画代码的最佳时间是什么,以便动画对用户显得自然流畅?

    animateCurrentBarHeight的代码

    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();        
    }
    

3 个答案:

答案 0 :(得分:4)

我不相信有一种方法可以像这样在活动转换上设置结束监听器,因此一种可能的解决方案是简单地设置动画的开始延迟。这将确保在第二个活动仍在动画/淡入屏幕时动画不会开始。

可以通过调用:

获取默认活动转换持续时间
getResources().getInteger(android.R.integer.config_mediumAnimTime);

答案 1 :(得分:2)

通常,可以使用UI线程上的消息来控制动画。在不知道该视图的确切实现的情况下,我会在posting a runnable中尝试在所有当前消息已经传递时运行,

而不是...animateCurrentBarHeight();,执行:

    new Handler().post(new Runnable(){
        @Override
        public void run() {
            DividendBarChartFragment.this.barChartCompositeViewByYear.animateCurrentBarHeight();
        }
    });

答案 2 :(得分:0)

很难确切地说出导致口吃的原因(在我的肉眼看来,第二个视频中的1个动画似乎几乎有口吃),所以这是一个理论上的答案,在最坏的情况下应该事情变得更好。

首先,我个人看不到在简单地启动活动时使用ViewTreeObserver方法的价值。如果您通过启动Activity 执行生命周期,那么在适当的生命周期事件中会更有意义。要准确了解当前配置中发生的情况,我建议您查看ActivityFragment生命周期(特别是生命周期流程图)。

根据您要执行的操作,您希望动画在显示活动的生命周期中尽可能延迟。通过尝试在onGlobalLayout()事件中执行动画,您正在尝试在完成布局操作时执行动画。在Android中,布局操作和绘图(更不用说在屏幕上显示)是非常不同的动作。例如,基本View lifecycle(您基本上使用onGlobalLayout()听众观察)会转到onMeasure()onLayout()onDraw()。基于此,你试图在View甚至被绘制到屏幕之前执行你的动画(这个结论是基于一些简化的假设,但一般的要点仍然存在)。

使用onResume()Activity的{​​{1}}方法为活动创建活动执行此动画会更有意义(取决于您的应用设置 - 但看起来比如Fragment方法是合适的)。这样做的副作用是每当用户重新打开您的应用程序时都会发生动画。如果不希望这样,您可以始终在Fragment.onResume()方法中设置一个标志,以确保动画仅运行一次。或者您也可以查看onCreate(),因为这可能是一个更好的地方,具体取决于您的应用程序结构。最基本解决方案的示例代码:

onStart()

这是您在public class DividendBarChartFragment extends SherlockFragment { // ... existing code ... @Override public void onResume() { super.onResume(); DividendBarChartFragment.this.barChartCompositeViewByYear.animateCurrentBarHeight(); } } / Activity生命周期方面有权访问的最晚版本(您可以转到Fragment但这不是必需的,不建议在method documentation)。如果这不能解决问题,那么您的下一个选择是仍然在这里开始动画,但包括延迟启动它。这不太稳健,但应该保证做到这一点。鉴于您尚未提供Activity.onPostResume()函数的实现,我只能建议您对其进行扩展以采用延迟animateCurrentBarHeight()参数并进行相应调整(int是其中之一{ {3}}你可以根据你动画的表现来实现这一点。延迟Animation.startOffset()的代码仍然几乎相同:

onResume()

如果这不能解决口吃问题,那么如果你能提供完全如何动画的代码,将会非常有帮助。