任务一 实现 MV 页面与页面跳转

单元二已经在歌曲列表中预留了 MV 图标。本任务先搭建视频页面并接通跳转,再补上歌曲信息和返回按钮。

一、任务目标

任务结束后,应用将能够:

  • 从歌曲列表的 MV 图标进入 VideoActivity。
  • 使用 Intent 传递 MV 地址、歌曲名称和歌手信息。
  • 在视频页面显示歌曲信息,并通过返回按钮回到列表。
  • 没有 MV 地址时不打开视频页面。

二、创建视频页面

1. 创建视频页面布局

在 app/src/main/res/layout 下新建 activity_video.xml,先用黑色 ConstraintLayout 和 FrameLayout 搭出视频页面的基本框架。项目已启用 ViewBinding,创建并同步布局后会生成 ActivityVideoBinding。后续任务会在视频容器中加入播放器。

app/src/main/res/layout/activity_video.xml
<androidx.constraintlayout.widget.ConstraintLayout xmlns:android="http://schemas.android.com/apk/res/android"
xmlns:app="http://schemas.android.com/apk/res-auto"
android:layout_width="match_parent"
android:layout_height="match_parent"
android:background="@android:color/black">
<!-- 视频容器,后续将在此处放入播放器。 -->
<FrameLayout
android:id="@+id/video_container"
android:layout_width="0dp"
android:layout_height="0dp"
android:background="@android:color/black"
app:layout_constraintBottom_toBottomOf="parent"
app:layout_constraintEnd_toEndOf="parent"
app:layout_constraintStart_toStartOf="parent"
app:layout_constraintTop_toTopOf="parent" />
</androidx.constraintlayout.widget.ConstraintLayout>

2. 创建 VideoActivity 并接收页面数据

在 app/src/main/java/com/sziit/musicplayer/ui/activity 下新建 VideoActivity.kt。Activity 先加载刚创建的布局,并从 Intent 中读取 MV 地址、歌曲名称和歌手,暂存在成员变量中,供后续页面显示和视频播放使用。

app/src/main/java/com/sziit/musicplayer/ui/activity/VideoActivity.kt
package com.sziit.musicplayer.ui.activity
import android.os.Bundle
import androidx.appcompat.app.AppCompatActivity
import com.sziit.musicplayer.databinding.ActivityVideoBinding
class VideoActivity : AppCompatActivity() {
private lateinit var binding: ActivityVideoBinding
// 保存列表页传来的数据,供后续页面显示和视频播放使用。
private var mvUrl = ""
private var songName = ""
private var singerName = ""
override fun onCreate(savedInstanceState: Bundle?) {
super.onCreate(savedInstanceState)
// 加载视频页面布局。
binding = ActivityVideoBinding.inflate(layoutInflater)
setContentView(binding.root)
// 读取列表页通过 Intent 传来的信息。
mvUrl = intent.getStringExtra(EXTRA_MV).orEmpty()
songName = intent.getStringExtra(EXTRA_SONG).orEmpty()
singerName = intent.getStringExtra(EXTRA_SINGER).orEmpty()
}
// 集中定义 Intent 使用的键名,保证传递和读取时使用相同的名称。
companion object {
const val EXTRA_MV = "mv"
const val EXTRA_SONG = "song"
const val EXTRA_SINGER = "singer"
}
}

ActivityVideoBinding 会在布局文件创建后生成。若编辑器暂时提示找不到它,等待项目完成同步即可。

3. 注册 VideoActivity

打开 app/src/main/AndroidManifest.xml,在 <application> 标签内注册 VideoActivity。

app/src/main/AndroidManifest.xml
<manifest xmlns:android="http://schemas.android.com/apk/res/android">
...
<application ...>
...
<activity android:name=".ui.activity.VideoActivity" />
...
</application>
</manifest>

三、从歌曲列表打开视频页面

1. 设置 MV 图标的点击操作

打开 MusicListFragment.kt,把适配器的 MV 点击回调交给 openMv(),并在该方法中检查地址、传递数据和打开页面。

