Android KitKat下Activity间视频纹理淡入淡出过渡异常解决方案咨询
解决KitKat系统中TextureView视频淡入淡出过渡出现白色空白的问题
你遇到的这个问题确实是Android 4.4(KitKat)系统的一个已知bug:当使用overridePendingTransition进行Activity跳转时,旧Activity退出后会短暂显示窗口背景(默认白色),而新Activity的TextureView需要等待MediaPlayer加载并准备好视频才能显示内容,这就导致了过渡期间的白色空白。
下面是针对KitKat系统的几种可行解决方案,按推荐程度排序:
方案一:在同一个Activity中管理多个TextureView(最推荐)
放弃Activity跳转,将两个视频的TextureView放在同一个布局中叠层显示,通过直接控制它们的Alpha动画实现淡入淡出,完全避免窗口切换的间隙。
步骤1:编写布局文件(activity_main.xml)
<FrameLayout xmlns:android="http://schemas.android.com/apk/res/android" android:id="@+id/root_layout" android:layout_width="match_parent" android:layout_height="match_parent"> <!-- 第一个视频的TextureView,初始显示 --> <TextureView android:id="@+id/texture_video1" android:layout_width="match_parent" android:layout_height="match_parent" android:alpha="1.0"/> <!-- 第二个视频的TextureView,初始隐藏 --> <TextureView android:id="@+id/texture_video2" android:layout_width="match_parent" android:layout_height="match_parent" android:alpha="0.0"/> </FrameLayout>
步骤2:Activity中的实现代码
public class VideoSwitchActivity extends AppCompatActivity implements SurfaceTextureListener { private TextureView textureVideo1, textureVideo2; private MediaPlayer player1, player2; private boolean isShowingVideo1 = true; @Override protected void onCreate(Bundle savedInstanceState) { super.onCreate(savedInstanceState); setContentView(R.layout.activity_main); textureVideo1 = findViewById(R.id.texture_video1); textureVideo2 = findViewById(R.id.texture_video2); // 设置SurfaceTexture监听器,准备视频播放 textureVideo1.setSurfaceTextureListener(this); textureVideo2.setSurfaceTextureListener(this); // 点击布局任意位置切换视频 findViewById(R.id.root_layout).setOnClickListener(v -> switchVideo()); } @Override public void onSurfaceTextureAvailable(SurfaceTexture surface, int width, int height) { // 根据SurfaceTexture对应的TextureView初始化对应的MediaPlayer if (surface == textureVideo1.getSurfaceTexture()) { initPlayer(player1, R.raw.test1, surface); } else if (surface == textureVideo2.getSurfaceTexture()) { initPlayer(player2, R.raw.test2, surface); } } // 初始化MediaPlayer的工具方法 private void initPlayer(MediaPlayer player, int videoResId, SurfaceTexture surface) { player = MediaPlayer.create(this, videoResId); player.setLooping(true); player.setSurface(new Surface(surface)); player.start(); } // 切换视频的核心方法,执行淡入淡出动画 private void switchVideo() { Animation fadeOutAnim = AnimationUtils.loadAnimation(this, R.anim.fade_out); Animation fadeInAnim = AnimationUtils.loadAnimation(this, R.anim.fade_in); if (isShowingVideo1) { // 当前显示视频1,切换到视频2 textureVideo1.startAnimation(fadeOutAnim); textureVideo2.startAnimation(fadeInAnim); textureVideo1.setAlpha(0.0f); textureVideo2.setAlpha(1.0f); } else { // 当前显示视频2,切换到视频1 textureVideo2.startAnimation(fadeOutAnim); textureVideo1.startAnimation(fadeInAnim); textureVideo2.setAlpha(0.0f); textureVideo1.setAlpha(1.0f); } isShowingVideo1 = !isShowingVideo1; } // SurfaceTextureListener的其他空实现 @Override public void onSurfaceTextureSizeChanged(SurfaceTexture surface, int width, int height) {} @Override public boolean onSurfaceTextureDestroyed(SurfaceTexture surface) { return false; } @Override public void onSurfaceTextureUpdated(SurfaceTexture surface) {} @Override protected void onDestroy() { super.onDestroy(); // 释放MediaPlayer资源 if (player1 != null) player1.release(); if (player2 != null) player2.release(); } }
这个方案的优势是完全在同一个窗口内操作,没有Activity切换的空白,过渡效果流畅,完美适配KitKat系统。
方案二:使用Fragment切换代替Activity跳转
如果业务逻辑需要拆分页面,可以将每个视频放在独立的Fragment中,通过FragmentTransaction的自定义动画实现过渡,同样避免Activity窗口切换的问题。
核心切换代码
// 在宿主Activity中切换Fragment getSupportFragmentManager().beginTransaction() .setCustomAnimations(R.anim.fade_in, R.anim.fade_out) // 设置淡入淡出动画 .replace(R.id.fragment_container, new NextVideoFragment()) .commit();
每个Fragment内部的TextureView和MediaPlayer初始化逻辑和你之前的Activity代码一致即可。
方案三:修改Activity窗口为透明(妥协方案)
如果必须保留Activity跳转,可以尝试将两个Activity的窗口背景设为透明,减少空白的视觉冲击,但在KitKat上可能仍有短暂的空白(取决于视频加载速度)。
步骤1:定义透明主题(styles.xml)
<style name="TransparentVideoActivity" parent="Theme.AppCompat.Light.NoActionBar"> <item name="android:windowBackground">@android:color/transparent</item> <item name="android:windowIsTranslucent">true</item> <item name="android:windowAnimationStyle">@null</item> </style>
步骤2:在Manifest中为Activity应用该主题
<activity android:name=".MainActivity" android:theme="@style/TransparentVideoActivity"/> <activity android:name=".FirstVideoActivity" android:theme="@style/TransparentVideoActivity"/>
同时要确保新Activity的MediaPlayer尽可能早地初始化(比如在onCreate中立即开始准备),缩短空白时间。
内容的提问来源于stack exchange,提问作者acroscene
相关产品推荐
相关产品推荐

