Skip to content

Instantly share code, notes, and snippets.

@byJeevan
Last active August 16, 2025 09:35
Show Gist options
  • Select an option

  • Save byJeevan/f67485bf380e86d4f87a723ac383827c to your computer and use it in GitHub Desktop.

Select an option

Save byJeevan/f67485bf380e86d4f87a723ac383827c to your computer and use it in GitHub Desktop.
SwiftUI Components & Extension that saves iOSDev time.
### UIKit is **EVENT-Driven** framework - We could reference each view in the hierarchy, update its appearance when the view is loaded or as a reaction on an event.
### SwiftUI is **Declarative, State Driven** framework - We cannot reference any view in the hierarchy, neither can we directly mutate a view as a reaction to an event.
Instead, we mutate the state bound to the view. Delegates, target-actions, responder chain, KVO .. replaced with Closures & bindings.
@byJeevan

byJeevan commented Jun 8, 2020

Copy link
Copy Markdown
Author

// SwiftUI Button

    // Button - Fill Width
        Button(action: {
            print("Button tapped!")
        }) {
            Text("LOGIN")
                 .fontWeight(.bold)
                .font(.headline)
                .frame(minWidth: 100, maxWidth: .infinity, minHeight: 50)
                .background(Color.red)
                .foregroundColor(Color.white)
                .cornerRadius(25.0)
        }
        
  // Button - FIT Title Width
        Button(action: {
            print("Login tapped!")
        }) {
            HStack {
                Text("LOGIN")
                    .fontWeight(.bold)
                    .font(.headline)
            }                
        }
        .padding()
        .background(Color.red)
        .foregroundColor(Color.white)
        .cornerRadius(.infinity)

@byJeevan

byJeevan commented Jun 8, 2020

Copy link
Copy Markdown
Author

Color Extension :

/// Hex to Color converter. Usage eg. Color(hex: 0x363CC) or Color(hexString: "#FF0000")
extension Color {
  
  init(hexString: String, alpha: Double = 1.0) {
    var cString = hexString.trimmingCharacters(in: .whitespacesAndNewlines).uppercased()
    
    if cString.hasPrefix("#") { cString.removeFirst() }
    
    if cString.count == 6 {
      var rgbValue: UInt64 = 0
      Scanner(string: cString).scanHexInt64(&rgbValue)
      
      self.init(red: CGFloat((rgbValue & 0xFF0000) >> 16) / 255.0,
                green: CGFloat((rgbValue & 0x00FF00) >> 8) / 255.0,
                blue: CGFloat(rgbValue & 0x0000FF) / 255.0,
                opacity: alpha)
    } else {
      self.init(hexString: "#000000")
    }
  }
  
  init(hex: Int, alpha: Double = 1.0) {
    let components = (
      R: Double((hex >> 16) & 0xff) / 255,
      G: Double((hex >> 08) & 0xff) / 255,
      B: Double((hex >> 00) & 0xff) / 255
    )
    self.init(.sRGB, red: components.R, green: components.G, blue: components.B, opacity: alpha)
  }
}

@byJeevan

byJeevan commented Jul 4, 2020

Copy link
Copy Markdown
Author

/* CARD SHADOW for any view */

<your view >.background(
                           RoundedRectangle(cornerRadius: 15)
                               .foregroundColor(Color.white)
                               .shadow( color: Color.gray.opacity(0.35),radius: 15, x: 0, y: 0))

@byJeevan

byJeevan commented Jul 18, 2020

Copy link
Copy Markdown
Author

/* Full Screen */

  <you view>
        .frame(minWidth: 0, maxWidth: .infinity, minHeight: 0, maxHeight: .infinity)
        .background(Color.red)
        .edgesIgnoringSafeArea(.all)

@byJeevan

byJeevan commented Aug 9, 2020

Copy link
Copy Markdown
Author

//Navigation bar hidden for a view

    NavigationView {
        
        ZStack {
            
      <your content view eleemnts>
        }
        .navigationBarTitle("Hidden Title")
        .navigationBarHidden(self.isNavigationBarHidden)
        .onAppear {
            self.isNavigationBarHidden = true
        }
        
        
    }