app/src/main/java/com/sziit/musicplayer/ui/fragment/MusicListFragment.kt
// ... 省略已有导入。
import android.content.Intent
import android.widget.Toast
import com.sziit.musicplayer.ui.activity.VideoActivity
class MusicListFragment : Fragment() {
// ... 省略已有字段和其他方法。
override fun onViewCreated(view: View, savedInstanceState: Bundle?) {
super.onViewCreated(view, savedInstanceState)
// ... 省略 RecyclerView 初始化代码。
adapter = MusicListAdapter(
onMusicClick = { song -> playSong(song) },
onMvClick = {}
onMvClick = { song -> openMv(song) }
)
// ... 省略 RecyclerView 后续设置代码。
}
private fun openMv(song: Song) {
// 没有 MV 地址时提示用户,并结束跳转。
if (song.mvPath.isNullOrEmpty()) {
Toast.makeText(requireContext(), "该歌曲没有视频", Toast.LENGTH_SHORT).show()
return
}
// 将 MV 地址和歌曲信息传给 VideoActivity。
val intent = Intent(requireContext(), VideoActivity::class.java).apply {
putExtra(VideoActivity.EXTRA_MV, song.mvPath)
putExtra(VideoActivity.EXTRA_SONG, song.name)
putExtra(VideoActivity.EXTRA_SINGER, song.singer)
}
startActivity(intent)
}
}

2. 验证页面跳转

运行应用,点击有 MV 地址的歌曲图标,确认能打开黑色的视频页面;按设备的系统返回键,确认回到歌曲列表。没有 MV 地址的歌曲不会显示 MV 图标;跳转方法也会检查地址,避免打开空页面。

点击 MV 图标后打开视频页面

此时视频页面还没有歌曲信息和页面内的返回按钮,下一部分会继续添加。

四、完善视频页面布局

1. 添加歌曲信息和返回按钮

在 activity_video.xml 的视频容器之后添加返回按钮、歌曲名称和歌手控件。返回图标使用初始工程中的 ic_back,并设置白色 tint,使它在黑色背景上清晰可见。

app/src/main/res/layout/activity_video.xml
<androidx.constraintlayout.widget.ConstraintLayout ...>
...
<!-- 返回按钮显示在页面左上角。 -->
<ImageView
android:id="@+id/img_back"
android:layout_width="56dp"
android:layout_height="56dp"
android:contentDescription="返回"
android:padding="12dp"
android:src="@drawable/ic_back"
app:tint="@android:color/white"
app:layout_constraintStart_toStartOf="parent"
app:layout_constraintTop_toTopOf="parent" />
<!-- 歌曲名称显示在页面左下角。 -->
<TextView
android:id="@+id/tv_song"
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:layout_marginStart="16dp"
android:layout_marginBottom="4dp"
android:textColor="@android:color/white"
android:textSize="22sp"
android:textStyle="bold"
app:layout_constraintBottom_toTopOf="@id/tv_singer"
app:layout_constraintStart_toStartOf="parent" />
<!-- 歌手显示在歌曲名称下方。 -->
<TextView
android:id="@+id/tv_singer"
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:layout_marginStart="16dp"
android:layout_marginBottom="16dp"
android:textColor="@android:color/white"
android:textSize="16sp"
app:layout_constraintBottom_toBottomOf="parent"
app:layout_constraintStart_toStartOf="parent" />
</androidx.constraintlayout.widget.ConstraintLayout>

2. 显示歌曲信息并设置返回操作

回到 VideoActivity.kt,在 onCreate() 中将已接收的歌曲信息写入控件,并设置返回按钮关闭当前页面。

app/src/main/java/com/sziit/musicplayer/ui/activity/VideoActivity.kt
class VideoActivity : AppCompatActivity() {
// ... 省略已有字段和其他代码。
override fun onCreate(savedInstanceState: Bundle?) {
// ... 省略 super.onCreate()、布局加载和 Intent 数据读取。
// 将收到的歌曲信息显示在页面上。
binding.tvSong.text = songName
binding.tvSinger.text = singerName
// 点击后关闭视频页面,返回歌曲列表。
binding.imgBack.setOnClickListener { finish() }
}
// ... 省略 companion object。
}

3. 验证视频页面

再次运行应用,点击有 MV 地址的歌曲图标,确认页面显示歌曲名称、歌手和左上角的返回按钮;点击返回按钮,确认回到歌曲列表。

MV 页面与页面跳转效果

任务小结

本任务先搭建了视频页面并接通列表跳转,再补充歌曲信息和返回操作。列表页通过 Intent 传递 MV 地址、歌曲名称和歌手,VideoActivity 接收并显示这些数据。下一任务将在视频容器中接入 ExoPlayer。