我有一个自定义视图,它将在
期间执行动画代码看起来像
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
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();
}
答案 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
执行生命周期,那么在适当的生命周期事件中会更有意义。要准确了解当前配置中发生的情况,我建议您查看Activity和Fragment生命周期(特别是生命周期流程图)。
根据您要执行的操作,您希望动画在显示活动的生命周期中尽可能延迟。通过尝试在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()
如果这不能解决口吃问题,那么如果你能提供完全如何动画的代码,将会非常有帮助。