@byJeevan

byJeevan commented Aug 9, 2020

Copy link
Copy Markdown
Author

//Share Sheet

struct ShareSheet: UIViewControllerRepresentable {
    typealias Callback = (_ activityType: UIActivity.ActivityType?, _ completed: Bool, _ returnedItems: [Any]?, _ error: Error?) -> Void
    
    let activityItems: [Any]
    let applicationActivities: [UIActivity]? = nil
    let excludedActivityTypes: [UIActivity.ActivityType]? = nil
    let callback: Callback? = nil
    
    func makeUIViewController(context: Context) -> UIActivityViewController {
        let controller = UIActivityViewController(
            activityItems: activityItems,
            applicationActivities: applicationActivities)
        controller.excludedActivityTypes = excludedActivityTypes
        controller.completionWithItemsHandler = callback
        return controller
    }
    
    func updateUIViewController(_ uiViewController: UIActivityViewController, context: Context) {
        // nothing to do here
    }
}

//Usage :
struct ContentView: View {
    @State private var showShareSheet = false
    
    var body: some View {
        VStack(spacing: 20) {
            Text("Hello World")
            Button(action: {
                self.showShareSheet = true
            }) {
                Text("Share Me").bold()
            }
        }
        .sheet(isPresented: $showShareSheet) {
            ShareSheet(activityItems: ["Hello World"])
        }
    }
}

@byJeevan

Copy link
Copy Markdown
Author

Width of image = Screen width & aspect ratio retained (height)

 Image("workout-image")
            .resizable()
            .scaledToFit()

@byJeevan

byJeevan commented Oct 28, 2020

Copy link
Copy Markdown
Author
 let detectDirectionalDrags = DragGesture(minimumDistance: 3.0, coordinateSpace: .local)
    .onEnded { value in
        print(value.translation)
        
        if value.translation.width < 0 && value.translation.height > -30 && value.translation.height < 30 {
            print("left swipe")
        }
        else if value.translation.width > 0 && value.translation.height > -30 && value.translation.height < 30 {
            print("right swipe")
        }
        else if value.translation.height < 0 && value.translation.width < 100 && value.translation.width > -100 {
            print("up swipe")
        }
        else if value.translation.height > 0 && value.translation.width < 100 && value.translation.width > -100 {
            print("down swipe")
        }
        else {
            print("no clue")
        }
    }

usage .guesture(detectDirectionalDrags)

@byJeevan

byJeevan commented Nov 14, 2020

Copy link
Copy Markdown
Author

Corner Radius in specific corner

.background(Rectangle().cornerRadius(40.0, corners: [.topLeft, .topRight]).foregroundColor(Color(0xF4F5FC)))

extension View {
    func cornerRadius(_ radius: CGFloat, corners: UIRectCorner) -> some View {
        clipShape( RoundedCorner(radius: radius, corners: corners) )
    }
}

struct RoundedCorner: Shape {

    var radius: CGFloat = .infinity
    var corners: UIRectCorner = .allCorners

    func path(in rect: CGRect) -> Path {
        let path = UIBezierPath(roundedRect: rect, byRoundingCorners: corners, cornerRadii: CGSize(width: radius, height: radius))
        return Path(path.cgPath)
    }
}

@byJeevan

byJeevan commented Nov 14, 2020

Copy link
Copy Markdown
Author

What SwiftUI Transitions Are Available ?
There are 5 transitions available in SwiftUI:

  1. Slide - slide in the view from the leading side and remove it towards the trailing side.
  2. Move - slide in from the direction specified and remove it from the same direction.
  3. Opacity - fade in the view when inserted and fade out the view when removed.
  4. Scale - insert the view FROM the scale specified and reverse the effect when removed.
  5. Offset - like the move transition by you can set your own x and y coordinate.

Choices for applying an animation?

  1. Apply an animation directly to the view.
  2. Apply an animation to the parent view.
  3. Use an explicit animation (withAnimation closure) around the variable change that controls when the view is inserted/removed.

