Initial commit

This commit is contained in:
15lu.akari
2025-08-24 14:44:50 +03:00
parent dca1ae410b
commit 5a583d9415
50 changed files with 2019 additions and 17 deletions

View File

@ -0,0 +1,71 @@
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)
}
}
}