监控帧数代码
java代码
import android.os.Bundle;
import android.view.Choreographer;
import android.view.View;
import android.view.animation.ScaleAnimation;
import android.widget.FrameLayout;
import android.widget.RelativeLayout;
import androidx.appcompat.app.AppCompatActivity;
import com.example.myandroid.R;
public class FrameAnimateTest extends AppCompatActivity {
private FrameLayout parentLayout;
private RelativeLayout blueLayout;
private RelativeLayout redLayout;
private int currentFrameCount = 0;
private static final int TARGET_FRAME_RED = 30;
private static final int TARGET_FRAME_BLUE = 200;
@Override
protected void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
setContentView(R.layout.fram_antmate_layout);
parentLayout = findViewById(R.id.parentLayout);
blueLayout = findViewById(R.id.blueLayout);
redLayout = findViewById(R.id.redLayout);
startFrameMonitor();
startScalingAnimation();
}
private void startFrameMonitor() {
Choreographer.getInstance().postFrameCallback(new Choreographer.FrameCallback() {
@Override
public void doFrame(long frameTimeNanos) {
currentFrameCount++;
if (currentFrameCount == TARGET_FRAME_RED) {
switchToRedLayout();
} else if (currentFrameCount == TARGET_FRAME_BLUE) {
switchToBlueLayout();
}
// Continue monitoring the frames
Choreographer.getInstance().postFrameCallback(this);
}
});
}
private void switchToRedLayout() {
blueLayout.setVisibility(View.GONE);
redLayout.setVisibility(View.VISIBLE);
}
private void switchToBlueLayout() {
redLayout.setVisibility(View.GONE);
blueLayout.setVisibility(View.VISIBLE);
}
private void startScalingAnimation() {
ScaleAnimation scaleAnimation = new ScaleAnimation(
1.0f, 6.0f, 1.0f, 6.0f, // Scale from 50dp to 300dp
ScaleAnimation.RELATIVE_TO_SELF, 0.5f,
ScaleAnimation.RELATIVE_TO_SELF, 0.5f);
scaleAnimation.setDuration(10000); // Animate over 10 seconds
scaleAnimation.setFillAfter(true);
parentLayout.startAnimation(scaleAnimation);
}
}
xml代码
<?xml version="1.0" encoding="utf-8"?>
<FrameLayout xmlns:android="http://schemas.android.com/apk/res/android"
android:layout_width="match_parent"
android:layout_height="match_parent">
<FrameLayout
android:id="@+id/parentLayout"
android:layout_width="50dp"
android:layout_height="50dp"
android:layout_gravity="center"
android:background="#CCCCCC">
<RelativeLayout
android:id="@+id/blueLayout"
android:layout_width="match_parent"
android:layout_height="match_parent"
android:background="#0000FF" />
<RelativeLayout
android:id="@+id/redLayout"
android:layout_width="match_parent"
android:layout_height="match_parent"
android:background="#FF0000"
android:visibility="gone" />
</FrameLayout>
</FrameLayout>
讲解
在一个 Android Activity 中实现了一个动画效果,即一个父布局逐渐从 50dp 放大到 300dp,同时在特定帧数时切换子布局的可见性。从蓝色到红色再回到蓝色。
重要部分讲解
1. 布局文件 activity_main.xml
这个布局文件定义了一个 FrameLayout,作为我们的父布局,用于进行缩放动画。父布局中有两个子布局,一个蓝色 (blueLayout),一个红色 (redLayout):
<FrameLayout
android:id="@+id/parentLayout"
android:layout_width="50dp"
android:layout_height="50dp"
android:layout_gravity="center"
android:background="#CCCCCC">
<RelativeLayout
android:id="@+id/blueLayout"
android:layout_width="match_parent"
android:layout_height="match_parent"
android:background="#0000FF" />
<RelativeLayout
android:id="@+id/redLayout"
android:layout_width="match_parent"
android:layout_height="match_parent"
android:background="#FF0000"
android:visibility="gone" />
</FrameLayout>
**
FrameLayout充当父布局,设置初始宽度和高度为 50dp。- 子布局
blueLayout默认为可见 (visibility="visible"),redLayout初始为隐藏 (visibility="gone"),此时只显示蓝色布局。
2. MainActivity.java
onCreate 方法
当 Activity 被创建时,初始化布局并启动动画和帧监控器。
@Override
protected void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
setContentView(R.layout.activity_main);
parentLayout = findViewById(R.id.parentLayout);
blueLayout = findViewById(R.id.blueLayout);
redLayout = findViewById(R.id.redLayout);
startFrameMonitor();
startScalingAnimation();
}
**
setContentView(R.layout.activity_main):加载布局文件。findViewById(...):获取布局组件实例。startFrameMonitor():启动帧监控。startScalingAnimation():启动放大动画。
startScalingAnimation 方法
private void startScalingAnimation() {
ScaleAnimation scaleAnimation = new ScaleAnimation(
1.0f, 6.0f, 1.0f, 6.0f, // Scale from 50dp to 300dp
ScaleAnimation.RELATIVE_TO_SELF, 0.5f,
ScaleAnimation.RELATIVE_TO_SELF, 0.5f);
scaleAnimation.setDuration(10000); // Animate over 10 seconds
scaleAnimation.setFillAfter(true);
parentLayout.startAnimation(scaleAnimation);
}
**
- 缩放动画:创建
ScaleAnimation,定义从缩放倍数1.0f到6.0f,表示从初始尺寸放大到 6 倍(50dp 到 300dp)。 - 动画中心点:动画的中心点是布局自身的中心 (
RELATIVE_TO_SELF, 0.5f)。 - 动画时长:持续时间为10秒 (
10,000毫秒)。 - 动画结束时保持最终状态:设置
scaleAnimation.setFillAfter(true),以确保动画结束后保持最后的状态(即,放大后的尺寸)。
startFrameMonitor 方法
private void startFrameMonitor() {
Choreographer.getInstance().postFrameCallback(new Choreographer.FrameCallback() {
@Override
public void doFrame(long frameTimeNanos) {
currentFrameCount++;
if (currentFrameCount == TARGET_FRAME_RED) {
switchToRedLayout();
} else if (currentFrameCount == TARGET_FRAME_BLUE) {
switchToBlueLayout();
}
// Continue monitoring the frames
Choreographer.getInstance().postFrameCallback(this);
}
});
}
**
-
帧监控:使用
Choreographer进行帧回调,每次回调自增currentFrameCount。 -
布局切换:
- 在第 30 帧时,调用
switchToRedLayout()切换到红色布局。 - 在第 200 帧时,调用
switchToBlueLayout()切换回蓝色布局。
- 在第 30 帧时,调用
-
继续监测: 每一帧监测后再次设置回调,以便继续监测下一帧。
switchToRedLayout 和 switchToBlueLayout 方法
这些方法负责在特定帧数时切换布局的可见性:
private void switchToRedLayout() {
blueLayout.setVisibility(View.GONE);
redLayout.setVisibility(View.VISIBLE);
}
private void switchToBlueLayout() {
redLayout.setVisibility(View.GONE);
blueLayout.setVisibility(View.VISIBLE);
}
**
- switchToRedLayout:隐藏蓝色布局,显示红色布局。
- switchToBlueLayout:隐藏红色布局,显示蓝色布局。
总结
整个程序通过一种简单而有效的方式,在Java中使用 ScaleAnimation 结合 Choreographer 进行帧监控,以便在动画执行到指定帧时切换子布局的可见性。这种方法确保了在复杂动画中能够精确掌控视觉元素的切换时间点。