⚠️ As of this writing, the opacity and scale only work with explicit animations (withAnimation).

@byJeevan

byJeevan commented Mar 1, 2021

Copy link
Copy Markdown
Author

Creating a List with Navigation Link
Note the hierarchy : NavigationView >> List >> NavigationLink

        NavigationView {
            List(1...10, id: \.self) { index in
                
                if index == 1 {
                    //do something for row = 1
                }
                else{
                    NavigationLink(
                        destination: Text("Item #\(index) Details"),
                        label: {
                            Text("Item #\(index)")
                                .font(.system(size: 20, weight: .bold, design: .rounded))
                        })
                }
            
            }
            
            .navigationTitle("Latest News")
        }

@byJeevan

byJeevan commented Mar 1, 2021

Copy link
Copy Markdown
Author

Tabbar/ TabView creation - VStack as parent.

       VStack {
           
           TabView {
             
               
               Text("Video Tab")
                   .font(.system(size: 30, weight: .bold, design: .rounded))
                   .tabItem {
                       Image(systemName: "video.circle.fill")
                       Text("Live")
                   }
               
        
                
               Text("Profile Tab")
                   .font(.system(size: 30, weight: .bold, design: .rounded))
                   .tabItem {
                       Image(systemName: "person.crop.circle")
                       Text("Profile")
                   }
           }
           .accentColor(.red)
           .onAppear() {
               UITabBar.appearance().barTintColor = .white
           }
       }

Tint color and selection/highlight color of tab changed.

@byJeevan

byJeevan commented May 15, 2021

Copy link
Copy Markdown
Author

Click/Tap/Select/Touch event to view:

    @State private var isPresented = false

<your view>.gesture(DragGesture(minimumDistance: 0)
                                                        .onChanged { value in
                                                            if isPresented {
                                                                print("Touch down")
                                                            }
                                                            isPresented = false
                                                        }
                                                        .onEnded { value in
                                                            print("Touch up")
                                                            isPresented = true
                                                        }
                                                )
                                            

@byJeevan

byJeevan commented Nov 4, 2021

Copy link
Copy Markdown
Author

.navigationBarHidden(true) is not constructed for NavigationView instead, it should be it's child.

@byJeevan

byJeevan commented Nov 4, 2021

Copy link
Copy Markdown
Author

Return a view from a function - that checks some conditions.
PS: return types : some View vs AnyView vs View
Ref: https://stackoverflow.com/questions/62895948/how-to-return-a-view-type-from-a-function-in-swift-ui

@ViewBuilder func WidgetDetail(wOption: WidgetOptions) -> some View {
        switch wOption.id {
        case 0:
            CountryPicker()
        default:
            Text("Widget Not implemented")
        }
    }

@byJeevan

byJeevan commented Nov 5, 2021

Copy link
Copy Markdown
Author

Present view Modally (fullscreen) [ for iOS 14.0+]

         @State var isQuizPlayPresented = false
            
            Button(action: {
                  isQuizPlayPresented.toggle()
              }) {
                  Text("Get Started")
              }
              .padding()
              .fullScreenCover(isPresented: $isQuizPlayPresented, onDismiss: nil, content: QuizPlayView.init)

Dismiss a presented view (modally)

    @Environment(\.presentationMode) private var presentationMode // define
     self.presentationMode.wrappedValue.dismiss() // In button action

Advanced:

            .fullScreenCover(isPresented: $isResultView,
                             onDismiss: {
                self.presentationMode.wrappedValue.dismiss() // Dismisses current view along with Child view dismissed
            }, content: {
                QuizResultView(totalScore: 10) // Pass custom parameter to child view
            })

@byJeevan

Copy link
Copy Markdown
Author

Make the width of element fill till parent width

        VStack(alignment: .center) {
          Rectangle()
            .frame(height: 0.0) // -------- note this 
           Text("SHOW DETAILS")
        }
        .background(.yellow)
        

@byJeevan

byJeevan commented Apr 11, 2024

Copy link
Copy Markdown
Author

Basic Rail :

struct QuizRail: View {
  
