Guest User

HeartFelt

a guest
Oct 31st, 2025
31
0
Never
Not a member of Pastebin yet? Sign Up, it unlocks many cool features!
Swift 9.85 KB | Source Code | 0 0
  1. import SwiftUI
  2.  
  3. struct Block: Identifiable {
  4.     let id = UUID()
  5.    
  6.     var color: Color
  7.     var opacity: Double
  8.    
  9.     init(color: Color, opacity: Double = 1.0) {
  10.         self.color = color
  11.         self.opacity = opacity
  12.     }
  13. }
  14.  
  15. extension Color {
  16.     static let redShade = Color(red: 160/255, green: 0, blue: 0)
  17. }
  18.  
  19. struct HeartView: View {
  20.     @State private var colors: [[Block]]
  21.     @State private var color: Color = .red
  22.     @State private var visibleIndices: Set<String> = []
  23.     @State private var rotate = 85.0
  24.     @State private var offsetY = -200.0
  25.     @State private var opacity = 0.0
  26.    
  27.     let spacing: CGFloat
  28.     let radius: CGFloat
  29.    
  30.     init(
  31.         colors: [[Block]],
  32.         spacing: CGFloat = 0,
  33.         radius: CGFloat = 0
  34.     ) {
  35.         self._colors = State(initialValue: colors)
  36.         self.spacing = spacing
  37.         self.radius = radius
  38.     }
  39.    
  40.     var body: some View {
  41.         VStack(spacing: spacing) {
  42.             ForEach(0..<colors.count, id: \.self) { row in
  43.                 HStack(spacing: spacing) {
  44.                     ForEach(0..<colors[row].count, id: \.self) { col in
  45.                         let key = "\(row)-\(col)"
  46.                         Rectangle()
  47.                             .fill(colors[row][col].color)
  48.                             .opacity(visibleIndices.contains(key) ? 1 : 0)
  49.                             .scaleEffect(visibleIndices.contains(key) ? 1 : 0)
  50.                             .aspectRatio(1, contentMode: .fit)
  51.                             .clipShape(.rect(cornerRadius: radius))
  52.                             .onTapGesture {
  53.                                 colors[row][col].color = color
  54.                             }
  55.                     }
  56.                 }
  57.             }
  58.         }
  59.         .rotation3DEffect(
  60.             .degrees(rotate),
  61.             axis: (x: 1, y: 0, z: 0)
  62.         )
  63.         .offset(y: offsetY)
  64.         .opacity(opacity)
  65.         .padding()
  66.         .onAppear {
  67.             fadeInBlocks()
  68.             withAnimation(.easeInOut(duration: 1)) {
  69.                 rotate = 0.0
  70.                 offsetY = 0.0
  71.                 opacity = 1.0
  72.             }
  73.         }
  74.     }
  75.    
  76.     // MARK: - Gradual Fade-in Logic
  77.     func fadeInBlocks() {
  78.         // Collect only non-clear cells
  79.         let allIndices = colors.enumerated().flatMap { row, cols in
  80.             cols.indices.compactMap { col -> String? in
  81.                 let color = colors[row][col].color
  82.                 return color == .clear ? nil : "\(row)-\(col)"
  83.             }
  84.         }
  85.        
  86.         var remaining = allIndices.shuffled()
  87.         var delay: Double = 0
  88.         let delta: Double = 0.05
  89.        
  90.         while !remaining.isEmpty {
  91.             let nextBatch = Array(remaining.prefix(4))
  92.             remaining.removeFirst(min(4, remaining.count))
  93.            
  94.             DispatchQueue.main.asyncAfter(deadline: .now() + delay) {
  95.                 withAnimation(.easeIn(duration: delta)) {
  96.                     visibleIndices.formUnion(nextBatch)
  97.                 }
  98.             }
  99.             delay += delta
  100.         }
  101.     }
  102.    
  103.  
  104. }
  105.  
  106. #Preview {
  107.     ZStack {
  108.         Color.blue.opacity(0.3).ignoresSafeArea()
  109.        
  110.         HeartView(colors: heartImage)
  111.     }
  112. }
  113.  
  114.  
  115. let heartImage: [[Block]] = {
  116.     var colors = Array(
  117.         repeating: Array(repeating: Block(color: .red), count: 16),
  118.         count: 16
  119.     )
  120.    
  121.     colors[0][0].color = .clear
  122.     colors[0][1].color = .clear
  123.     colors[0][2].color = .clear
  124.     colors[0][3].color = .clear
  125.     colors[0][4].color = .clear
  126.     colors[0][5].color = .clear
  127.     colors[0][6].color = .clear
  128.     colors[0][7].color = .clear
  129.     colors[0][8].color = .clear
  130.     colors[0][9].color = .clear
  131.     colors[0][10].color = .clear
  132.     colors[0][11].color = .clear
  133.     colors[0][12].color = .clear
  134.     colors[0][13].color = .clear
  135.     colors[0][14].color = .clear
  136.     colors[0][15].color = .clear
  137.    
  138.     colors[1][0].color = .clear
  139.     colors[1][1].color = .clear
  140.     colors[1][2].color = .clear
  141.     colors[1][3].color = .clear
  142.     colors[1][4].color = .clear
  143.     colors[1][5].color = .clear
  144.     colors[1][6].color = .clear
  145.     colors[1][7].color = .clear
  146.     colors[1][8].color = .clear
  147.     colors[1][9].color = .clear
  148.     colors[1][10].color = .clear
  149.     colors[1][11].color = .clear
  150.     colors[1][12].color = .clear
  151.     colors[1][13].color = .clear
  152.     colors[1][14].color = .clear
  153.     colors[1][15].color = .clear
  154.     colors[2][0].color = .clear
  155.     colors[2][1].color = .clear
  156.     colors[2][2].color = .clear
  157.     colors[2][3].color = .black
  158.     colors[2][4].color = .black
  159.     colors[2][5].color = .black
  160.     colors[2][6].color = .clear
  161.     colors[2][7].color = .clear
  162.     colors[2][8].color = .clear
  163.     colors[2][9].color = .clear
  164.     colors[2][10].color = .black
  165.     colors[2][11].color = .black
  166.     colors[2][12].color = .black
  167.     colors[2][13].color = .clear
  168.     colors[2][14].color = .clear
  169.     colors[2][15].color = .clear
  170.     colors[3][0].color = .clear
  171.     colors[3][1].color = .clear
  172.     colors[3][2].color = .black
  173.     colors[3][3].color = .redShade
  174.  
  175.     colors[3][6].color = .black
  176.     colors[3][7].color = .clear
  177.     colors[3][8].color = .clear
  178.     colors[3][9].color = .black
  179.  
  180.     colors[3][13].color = .black
  181.     colors[3][14].color = .clear
  182.     colors[3][15].color = .clear
  183.     colors[4][0].color = .clear
  184.     colors[4][1].color = .black
  185.     colors[4][2].color = .redShade
  186.  
  187.     colors[4][7].color = .black
  188.     colors[4][8].color = .black
  189.  
  190.     colors[4][11].color = .white
  191.    
  192.     colors[4][14].color = .black
  193.     colors[4][15].color = .clear
  194.    
  195.     colors[5][0].color = .clear
  196.     colors[5][1].color = .black
  197.     colors[5][2].color = .redShade
  198.    
  199.     colors[5][12].color = .white
  200.    
  201.     colors[5][14].color = .black
  202.     colors[5][15].color = .clear
  203.     colors[6][0].color = .clear
  204.     colors[6][1].color = .black
  205.     colors[6][2].color = .redShade
  206.  
  207.     colors[6][14].color = .black
  208.     colors[6][15].color = .clear
  209.     colors[7][0].color = .clear
  210.     colors[7][1].color = .black
  211.     colors[7][2].color = .redShade
  212.     colors[7][14].color = .black
  213.     colors[7][15].color = .clear
  214.     colors[8][0].color = .clear
  215.     colors[8][1].color = .clear
  216.     colors[8][2].color = .black
  217.     colors[8][3].color = .redShade
  218.     colors[8][4].color = .redShade
  219.  
  220.     colors[8][13].color = .black
  221.     colors[8][14].color = .clear
  222.     colors[8][15].color = .clear
  223.    
  224.     colors[9][0].color = .clear
  225.     colors[9][1].color = .clear
  226.     colors[9][2].color = .clear
  227.     colors[9][3].color = .black
  228.     colors[9][4].color = .redShade
  229.     colors[9][5].color = .redShade
  230.  
  231.     colors[9][12].color = .black
  232.     colors[9][13].color = .clear
  233.     colors[9][14].color = .clear
  234.     colors[9][15].color = .clear
  235.     colors[10][0].color = .clear
  236.     colors[10][1].color = .clear
  237.     colors[10][2].color = .clear
  238.     colors[10][3].color = .clear
  239.     colors[10][4].color = .black
  240.     colors[10][5].color = .redShade
  241.     colors[10][6].color = .redShade
  242.  
  243.     colors[10][11].color = .black
  244.     colors[10][12].color = .clear
  245.     colors[10][13].color = .clear
  246.     colors[10][14].color = .clear
  247.     colors[10][15].color = .clear
  248.     colors[11][0].color = .clear
  249.     colors[11][1].color = .clear
  250.     colors[11][2].color = .clear
  251.     colors[11][3].color = .clear
  252.     colors[11][4].color = .clear
  253.     colors[11][5].color = .black
  254.     colors[11][6].color = .redShade
  255.     colors[11][7].color = .redShade
  256.  
  257.     colors[11][10].color = .black
  258.     colors[11][11].color = .clear
  259.     colors[11][12].color = .clear
  260.     colors[11][13].color = .clear
  261.     colors[11][14].color = .clear
  262.     colors[11][15].color = .clear
  263.     colors[12][0].color = .clear
  264.     colors[12][1].color = .clear
  265.     colors[12][2].color = .clear
  266.     colors[12][3].color = .clear
  267.     colors[12][4].color = .clear
  268.     colors[12][5].color = .clear
  269.     colors[12][6].color = .black
  270.     colors[12][7].color = .redShade
  271.     colors[12][8].color = .redShade
  272.     colors[12][9].color = .black
  273.     colors[12][10].color = .clear
  274.     colors[12][11].color = .clear
  275.     colors[12][12].color = .clear
  276.     colors[12][13].color = .clear
  277.     colors[12][14].color = .clear
  278.     colors[12][15].color = .clear
  279.    
  280.     colors[13][0].color = .clear
  281.     colors[13][1].color = .clear
  282.     colors[13][2].color = .clear
  283.     colors[13][3].color = .clear
  284.     colors[13][4].color = .clear
  285.     colors[13][5].color = .clear
  286.     colors[13][6].color = .clear
  287.     colors[13][7].color = .black
  288.     colors[13][8].color = .black
  289.     colors[13][9].color = .clear
  290.     colors[13][10].color = .clear
  291.     colors[13][11].color = .clear
  292.     colors[13][12].color = .clear
  293.     colors[13][13].color = .clear
  294.     colors[13][14].color = .clear
  295.     colors[13][15].color = .clear
  296.     colors[14][0].color = .clear
  297.     colors[14][1].color = .clear
  298.     colors[14][2].color = .clear
  299.     colors[14][3].color = .clear
  300.     colors[14][4].color = .clear
  301.     colors[14][5].color = .clear
  302.     colors[14][6].color = .clear
  303.     colors[14][7].color = .clear
  304.     colors[14][8].color = .clear
  305.     colors[14][9].color = .clear
  306.     colors[14][10].color = .clear
  307.     colors[14][11].color = .clear
  308.     colors[14][12].color = .clear
  309.     colors[14][13].color = .clear
  310.     colors[14][14].color = .clear
  311.     colors[14][15].color = .clear
  312.     colors[15][0].color = .clear
  313.     colors[15][1].color = .clear
  314.     colors[15][2].color = .clear
  315.     colors[15][3].color = .clear
  316.     colors[15][4].color = .clear
  317.     colors[15][5].color = .clear
  318.     colors[15][6].color = .clear
  319.     colors[15][7].color = .clear
  320.     colors[15][8].color = .clear
  321.     colors[15][9].color = .clear
  322.     colors[15][10].color = .clear
  323.     colors[15][11].color = .clear
  324.     colors[15][12].color = .clear
  325.     colors[15][13].color = .clear
  326.     colors[15][14].color = .clear
  327.     colors[15][15].color = .clear
  328.    
  329.     return colors
  330. }()
  331.  
  332.  
  333.  
  334.  
  335.  
  336.  
Advertisement
Add Comment
Please, Sign In to add comment