Files
WhiteNights_iOS/WhiteNights/Utils/MarqueeText.swift
2025-08-24 14:44:50 +03:00

72 lines
2.3 KiB
Swift
Raw Blame History

This file contains ambiguous Unicode characters

This file contains Unicode characters that might be confused with other characters. If you think that this is intentional, you can safely ignore this warning. Use the Escape button to reveal them.

import SwiftUI
struct MarqueeText: View {
let text: String
let font: Font
let foregroundColor: Color
private let speed: CGFloat = 10 // пикселей в секунду
@State private var textWidth: CGFloat = 0
@State private var containerWidth: CGFloat = 0
@State private var offset: CGFloat = 0
@State private var animationStarted = false
var body: some View {
GeometryReader { geo in
Text(text)
.font(font)
.foregroundColor(foregroundColor)
.lineLimit(1)
.fixedSize() // важно, чтобы не обрезался
.background(WidthGetter())
.offset(x: offset)
.onAppear {
containerWidth = geo.size.width
if textWidth > containerWidth, !animationStarted {
animationStarted = true
let distance = textWidth - containerWidth
let duration = Double(distance / speed)
withAnimation(.linear(duration: duration).repeatForever(autoreverses: true)) {
offset = -distance
}
}
}
.clipped()
}
.frame(height: lineHeight(for: font))
.onPreferenceChange(WidthKey.self) { width in
textWidth = width
}
}
private func lineHeight(for font: Font) -> CGFloat {
switch font {
case .largeTitle: return 34
case .title: return 28
case .title2: return 22
case .title3: return 20
case .headline: return 17
case .body: return 17
case .callout: return 16
case .subheadline: return 15
case .caption: return 13
case .caption2: return 12
default: return 17
}
}
}
// MARK: Helpers для измерения ширины текста
private struct WidthKey: PreferenceKey {
static var defaultValue: CGFloat = 0
static func reduce(value: inout CGFloat, nextValue: () -> CGFloat) { value = nextValue() }
}
private struct WidthGetter: View {
var body: some View {
GeometryReader { geo in
Color.clear.preference(key: WidthKey.self, value: geo.size.width)
}
}
}