incallui android,Android M InCallUI动画简析

本篇回答下面几个问题:

1. 显示动画的流程是怎样的?

2. 为什么有些手机的动画不一样甚至没有动画?

写这一篇主要用两个原因:

1. 发现Android M上新增了一个类CircularRevealFragment.java,那么新的东西就想看看它是干什么的;

2. 我手机上没有打电话的动画!!

代码中两处动画,一处是InCallActivity显示动画,就是那个由一个点展开的动画,另一个是CallCard的动画,就是由下方升到上方的动画。

InCallActivity启动动画

在InCallActivity.java的internalResolveIntent()方法内(这个方法接收处理intent,必走),跳至 CircularRevealFragment.java

touchPoint即动画展开的那个点。可以看到这个touchPoint有两个取值的地方,这个有点类似于双保险,TouchPointManager中getPoint()取出来的值是点击的时候就保存到TouchPointManager中的,而(Point) extras.getParcelable(TouchPointManager.TOUCH_POINT);是在构造拨号的intent的时候存进去的

Point touchPoint = null;

if (TouchPointManager.getInstance().hasValidPoint()) {

// Use the most immediate touch point in the InCallUi if available

touchPoint = TouchPointManager.getInstance().getPoint();

} else {

// Otherwise retrieve the touch point from the call intent

if (call != null) {

touchPoint = (Point) extras.getParcelable(TouchPointManager.TOUCH_POINT);

}

}

// Start animation for new outgoing call

CircularRevealFragment.startCircularReveal(getFragmentManager(), touchPoint,

InCallPresenter.getInstance());

touchPoint每次点击的时候都应当set一次,举个DialtacsActivity.java里的例子,当然还有其他地方设置(能点的地方就应该设置一次):

@Override

public boolean dispatchTouchEvent(MotionEvent ev) {

if (ev.getAction() == MotionEvent.ACTION_DOWN) {

TouchPointManager.getInstance().setPoint((int) ev.getRawX(), (int) ev.getRawY());

}

return super.dispatchTouchEvent(ev);

}

CircularRevealFragment.java新增类

public static void startCircularReveal(FragmentManager fm, Point touchPoint,

OnCircularRevealCompleteListener listener) {

if (fm.findFragmentByTag(TAG) == null) {

fm.beginTransaction().add(R.id.main,

new CircularRevealFragment(touchPoint, listener), TAG)

.commitAllowingStateLoss();

} else {

Log.w(TAG, "An instance of CircularRevealFragment already exists");

}

}

然后在 CircularRevealFragment.java的onResume()方法内

@Override

public void onResume() {

super.onResume();

if (!mAnimationStarted) {

// Only run the animation once for each instance of the fragment

startOutgoingAnimation(InCallPresenter.getInstance().getThemeColors());//带了一个 ThemeColors展开动画

}

mAnimationStarted = true;

}

这里观察到一个现象,插卡和不插卡通话背景是不同的,双卡手机上两张卡拨打出去的动画背景可能也是不同的,就是因为上面的getThemeColors()返回的值也就是颜色不同。返回值的来源不具体跟了,设置这个颜色的地方在Settings>Sim Card 设置页点开sim卡有个颜色选择,背景色就是这里的颜色。

下面的方法新建动画并启动动画

public void startOutgoingAnimation(MaterialPalette palette) {

//略过本次不关心的

view.getViewTreeObserver().addOnPreDrawListener(new OnPreDrawListener() {

@Override

public boolean onPreDraw() {

final ViewTreeObserver vto = view.getViewTreeObserver();

if (vto.isAlive()) {

vto.removeOnPreDrawListener(this);

}

final Animator animator = getRevealAnimator(mTouchPoint);//获得动画

animator.addListener(new AnimatorListenerAdapter() {

@Override

public void onAnimationEnd(Animator animation) {

view.setClipToOutline(false);

if (mListener != null) {

android.util.Log.i(TAG, "onAnimationEnd: animation a");

mListener.onCircularRevealComplete(getFragmentManager());//动画结束后调

}

}

});

android.util.Log.i(TAG, "onPreDraw: animation 3");

animator.start();//动画开始了

return false;

}

});

}

好的诸位下面就是动画生成的地方,注意动画类型,这里携带了touchPoint

private Animator getRevealAnimator(Point touchPoint) {

final Activity activity = getActivity();

final View view = activity.getWindow().getDecorView();

final Display display = activity.getWindowManager().getDefaultDisplay();

final Point size = new Point();

display.getSize(size);

int startX = size.x / 2;

int startY = size.y / 2;

if (touchPoint != null) {

startX = touchPoint.x;

startY = touchPoint.y;

}

final Animator valueAnimator = ViewAnimationUtils.createCircularReveal(view,

startX, startY, 0, Math.max(size.x, size.y));

valueAnimator.setDuration(getResources().getInteger(R.integer.reveal_animation_duration));//设置动画时长

return valueAnimator;

}

