如何循环显示整个activity
How to circular reveal the entire activity
我尝试使用 android:windowEnterTransition
和 android:windowExitTransition
,但这似乎使 activity 中的每个视图都具有动画效果,即分别显示每个视图。我怎样才能用上面的内容为整个 activity 制作动画?两个活动之间没有共享元素。
有几种方法可以为整个 Activity 设置动画。最有效的机制是使用 Window 转换。这些针对 Window 进行操作,因此不需要在每一帧上重新绘制内容。缺点是操作仅限于较旧的动画框架。
通常,您会使用样式指定 window 动画。你可以在这里看到它是如何完成的:Start Activity with an animation
您还可以使用 overridePendingTransition 或 ActivityOptions.makeCustomAnimation
如果您想使用棒棒糖Activity Transitions 框架,您可以使用windowEnterTransition。如果您只想对您的内容进行操作,请将最外层的 ViewGroup 设置为:
<WhateverViewGroup ... android:transitionGroup="true"/>
您可能希望为您的视图组命名或 ID,并在进入转换中使用它,以便它仅针对该组。否则它也会针对状态栏背景之类的东西。
如果你想让它对整个Window内容进行操作:
getWindow().getDecorView().setTransitionGroup(true)
这将强制 window 内容作为一个单元。
经过大量研究和 android 阅读源代码,我想出了如何做到这一点。它在 Scala 中,但您应该轻松地将其转换为 Java。
以下是最重要的部分。
override protected def onCreate(savedInstanceState: Bundle) {
super.onCreate(savedInstanceState)
val window = getWindow
val decor = window.getDecorView.asInstanceOf[ViewGroup]
// prevent fading of background
decor.setBackgroundColor(android.R.color.transparent)
if (Build.version >= 21) {
window.setEnterTransition(circularRevealTransition)
window.setReturnTransition(circularRevealTransition)
// decor.setTransitionGroup(true) won't work
for (i <- 0 until decor.getChildCount) {
val child = decor.getChildAt(i).asInstanceOf[ViewGroup]
if (child != null) child.setTransitionGroup(true)
}
if (savedInstanceState == null) {
val intent = getIntent
val x = intent.getFloatExtra(EXTRA_SPAWN_LOCATION_X, Float.NaN)
if (!x.isNaN) {
val y = intent.getFloatExtra(EXTRA_SPAWN_LOCATION_Y, Float.NaN)
if (!y.isNaN) circularRevealTransition.spawnLocation = (x, y)
}
}
}
}
@TargetApi(21)
class CircularReveal(context: Context, attrs: AttributeSet = null)
extends Visibility(context, attrs) {
var spawnLocation: (Float, Float) = _
var stopper: View = _
private val metrics = new DisplayMetrics
private lazy val wm = context.getSystemService(Context.WINDOW_SERVICE)
.asInstanceOf[WindowManager]
private def getEnclosingCircleRadius(x: Float, y: Float) =
math.hypot(math.max(x, metrics.widthPixels - x),
math.max(y, metrics.widthPixels - y)).toFloat
override def onAppear(sceneRoot: ViewGroup, view: View,
startValues: TransitionValues, endValues: TransitionValues) = {
wm.getDefaultDisplay.getMetrics(metrics)
val (x, y) = LocationObserver.getRelatedTo(spawnLocation, view)
new NoPauseAnimator(ViewAnimationUtils
.createCircularReveal(view, x.toInt, y.toInt, 0,
getEnclosingCircleRadius(x, y)))
}
override def onDisappear(sceneRoot: ViewGroup, view: View,
startValues: TransitionValues, endValues: TransitionValues) = {
wm.getDefaultDisplay.getMetrics(metrics)
val (x, y) = if (stopper == null)
LocationObserver.getRelatedTo((metrics.widthPixels * .5F,
metrics.heightPixels.toFloat), view)
else LocationObserver.getRelatedTo(stopper, view)
new NoPauseAnimator(ViewAnimationUtils
.createCircularReveal(view, x.toInt, y.toInt,
getEnclosingCircleRadius(x, y), 0))
}
}
我尝试使用 android:windowEnterTransition
和 android:windowExitTransition
,但这似乎使 activity 中的每个视图都具有动画效果,即分别显示每个视图。我怎样才能用上面的内容为整个 activity 制作动画?两个活动之间没有共享元素。
有几种方法可以为整个 Activity 设置动画。最有效的机制是使用 Window 转换。这些针对 Window 进行操作,因此不需要在每一帧上重新绘制内容。缺点是操作仅限于较旧的动画框架。
通常,您会使用样式指定 window 动画。你可以在这里看到它是如何完成的:Start Activity with an animation
您还可以使用 overridePendingTransition 或 ActivityOptions.makeCustomAnimation
如果您想使用棒棒糖Activity Transitions 框架,您可以使用windowEnterTransition。如果您只想对您的内容进行操作,请将最外层的 ViewGroup 设置为:
<WhateverViewGroup ... android:transitionGroup="true"/>
您可能希望为您的视图组命名或 ID,并在进入转换中使用它,以便它仅针对该组。否则它也会针对状态栏背景之类的东西。
如果你想让它对整个Window内容进行操作:
getWindow().getDecorView().setTransitionGroup(true)
这将强制 window 内容作为一个单元。
经过大量研究和 android 阅读源代码,我想出了如何做到这一点。它在 Scala 中,但您应该轻松地将其转换为 Java。
以下是最重要的部分。
override protected def onCreate(savedInstanceState: Bundle) {
super.onCreate(savedInstanceState)
val window = getWindow
val decor = window.getDecorView.asInstanceOf[ViewGroup]
// prevent fading of background
decor.setBackgroundColor(android.R.color.transparent)
if (Build.version >= 21) {
window.setEnterTransition(circularRevealTransition)
window.setReturnTransition(circularRevealTransition)
// decor.setTransitionGroup(true) won't work
for (i <- 0 until decor.getChildCount) {
val child = decor.getChildAt(i).asInstanceOf[ViewGroup]
if (child != null) child.setTransitionGroup(true)
}
if (savedInstanceState == null) {
val intent = getIntent
val x = intent.getFloatExtra(EXTRA_SPAWN_LOCATION_X, Float.NaN)
if (!x.isNaN) {
val y = intent.getFloatExtra(EXTRA_SPAWN_LOCATION_Y, Float.NaN)
if (!y.isNaN) circularRevealTransition.spawnLocation = (x, y)
}
}
}
}
@TargetApi(21)
class CircularReveal(context: Context, attrs: AttributeSet = null)
extends Visibility(context, attrs) {
var spawnLocation: (Float, Float) = _
var stopper: View = _
private val metrics = new DisplayMetrics
private lazy val wm = context.getSystemService(Context.WINDOW_SERVICE)
.asInstanceOf[WindowManager]
private def getEnclosingCircleRadius(x: Float, y: Float) =
math.hypot(math.max(x, metrics.widthPixels - x),
math.max(y, metrics.widthPixels - y)).toFloat
override def onAppear(sceneRoot: ViewGroup, view: View,
startValues: TransitionValues, endValues: TransitionValues) = {
wm.getDefaultDisplay.getMetrics(metrics)
val (x, y) = LocationObserver.getRelatedTo(spawnLocation, view)
new NoPauseAnimator(ViewAnimationUtils
.createCircularReveal(view, x.toInt, y.toInt, 0,
getEnclosingCircleRadius(x, y)))
}
override def onDisappear(sceneRoot: ViewGroup, view: View,
startValues: TransitionValues, endValues: TransitionValues) = {
wm.getDefaultDisplay.getMetrics(metrics)
val (x, y) = if (stopper == null)
LocationObserver.getRelatedTo((metrics.widthPixels * .5F,
metrics.heightPixels.toFloat), view)
else LocationObserver.getRelatedTo(stopper, view)
new NoPauseAnimator(ViewAnimationUtils
.createCircularReveal(view, x.toInt, y.toInt,
getEnclosingCircleRadius(x, y), 0))
}
}