#swift #swiftui
#swift #swiftui
Вопрос:
Я хочу создать индикатор выполнения (круг) с большим круглым наконечником, который будет следовать за прогрессом. Не могли бы вы подсказать мне, есть ли какой-нибудь стандартный способ сделать это? Или для понимания положения требуется дополнительный круг и некоторые вычисления?
struct Loader: View {
var percent: CGFloat = 0
var colors: [Color] = [
Color(red: 0.949, green: 0.9098, blue: 0.8706),
Color(red: 0.9569, green: 0.5882, blue: 0.2196)
]
var body: some View {
ZStack{
Circle()
.fill(Color.white)
.frame(width: 300, height: 300, alignment: .center)
.overlay(
Circle()
.trim(from: 0, to: percent * 0.01)
.stroke(style: StrokeStyle(lineWidth: 22, lineCap: .butt, lineJoin: .miter, miterLimit: 10))
.fill(AngularGradient(gradient: .init(colors: colors), center: .center, startAngle: .zero, endAngle: .init(degrees: 360)))
.rotationEffect(.degrees(-90))
).animation(.spring(response: 1.0, dampingFraction: 1.0, blendDuration: 1.0))
Text(String(format: "%.1f", percent) " %").font(.system(size: 20)).fontWeight(.heavy)
}
}
}
Что я хочу сделать:
Что я уже сделал:
Ответ №1:
Вот потенциальное решение. Я добавил наложение поверх загрузчика, я увеличил его высоту до полного размера большого круга, а затем просто повернул наложение с завершением. Таким образом, они анимируются одновременно.
import SwiftUI
struct CircleView: View {
@State var percent: CGFloat = 0
var body: some View {
Loader(percent: $percent)
.onAppear {
DispatchQueue.main.asyncAfter(deadline: .now() 2.0) {
withAnimation(Animation.linear(duration: 1.0)) {
percent = 20
}
}
DispatchQueue.main.asyncAfter(deadline: .now() 3.0) {
withAnimation(Animation.linear(duration: 2.0)) {
percent = 55
}
}
DispatchQueue.main.asyncAfter(deadline: .now() 5.0) {
withAnimation(Animation.linear(duration: 4.0)) {
percent = 100
}
}
}
}
}
struct CircleView_Previews: PreviewProvider {
static var previews: some View {
CircleView()
}
}
struct Loader: View {
@Binding var percent: CGFloat
var colors: [Color] = [
Color(red: 0.949, green: 0.9098, blue: 0.8706),
Color(red: 0.9569, green: 0.5882, blue: 0.2196)
]
let circleHeight: CGFloat = 300
var body: some View {
let pinHeight = circleHeight * 0.1
let completion = percent * 0.01
Circle()
.trim(from: 0, to: completion)
.stroke(style: StrokeStyle(lineWidth: 22, lineCap: .butt, lineJoin: .miter, miterLimit: 10))
.fill(AngularGradient(gradient: .init(colors: colors), center: .center, startAngle: .zero, endAngle: .init(degrees: 360)))
.rotationEffect(.degrees(-90))
.frame(width: circleHeight, height: circleHeight)
.overlay(
Text(String(format: "%.1f", percent) " %").font(.system(size: 20)).fontWeight(.heavy)
.animation(nil)
)
.overlay(
Circle()
.frame(width: pinHeight, height: pinHeight)
.offset(y: -pinHeight / 2)
.frame(maxWidth: .infinity, maxHeight: .infinity, alignment: .top)
.rotationEffect(Angle(degrees: 360 * Double(completion)))
)
}
}
Комментарии:
1. Спасибо. Я не уверен в интерфейсе и SwiftUI, но ваше предложение кажется довольно простым в реализации.