  var body: some View {
    ScrollView(.horizontal) {
      HStack(spacing: 16) {
        ForEach((1...10), id: \.self) {_ in
          Rectangle()
            .frame(width: 150, height: 200)
            .cornerRadius(8)
        }
      }
      .padding(.horizontal, 16)
    }
  }
}

@byJeevan

byJeevan commented Apr 16, 2024

Copy link
Copy Markdown
Author

List Options without separator (from iOS 15.0+),

  • Row background
          List {
            ForEach(items, id: \.self) { item in
              Text("item here")
                .listRowBackground(Color.yellow)
                .listRowInsets(.none)
                .listRowSeparator(.hidden)
            }
          }
          .listStyle(.plain)
  • Swipe Actions
               .swipeActions(edge: .leading, allowsFullSwipe: false) {
                  Button {
                    print("Leading swipe action on \(item)")
                  } label: {
                    Label("Favorite", systemImage: "star.fill")
                  }
                  .tint(.yellow)
                }
                .swipeActions(edge: .trailing, allowsFullSwipe: false) {
                  Button(role: .destructive) {
                    print("Trailing swipe action on \(item)")
                  } label: {
                    Label("Delete", systemImage: "trash.fill")
                  }
                  
                  Button {
                    print("More actions on \(item)")
                  } label: {
                    Label("More", systemImage: "ellipsis")
                  }
                  .tint(.blue)
                }

Tip: Give .tint(.clear) if you need just icon without background color.

@byJeevan

Copy link
Copy Markdown
Author

☢️ A workaround calculated the height of ScrollView

  @State var heightCalculated = 0.0

  var body: some View {

    ScrollView {
      ForEach(0..<10) { i in
        Text("\(i)")
      }
      .background(
        GeometryReader { proxy in
          Color.clear.onAppear { 
            heightCalculated = proxy.size.height
            debugPrint(proxy.size.height)
          }
        }
      )

    }
    .frame(height: heightCalculated)
  }

@byJeevan

Copy link
Copy Markdown
Author

To make Content view as parameter. A better way to build Generic views.

struct ContainerView<Content: View>: View {
  @ViewBuilder var content: Content
    
  var body: some View {
    content
  }
}


// Usage
ContainerView{
  ...
}

@byJeevan

Copy link
Copy Markdown
Author

Debugging:

  1. let _ = Self._printChanges() print statement to trace view lifecycle
  2. let _ = print("Update XYZView") We use this print to trace whether the body of Particular view (eg. SpyView) is executed or not.

ref: https://sarunw.com/posts/how-to-do-print-debugging-in-swiftui/

@byJeevan

Copy link
Copy Markdown
Author

To make fullscreen view to fill entire screen:

ZStack {
   Text("Hello").background(.yellow)
}
.frame(maxWidth: .infinity, maxHeight: .infinity) // this is important
.background(.blue)

@byJeevan

byJeevan commented Mar 7, 2025

Copy link
Copy Markdown
Author
public extension View {

  // Creates a outline border for text of having any font size.
  func outlinedText(shadowColor: Color = .white, radius: CGFloat = 0, offset: CGFloat = 0.5) -> some View {
    self
      .shadow(color: shadowColor, radius: radius, x: offset, y: 0)  // Right
      .shadow(color: shadowColor, radius: radius, x: 0, y: offset)  // Down
      .shadow(color: shadowColor, radius: radius, x: -offset, y: 0) // Left
      .shadow(color: shadowColor, radius: radius, x: 0, y: -offset) // Up
  }
}

@byJeevan

byJeevan commented Aug 16, 2025

Copy link
Copy Markdown
Author

Create Alert (system alert)

struct ContentView: View {
    @State private var showAlert = false // 1
    
    var body: some View {
        VStack {
            Button("Show Alert") {
                showAlert = true // 2
            }
        }
// 3.
        .alert("Important Message", isPresented: $showAlert) {
            Button("OK", role: .cancel) { }
            Button("Delete", role: .destructive) {
                // handle delete action
            }
        } message: {
            Text("This is an alert in SwiftUI.")
        }
    }
}

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment