首页 经验

诗词速通,漫游泡泡,词汇宝,新维日语,简易物理,点此下载


如何利用 Swift(编程语言) 和 SwiftUI 框架的 Preview(预览功能) 来制作一个帮助你进行日语影子跟读(Shadowing)的练习工具

时间: 2025-09-07 05:26:40

(部分内容来自网络,其真实性存疑,为了避免对您造成误导,请谨慎甄别。)

好的,我们来详细说明一下如何利用 Swift(编程语言) 和 SwiftUI 框架的 Preview(预览功能) 来制作一个帮助你进行日语影子跟读(Shadowing)的练习工具。


这个应用的核心功能是:播放一段日语音频,同时在屏幕上动态显示当前正在说的文本(就像卡拉OK一样),帮助你进行眼和耳的同步跟读训练。


我们将使用 SwiftUI 来实现界面和逻辑,并充分利用 SwiftUI Preview 来实时调试界面布局。




第一步:项目概述与设计


功能需求:

1.  音频播放控制: 播放、暂停、跳转。

2.  文本同步高亮: 根据音频的当前播放时间,高亮对应的文本。

3.  文本数据: 需要准备一段日语文本和对应的时间戳。


技术要点:

*   AVPlayer:用于播放远程或本地的音频文件。

*   ScrollViewReader 和 ScrollView:用于在文本很长时自动滚动到当前高亮句子的位置。

*   Timer:定时器,用于不断检查音频的当前播放时间,并更新UI。

*   SwiftUI Preview:用于实时设计和调整文本高亮、布局等界面效果。




第二步:数据模型 (Model)


首先,我们需要定义数据结构。我们需要将完整的文本拆分成句子或段落,并为每一段关联一个开始时间戳。


import Foundation

// 单句模型 struct Sentence: Identifiable, Decodable {     var id: UUID = UUID()     let startTime: Double // 开始时间(秒)     let text: String      // 该时间点对应的句子
    // CodingKeys 用于JSON解码(如果从文件加载数据)     enum CodingKeys: String, CodingKey {         case startTime, text     } }
// 跟读会话模型,包含整个音频和文本信息 struct ShadowingSession: Decodable {     let audioFileName: String     let sentences: [Sentence] }


你可以创建一个 session.json 文件来存储你的音频和文本数据。

{
  "audioFileName": "japanese_dialogue.mp3",
  "sentences": [
    { "startTime": 0.0, "text": "こんにちは。" },
    { "startTime": 2.5, "text": "今日はいい天気ですね。" },
    { "startTime": 6.0, "text": "どこかへ出かけませんか?" },
    { "startTime": 10.0, "text": "ええ、そうしましょう。" }
  ]
}




第三步:创建播放器管理器 (ViewModel)


这是一个关键类,它负责管理音频播放、跟踪时间,并发布当前状态给UI。


import Foundation
import AVFoundation
import Combine

class ShadowingPlayerViewModel: ObservableObject {     // 播放器     private var player: AVPlayer?     // 定时器,用于更新当前时间     private var timer: AnyCancellable?          // 发布的属性,UI会监听这些变化     @Published var isPlaying = false     @Published var currentTime: Double = 0.0     @Published var currentSentence: Sentence?          let session: ShadowingSession          init(session: ShadowingSession) {         self.session = session         // 初始化播放器         if let url = Bundle.main.url(forResource: session.audioFileName, withExtension: nil) {             player = AVPlayer(url: url)         }                  // 设置定时器,每秒更新60次(更流畅)         timer = Timer.publish(every: 0.016, on: .main, in: .common)             .autoconnect()             .sink { [weak self] _ in                 self?.updateCurrentTime()             }     }          // 更新当前时间,并查找对应的句子     private func updateCurrentTime() {         guard let player = player else { return }         currentTime = player.currentTime().seconds                  // 根据当前时间找到最后一个开始时间小于等于currentTime的句子         // 这里假设sentences是按startTime升序排列的         if let sentence = session.sentences.last(where: { $0.startTime <= currentTime }) {             currentSentence = sentence         }     }          // 播放/暂停     func playPause() {         guard let player = player else { return }                  if player.timeControlStatus == .playing {             player.pause()             isPlaying = false         } else {             player.play()             isPlaying = true         }     }          // 跳转到特定句子的开始时间     func seek(to sentence: Sentence) {         player?.seek(to: CMTime(seconds: sentence.startTime, preferredTimescale: 1))         // 如果当前是暂停状态,跳转后自动播放         if !isPlaying {             playPause()         }     } }




第四步:构建用户界面 (View)


现在我们来创建主界面,使用 SwiftUI Preview 来实时查看效果。


import SwiftUI

struct ShadowingView: View {     @StateObject var viewModel: ShadowingPlayerViewModel          var body: some View {         VStack(spacing: 20) {             // 1. 播放控制按钮             Button(action: {                 viewModel.playPause()             }) {                 Image(systemName: viewModel.isPlaying ? "pause.circle.fill" : "play.circle.fill")                     .font(.system(size: 60))             }                          // 2. 文本显示区域             ScrollViewReader { scrollProxy in                 ScrollView {                     LazyVStack(alignment: .leading, spacing: 15) {                         ForEach(viewModel.session.sentences) { sentence in                             Text(sentence.text)                                 .font(.title2)                                 .padding(8)                                 .background(                                     // 如果是当前句子,高亮为黄色                                     viewModel.currentSentence?.id == sentence.id ? Color.yellow.opacity(0.5) : Color.clear                                 )                                 .cornerRadius(8)                                 .id(sentence.id) // 必须为可滚动视图设置id                                 .onTapGesture {                                     // 点击某句可以跳转到那句                                     viewModel.seek(to: sentence)                                 }                         }                     }                     .padding()                 }                 .frame(maxHeight: 300)                 // 当当前句子变化时,自动滚动到该句子                 .onChange(of: viewModel.currentSentence) { newSentence in                     withAnimation(.easeInOut(duration: 0.5)) {                         if let sentence = newSentence {                             scrollProxy.scrollTo(sentence.id, anchor: .center)                         }                     }                 }             }                          // 3. 时间显示(可选)             Text("$viewModel.currentTime, specifier: "%.1f")秒")                 .font(.body.monospacedDigit())                          Spacer()         }         .padding()     } }




第五步:利用 SwiftUI Preview 进行预览和调试


这是 SwiftUI 最强大的功能之一。我们可以在另一台模拟器或甚至不运行整个App的情况下,实时调整和预览界面。


// 为Preview提供一个假的Session
#if DEBUG
let previewSession = ShadowingSession(
    audioFileName: "preview_audio.mp3",
    sentences: [
        Sentence(startTime: 0.0, text: "これはプレビュー用のテキストです。"),
        Sentence(startTime: 3.0, text: "SwiftUIのPreview機能はとても便利です。"),
        Sentence(startTime: 7.0, text: "リアルタイムでUIの確認ができます。")
    ]
)

struct ShadowingView_Previews: PreviewProvider {     static var previews: some View {         // 在Preview中,我们不需要真的播放音频         ShadowingView(viewModel: ShadowingPlayerViewModel(session: previewSession))     } } #endif


在 Preview 中你能做什么:

1.  即时反馈: 修改 ShadowingView 的代码(例如字体大小、颜色、间距),Preview 面板会立即更新。

2.  调试布局: 检查文本高亮、滚动区域是否正常工作。你可以手动修改 @Published 的属性来模拟播放状态(例如,在 Preview 的代码里写 viewModel.currentSentence = previewSession.sentences[1] 来测试高亮和滚动)。

3.  多设备预览: 在 Preview 面板底部,你可以选择在不同的设备(iPhone, iPad)和深色/浅色模式下查看界面效果。




总结


通过结合 Swift 的强大多媒体处理能力和 SwiftUI Preview 的实时UI调试能力,你可以高效地构建一个非常实用的日语影子跟读工具。


开发流程:

1.  定义数据模型 (Sentence, ShadowingSession)。

2.  创建管理播放和状态的 ViewModel (ShadowingPlayerViewModel)。

3.  构建主界面 (ShadowingView)。

4.  不断使用 SwiftUI Preview 来调整和优化界面。

5.  最后,将 JSON 数据文件和音频文件添加到项目中,并初始化 ShadowingPlayerViewModel。


希望这个详细的指南对你有帮助!你可以在这个基础上继续添加更多功能,比如播放速度控制、循环播放某一句、生词本等。


还有问题,向AI提问。


上一个 【swift】问题可能出现在 `min(600, geometry.size.width - 200)` 这个计算中 文章列表 下一个 SwiftUI 算法可视化合集框架

(汉语/英语/日语/法语/德语)语音助手(识别/合成),智能翻译,高中物理动画,数据分析,数据可视化,电话: 18201798243(同v)

© 2019-至今 适观科技

沪ICP备17002269号