Post

[Ios App] 자동 스크롤 기능

[Ios App] 자동 스크롤 기능

자동 스크롤 구현하기 위해서 기본 로직을 생각해보자면

  • Toggle을 사용해 자동 스크롤 여부를 제어
  • ScrollViewReader를 사용하여 특정 인덱스로 스크롤
  • Timer.publish를 사용하여 일정 주기로 현재 재생 시간을 확인하고, 그에 해당하는 자막 인덱스로 스크롤
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
struct ScriptView: View {
    @State var script: Script
    @ObservedObject var youTubePlayer: YouTubePlayer // 외부에서 주입받은 YouTubePlayer
    @State private var autoScrollEnabled: Bool = false  // 자동 스크롤 on/off 토글
    @State private var currentHighlightedIndex: Int? = nil // 현재 하이라이트된 인덱스

    var body: some View {
        VStack {
            // 자동 스크롤 토글 스위치
            Toggle("자동 스크롤", isOn: $autoScrollEnabled)
                .padding(.horizontal)
                .padding(.top)

            ScrollViewReader { proxy in
                ScrollView {
                    ForEach(0..<max(script.timeStampedKOR.count, script.timeStampedJPN.count), id: \.self) { index in
                        HStack(alignment: .top, spacing: 8) {
                            // 한국어 자막
                        
                            // 일본어 자막
                            
                        }
                        .id(index) // 각 행에 id 부여 (ScrollViewReader에서 사용)
                        // 현재 하이라이트 인덱스와 일치하면 배경 색상을 입힘
                        .background(
                            index == currentHighlightedIndex ? Color.yellow.opacity(0.3) : Color.clear
                        )
                    }
                }
                .frame(height: 400)
                .scriptBackground()
                // Timer를 이용하여 자동 스크롤 구현
                .onReceive(Timer.publish(every: 0.5, on: .main, in: .common).autoconnect()) { _ in
                    if autoScrollEnabled {
                        Task {
                            do {
                                // Retrieve the current playback time asynchronously
                                let currentTime = try await youTubePlayer.getCurrentTime()
                                // Convert currentTime to seconds (Double)
                                let currentTimeInSeconds = currentTime.converted(to: .seconds).value
                                if let index = script.timeStamps.lastIndex(where: { $0.seconds <= currentTimeInSeconds }) {
                                    withAnimation {
                                        proxy.scrollTo(index, anchor: .center)
                                        currentHighlightedIndex = index
                                    }
                                }
                            } catch {
                                print("Error fetching current time: \(error)")
                            }
                        }
                    }
                }
            }
        }
    }
}

동작 설명

  • Toggle(“자동 스크롤”, isOn: $autoScrollEnabled)
    • 사용자가 스위치를 켜면 autoScrollEnabledtrue가 되어 자동 스크롤이 활성화된다.
  • ScrollViewReader와 .id(index)
    • 각 자막 행에 id(index)를 부여해, ScrollViewReader를 통해 해당 행으로 스크롤할 수 있도록 한다.
  • Timer.publish & onReceive
    • 0.5초마다 Timer가 트리거되며, 자동 스크롤이 활성화된 경우 현재 재생 시간(youTubePlayer.currentTime)과 자막의 타임스탬프를 비교
    • 현재 시간보다 작거나 같은 마지막 타임스탬프의 인덱스를 찾아 해당 인덱스로 스크롤
This post is licensed under CC BY 4.0 by the author.