好的InCallActivity的动画显示完以后,下面接着CallCardFragment的动画。

CallCard动画

在动画执行完InCallActivity的启动动画以后,通过mListener.onCircularRevealComplete(getFragmentManager());调用CallCardFragement.java中的 animateForNewOutgoingCall()

InCallPresenter.java

public void onCircularRevealComplete(FragmentManager fm) {

if (mInCallActivity != null) {

mInCallActivity.showCallCardFragment(true);//显示CallCard

mInCallActivity.getCallCardFragment().animateForNewOutgoingCall();//CallCardFragment中显示动画

CircularRevealFragment.endCircularReveal(mInCallActivity.getFragmentManager());

}

}

CallCardFragment.java

关注一下动画类型

@Override

public void animateForNewOutgoingCall() {

//略过本次不关心的

observer.addOnGlobalLayoutListener(new OnGlobalLayoutListener() {

@Override

public void onGlobalLayout() {

//略过本次不关心的

final Animator animator = getShrinkAnimator(parent.getHeight(), originalHeight);//注意动画类型

animator.addListener(new AnimatorListenerAdapter() {

@Override

public void onAnimationEnd(Animator animation) {

mPrimaryCallCardContainer.setTag(R.id.view_tag_callcard_actual_height,

null);

setViewStatePostAnimation(listener);

mIsAnimating = false;

InCallPresenter.getInstance().onShrinkAnimationComplete();//动画结束后

}

});

animator.start();//开始动画

}

});

}

getShrinkAnimator()动画生成

/** * Animator that performs the upwards shrinking animation of the blue call card scrim. * At the start of the animation, each child view is moved downwards by a pre-specified amount * and then translated upwards together with the scrim. */

private Animator getShrinkAnimator(int startHeight, int endHeight) {

final ObjectAnimator shrinkAnimator =

ObjectAnimator.ofInt(mPrimaryCallCardContainer, "bottom", startHeight, endHeight);

shrinkAnimator.setDuration(mShrinkAnimationDuration);//设置动画时长

shrinkAnimator.addListener(new AnimatorListenerAdapter() {

@Override

public void onAnimationStart(Animator animation) {

mFloatingActionButton.setEnabled(true);

}

});

shrinkAnimator.setInterpolator(AnimUtils.EASE_IN);

return shrinkAnimator;

}

动画时长来源:

mShrinkAnimationDuration = getResources().getInteger(R.integer.shrink_animation_duration);

好了现在我们回头看看文章开头的两个问题是否得到了解答。

前面的流程基本上就是动画生成,设置属性,显示动画的流程,

非要话个图的话大概就是下面这样

0818b9ca8b590ca3270a3433284dd417.png

如果我们把Android M上的动画代码跟Android L上的代码做对比的话会发现,Android L也有这两个类型的动画,都在CallCardFragment.java里,通过mAnimatorSet.playSequentially(revealAnimator, shrinkAnimator);顺序播放两个动画。

第二个问题的答案貌似还不明显,为什么有些手机的动画不一样?

我们观察到的不同有两点:1.背景颜色不同,2.有些似乎没有动画。

第1点不重点解答,上文也提到过颜色取值自SIM卡设置里面选择的颜色,而且颜色不同起码有动画嘛;

第2点有又两种情况:1)没用动画;2)动画时间极短,以至于看起来像没有动画。

注意到两次设置动画时间的代码分别是:

//InCallActivity或者说叫CircularRevealFragment

valueAnimator.setDuration(getResources().getInteger(R.integer.reveal_animation_duration));

//CallCardFragment

mShrinkAnimationDuration = getResources().getInteger(R.integer.shrink_animation_duration);

那么这两个值的来源呢?



0818b9ca8b590ca3270a3433284dd417.png

从上图中可以看到,这个动画时长默认是333ms的,但是在有些配置文件里面是1,而且都改成了1!!从他们所在的文件夹可以看到,这个配置是针对中国移动sim卡的修改(mcc mnc 匹配到中国移动),难道是针对中国移动定制机的修改?苦了我刷CM系统的人们(AOSP没这个配置)。

是哪个家伙做了这样的修改(黑线脸)?!



0818b9ca8b590ca3270a3433284dd417.png

提交者就不贴出来了,他针对中国移动新增了这4个文件配置动画时长。。

题外: 从这里又可以看出一点,嫌通话界面启动慢的可以改动画时长,这也是有时候所谓的“性能要求”/“响应时间”。 完。

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值