ConfirmationView.swift 2.7 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596
  1. import SwiftUI
  2. struct ConfirmationView: View {
  3. @Binding var success: Bool?
  4. var body: some View {
  5. ZStack {
  6. Group {
  7. Image(systemName: "checkmark.circle.fill")
  8. .resizable()
  9. .foregroundColor(.loopGreen)
  10. .opacity(success == true ? 1.0 : 0.0)
  11. .scaleEffect(success == true ? 1.0 : 0.0)
  12. Image(systemName: "xmark.circle.fill")
  13. .resizable()
  14. .foregroundColor(.loopRed)
  15. .opacity(success == false ? 1.0 : 0.0)
  16. .scaleEffect(success == false ? 1.0 : 0.0)
  17. BlinkingView(count: 10, size: 10)
  18. .opacity(success == nil ? 1.0 : 0.0)
  19. .scaleEffect(success == nil ? 1.0 : 0.0)
  20. }
  21. .frame(width: 50, height: 50)
  22. }
  23. .frame(maxWidth: .infinity, maxHeight: .infinity)
  24. .onTapGesture {
  25. toggleState()
  26. }
  27. }
  28. func toggleState() {
  29. withAnimation(.easeIn.speed(1)) {
  30. success = success == nil ? true : success == true ? false : nil
  31. }
  32. }
  33. }
  34. struct ConfirmationView_Previews: PreviewProvider {
  35. struct Container: View {
  36. @State var success: Bool?
  37. var body: some View {
  38. ConfirmationView(success: $success)
  39. }
  40. }
  41. static var previews: some View {
  42. Container()
  43. }
  44. }
  45. struct BlinkingView: View {
  46. let count: UInt
  47. let size: CGFloat
  48. var body: some View {
  49. GeometryReader { geometry in
  50. ForEach(0 ..< Int(count)) { index in
  51. item(forIndex: index, in: geometry.size)
  52. .frame(width: geometry.size.width, height: geometry.size.height)
  53. }
  54. }
  55. .animation(.none, value: false)
  56. .aspectRatio(contentMode: .fit)
  57. .onAppear {
  58. scale = 1
  59. opacity = 1
  60. }
  61. }
  62. @State var scale = 0.5
  63. @State var opacity = 0.25
  64. func animation(index: Int) -> Animation {
  65. Animation
  66. .default
  67. .repeatCount(.max, autoreverses: true)
  68. .delay(Double(index) / Double(count) / 2)
  69. }
  70. private func item(forIndex index: Int, in geometrySize: CGSize) -> some View {
  71. let angle = 2 * CGFloat.pi / CGFloat(count) * CGFloat(index)
  72. let x = (geometrySize.width / 2 - size / 2) * cos(angle)
  73. let y = (geometrySize.height / 2 - size / 2) * sin(angle)
  74. return Circle()
  75. .frame(width: size, height: size)
  76. .scaleEffect(scale)
  77. .opacity(opacity)
  78. .animation(animation(index: index), value: scale)
  79. .animation(animation(index: index), value: opacity)
  80. .offset(x: x, y: y)
  81. }
  82. }