Snippets Collections
import SwiftUI

struct ContentView: View {
    var body: some View {
        VStack {
            Image(systemName: "globe")
                .imageScale(.large)
                .foregroundStyle(.tint)
            Text("Hello, world!")
        }
        .padding()
        .alignment(.top)
    }
}
extension View {
    
    @ViewBuilder
    func alignment(_ alignment: Alignment) -> some View {
        switch alignment {
        case .leading:
            self.frame(maxWidth: .infinity, alignment: .leading)
        case .trailing:
            self.frame(maxWidth: .infinity, alignment: .trailing)
        case .top:
            self.frame(maxHeight: .infinity, alignment: .top)
        case .bottom:
            self.frame(maxHeight: .infinity, alignment: .bottom)
        case .topLeading:
            self
                .frame(maxHeight: .infinity, alignment: .top)
                .frame(maxWidth: .infinity, alignment: .leading)
        case .topTrailing:
            self
                .frame(maxHeight: .infinity, alignment: .top)
                .frame(maxWidth: .infinity, alignment: .trailing)
        case .bottomLeading:
            self
                .frame(maxHeight: .infinity, alignment: .bottom)
                .frame(maxWidth: .infinity, alignment: .leading)
        case .bottomTrailing:
            self
                .frame(maxHeight: .infinity, alignment: .bottom)
                .frame(maxWidth: .infinity, alignment: .trailing)
        default:
            self.frame(maxWidth: .infinity, maxHeight: .infinity, alignment: .center)
        }
    }
}

#Preview {
    ContentView()
}
import SwiftUI

struct ContentView: View {
    @State var buttonHeight: Double = .zero
    
    var body: some View {
        ZStack(alignment: .bottom) {
            ScrollView {
                VStack {
                    Text("Lorem ipsum dolor sit amet, consectetur adipiscing elit. Etiam ac cursus nisl. Ut tincidunt nunc ut mauris finibus maximus. Donec libero ex, dapibus in placerat non, volutpat et turpis. Maecenas convallis quis est vitae fringilla. Nullam augue sapien, porta sit amet pulvinar vitae, accumsan id tellus. Nam condimentum laoreet congue. Cras enim velit, maximus eget cursus id, gravida sit amet libero. \n")
                    Text("Mauris rutrum dolor nunc, vel auctor diam luctus ac. Donec tincidunt ornare tincidunt. Cras felis purus, commodo ac auctor eu, ornare quis neque. Nunc ullamcorper massa scelerisque, ornare justo eget, consequat sapien. Sed vulputate hendrerit nibh, vitae fringilla tortor. Integer laoreet mauris ut neque dignissim sagittis. Maecenas sit amet ipsum magna. In cursus dui non ante auctor iaculis. Praesent blandit, libero id tempus pretium, nisi enim sodales dui, eget finibus metus metus ut ipsum. Morbi tristique, metus quis ullamcorper hendrerit, neque turpis varius nisi, quis dictum nulla mauris sed erat. Morbi velit ligula, bibendum ut arcu sed, ullamcorper sollicitudin tortor. Nunc ultricies mattis leo, sit amet porta mi varius suscipit. \n")
                    Text("Cras eget lorem justo. Nunc consequat lacinia eros, eget scelerisque enim tempus ut. Suspendisse at tellus mauris. Etiam vel auctor neque. Praesent nec ligula vitae dolor tempor malesuada nec id sapien. Donec mattis augue ac nunc pharetra, ut imperdiet mi ultricies. Fusce id nulla lacinia elit tincidunt venenatis nec malesuada dui. Maecenas consectetur turpis vel eros molestie interdum. Mauris vestibulum odio nibh, eget tristique neque interdum dapibus. Vestibulum commodo ligula in tempus suscipit. Mauris scelerisque turpis in nunc tempus suscipit. Nulla tempus fermentum dui rutrum posuere. Aenean elit est, lobortis quis leo efficitur, pretium sollicitudin arcu. Maecenas et leo scelerisque, dignissim arcu a, pellentesque ipsum.")
                }
                .padding(.bottom, 40 + buttonHeight)
            }
            .padding()
            .edgesIgnoringSafeArea(.bottom)
            
            Button {
                
            } label: {
                Text("Hello!")
                    .tint(.white)
                    .padding()
                    .background(
                        RoundedRectangle(cornerRadius: 15)
                            .foregroundColor(Color.yellow)
                    )
                    .frame(maxWidth: 80)
            }
            .getSize { size in
                self.buttonHeight = size.height
            }
        }
    }
}

extension View {
    func getSize(size: @escaping (CGSize) -> Void) -> some View {
        background {
            GeometryReader { geo in
                Color.clear
                    .preference(key: ViewPreferenceKey.self, value: geo.size)
            }
        }
        .onPreferenceChange(ViewPreferenceKey.self, perform: size)
    }
}

struct ViewPreferenceKey: PreferenceKey {
    static var defaultValue: CGSize = .zero
    
    static func reduce(value: inout CGSize, nextValue: () -> CGSize) {}
}

struct ContentView_Previews: PreviewProvider {
    static var previews: some View {
        ContentView()
    }
}
import SwiftUI

struct ContentView: View {
    private let userDefaults = UserDefaults.standard
    private let COLOR_KEY = "COLOR_KEY"
    @State var selectedColor: Color = .purple
    
    var body: some View {
        NavigationView {
            VStack(spacing: 20) {
                RoundedRectangle(cornerRadius: 20)
                    .fill(selectedColor)
                    .frame(height: 240)
                    .overlay {
                        Text("Red")
                            .font(.system(.title))
                            .foregroundColor(.white)
                    }
                
                Button {
                    saveColor(color: selectedColor)
                } label: {
                    Text("Save Color")
                        .frame(maxWidth: .infinity)
                        .font(.system(.headline, design: .rounded))
                }
                .padding()
                .frame(maxWidth: .infinity)
                .foregroundColor(.white)
                .background(selectedColor)
                .cornerRadius(10)
                
                Spacer()
            }
            .padding()
            .navigationBarTitle("Save Color", displayMode: .inline)
            .navigationBarItems(trailing: ColorPicker("", selection: $selectedColor))
            .onAppear {
                selectedColor = loadColor()
            }
        }
    }
    
    // Save Color
    func saveColor(color: Color) {
        let color = UIColor(color).cgColor
        
        if let components = color.components {
            userDefaults.set(components, forKey: COLOR_KEY)
            print("Save Color: \(components)")
        }
    }
    
    // Load Color
    func loadColor() -> Color {
        guard let array = userDefaults.object(forKey: COLOR_KEY) as? [CGFloat] else {
            return Color.purple
        }
        print("Load Color: \(array)")
        
        let color = Color(.sRGB, red: array[0], green: array[1], blue: array[2], opacity: array[3])
        return color
    }
}
import SwiftUI

struct ThreeColorView: View {
    static let red_x: CGFloat = UIScreen.main.bounds.width/2
    static let red_y: CGFloat = UIScreen.main.bounds.height/3
    
    @State private var redPosition: CGPoint = .init(x: red_x, y: red_y)
    
    @State private var greenPosition: CGPoint = .init(x: red_x - 30, y: red_y + 60)
    
    @State private var bluePosition: CGPoint = .init(x: red_x + 30, y: red_y + 60)
    
    var body: some View {
        ZStack {
            Color.black.ignoresSafeArea()
            
            Circle()
                .fill(Color(.systemRed))
                .frame(width: 200, height: 200)
                .position(redPosition)
                .gesture(
                    DragGesture()
                        .onChanged({ value in
                            redPosition = value.location
                        })
                )
            Circle()
                .fill(Color(.systemGreen))
                .frame(width: 200, height: 200)
                .position(greenPosition)
                .gesture(
                    DragGesture()
                        .onChanged({ value in
                            greenPosition = value.location
                        })
                )
                .blendMode(.lighten)
            
            Circle()
                .fill(Color(.systemBlue))
                .frame(width: 200, height: 200)
                .position(bluePosition)
                .gesture(
                    DragGesture()
                        .onChanged({ value in
                            bluePosition = value.location
                        })
                )
                .blendMode(.lighten)
        }
    }
}
ScrollViewReader { proxy in
    ScrollView(.horizontal, showsIndicators: false) {
        HStack { // or LazyHStack
            ForEach(0..<items.count) { index in
                Text(items[index].title)
                    .id(index)
                    .onTapGesture {
                        print("tapped \(index)")
                    }
            }
        }
        .onAppear {
            DispatchQueue.main.async { 
                proxy.scrollTo(selectedIndex, anchor: .center)
            }
        }
    }
}
<html>
<head>
</head>
<body>
<div>
<a href="https://www.amazon.de/dp/B0BY49J5J3/?tag=r29future">E-Book</a></div>
</body>
</html>
import SwiftUI

// Capítulo 5: Casos de Uso Avanzados de Property Wrappers en SwiftUI.
// Ejemplo: Combinando diferentes Property Wrappers...

class UserData: ObservableObject {
    @Published var name: String = "John Doe"
}

@propertyWrapper
struct UpperCase {
    private(set) var value: String
    
    var wrappedValue: String {
        get { value }
        set { value = newValue.uppercased() }
    }
    
    init(wrappedValue: String) {
        self.value = wrappedValue.uppercased()
    }
}

struct User {
    @UpperCase var name: String
}

struct UserView: View {
    @ObservedObject var userData: UserData
    
    var body: some View {
        VStack {
            Text("Hello, \(userData.name)")
            TextField("Enter your name", text: $userData.name)
        }
    }
}

struct ContentView: View {
    @ObservedObject var userData = UserData()
    @State var user = User(name: "John Doe")
    
    var body: some View {
        VStack {
            UserView(userData: userData)
            Text("Hello, \(user.name)")
            TextField("Enter your name", text: $user.name)
        }
    }
}
import SwiftUI

// Capítulo 4: Creando nuestros propios Property Wrappers

@propertyWrapper
struct UpperCase {
    private(set) var value: String
    
    var wrappedValue: String {
        get { value }
        set { value = newValue.uppercased() }
    }
    
    init(wrappedValue: String) {
        self.value = wrappedValue.uppercased()
    }
}

struct User {
    @UpperCase var name: String
}

struct UserView: View {
    @ObservedObject var user: User
    
    var body: some View {
        VStack {
            Text("Hello, \(user.name)")
            TextField("Enter your name", text: $user.name)
        }
    }
}

struct ContentView: View {
     var body: some View {
       UserView(user: User(name: "John Doe"))
     }
}
import SwiftUI

class UserData: ObservableObject {
    @Published var name: String = "John Doe"
}

struct UserView: View {
    @ObservedObject var userData: UserData
    
    var body: some View {
        VStack {
            Text("Hello, \(userData.name)")
            TextField("Enter your name", text: $userData.name)
        }
    }
}

struct ContentView: View {
    var body: some View {
        UserView(userData: UserData())
    }
}
import SwiftUI

class UserData: ObservableObject {
    @Published var name: String = "John Doe"
}

struct UserView: View {
    @StateObject var userData: UserData
    
    var body: some View {
        VStack {
            Text("Hello, \(userData.name)")
            TextField("Enter your name", text: $userData.name)
        }
    }
}

struct ContentView: View {
    var body: some View {
        UserView(userData: UserData())
    }
}
import SwiftUI

struct UserSettings {
    var fontSize: CGFloat = 17
}

struct UserView: View {
    @EnvironmentObject var userSettings: UserSettings
    
    var body: some View {
        VStack {
            Text("Hello, World")
                .font(.system(size: userSettings.fontSize))
            Slider(value: $userSettings.fontSize, in: 10...30)
        }
    }
}

struct ContentView: View {
    var body: some View {
        UserView().environmentObject(UserSettings())
    }
}
import SwiftUI

struct User {
    var name: String
}

struct UserView: View {
    @Binding var user: User
    
    var body: some View {
        VStack {
            Text("Hello, \(user.name)")
            TextField("Enter your name", text: $user.name)
        }
    }
}

struct ContentView: View {
    @State var user = User(name: "John Doe")
    
    var body: some View {
        UserView(user: $user)
    }
}
import SwiftUI

struct ContentView: View {
    @State var name: String = "John Doe"
    
    var body: some View {
        VStack {
            Text("Hello, \(name)")
            TextField("Enter your name", text: $name)
        }
    }
}
//7. Implementar la autenticación de Firebase en nuestra aplicación

//Para implementar la autenticación de Firebase en nuestra aplicación, debemos seguir los siguientes pasos:

//- Agregar la autenticación de Firebase a nuestra aplicación.
//- Crear una cuenta de usuario y permitir que los usuarios inicien sesión y cierren sesión en la aplicación.

//```swiftui
// Registrar un usuario
Auth.auth().createUser(withEmail: email, password: password) { (authResult, error) in
  if let error = error {
    print("Error al registrar el usuario: \(error.localizedDescription)")
    return
  }
  guard let user = authResult?.user else {
    print("No se pudo obtener el usuario")
    return
  }
  print("Usuario registrado con éxito")
}

// Iniciar sesión con un usuario existente
Auth.auth().signIn(withEmail: email, password: password) { (authResult, error) in
  if let error = error {
    print("Error al iniciar sesión: \(error.localizedDescription)")
    return
  }
  guard let user = authResult?.user else {
    print("No se pudo obtener el usuario")
    return
  }
  print("Inicio de sesión exitoso")
}

// Cerrar sesión
do {
  try Auth.auth().signOut()
  print("Cierre de sesión exitoso")
} catch let error as NSError {
  print("Error al cerrar sesión: \(error.localizedDescription)")
}
//6. Implementar Cloud Storage en nuestra aplicación

//Para implementar Cloud Storage en nuestra aplicación, debemos seguir los siguientes pasos:

//- Agregar Cloud Storage a nuestra aplicación.
//- Subir y descargar archivos desde el almacenamiento en la nube.

//```swift
// Subir un archivo al almacenamiento en la nube
let storage = Storage.storage()
let storageRef = storage.reference()
let imageRef = storageRef.child("images/\(imageName)")
let metadata = StorageMetadata()
metadata.contentType = "image/jpeg"
let imageData = UIImageJPEGRepresentation(image, 0.8)!
imageRef.putData(imageData, metadata: metadata) { (metadata, error) in
  if let error = error {
    print("Error al subir el archivo: \(error.localizedDescription)")
    return
  }
  print("Archivo subido con éxito")
}

// Descargar un archivo desde el almacenamiento en la nube
let storage = Storage.storage()
let storageRef = storage.reference()
let imageRef = storageRef.child("images/\(imageName)")
imageRef.getData(maxSize: 1 * 1024 * 1024) { (data, error) in
  if let error = error {
    print("Error al descargar el archivo: \(error.localizedDescription)")
    return
  }
  guard let imageData = data else {
    print("No se pudo obtener el archivo")
    return
  }
  let image = UIImage(data: imageData)
  print("Archivo descargado con éxito")
}
// Leer datos de la base de datos
let db = Firestore.firestore()
db.collection("users").document(userId).getDocument { (document, error) in
if let document = document, document.exists {
let data = document.data()
let name = data?["name"] as? String ?? ""
let email = data?["email"] as? String ?? ""
print("Nombre: (name), Email: (email)")
} else {
print("El documento no existe")
}
}

// Consultar datos de la base de datos
let db = Firestore.firestore()
db.collection("users").whereField("name", isEqualTo: "Juan Pérez").getDocuments { (querySnapshot, error) in
  if let error = error {
         print("Error al consultar los datos: (error.localizedDescription)")
      return
}
guard let documents = querySnapshot?.documents else {
      print("No se encontraron documentos")
      return
}
for document in documents {
let data = document.data()
let name = data["name"] as? String ?? ""
let email = data["email"] as? String ?? ""
     print("Nombre: (name), Email: (email)")
  }
}

// Escuchar cambios en la base de datos
let db = Firestore.firestore()
db.collection("users").document(userId).addSnapshotListener { (document, error) in
  if let document = document, document.exists {
let data = document.data()
let name = data?["name"] as? String ?? ""
let email = data?["email"] as? String ?? ""
      print("Nombre: (name), Email: (email)")
} else {
     print("El documento no existe")
}
}
// Importar Firebase Auth
import Firebase
import FirebaseAuth

// Registrar un usuario
Auth.auth().createUser(withEmail: email, password: password) { (result, error) in
  if let error = error {
    print("Error al registrar el usuario: \(error.localizedDescription)")
    return
  }
  guard let user = result?.user else {
    print("No se pudo obtener el usuario")
    return
  }
  print("Usuario registrado con éxito: \(user.uid)")
}

// Autenticar un usuario
Auth.auth().signIn(withEmail: email, password: password) { (result, error) in
  if let error = error {
    print("Error al autenticar el usuario: \(error.localizedDescription)")
    return
  }
  guard let user = result?.user else {
    print("No se pudo obtener el usuario")
    return
  }
  print("Usuario autenticado con éxito: \(user.uid)")
}
//Para eliminar datos de la base de datos, podemos utilizar el siguiente código:
let documentRef = db.collection("cities").document("SF")
documentRef.delete() { error in
  if let error = error {
    print("Error al eliminar documento: \(error.localizedDescription)")
    return
  }
  print("Documento eliminado con éxito")
}
//Para actualizar datos en la base de datos, podemos utilizar el siguiente código:
let documentRef = db.collection("cities").document("SF")
documentRef.updateData([
  "population": 884363,
  "capital": false
]) { error in
  if let error = error {
    print("Error al actualizar datos: \(error.localizedDescription)")
    return
  }
  print("Datos actualizados con éxito")
}
//Para escribir datos en la base de datos, podemos utilizar el siguiente código:
let data: [String: Any] = [
  "name": "Santo Domingo",
  "population": 13929286
]
db.collection("cities").document("San Dom").setData(data) { error in
  if let error = error {
    print("Error al escribir datos: \(error.localizedDescription)")
    return
  }
  print("Datos escritos con éxito")
}
//Para leer datos de la base de datos, podemos utilizar los siguientes métodos:

// Leer todos los documentos de una colección
db.collection("cities").getDocuments() { (querySnapshot, error) in
  if let error = error {
    print("Error al obtener documentos: \(error.localizedDescription)")
    return
  }
  for document in querySnapshot!.documents {
    let data = document.data()
    let name = data["name"] as? String ?? ""
    let population = data["population"] as? Int ?? 0
    print("Ciudad: \(name), Población: \(population)")
  }
}

// Leer un documento específico de una colección
db.collection("cities").document("SF").getDocument() { (document, error) in
  if let document = document, document.exists {
    let data = document.data()
    let name = data?["name"] as? String ?? ""
    let population = data?["population"] as? Int ?? 0
    print("Ciudad: \(name), Población: \(population)")
  } else {
    print("El documento no existe")
  }
}
//Para crear una referencia a la base de datos, podemos utilizar el siguiente código:
let db = Firestore.firestore()
//Para eliminar archivos, podemos utilizar el siguiente código:
let fileRef = storageRef.child("files").child("fileName")
fileRef.delete { (error) in
  if let error = error {
    print("Error al eliminar archivo: \(error.localizedDescription)")
    return
  }
  print("Archivo eliminado con éxito")
}
//Para cargar y descargar archivos, podemos utilizar los siguientes métodos:

// Cargar un archivo
let data = Data()
let fileRef = storageRef.child("files").child("fileName")
fileRef.putData(data, metadata: nil) { (metadata, error) in
  if let error = error {
    print("Error al cargar archivo: \(error.localizedDescription)")
    return
  }
  print("Archivo cargado con éxito")
}

// Descargar un archivo
let fileRef = storageRef.child("files").child("fileName")
fileRef.getData(maxSize: 10 * 1024 * 1024) { (data, error) in
  if let error = error {
    print("Error al descargar archivo: \(error.localizedDescription)")
    return
  }
  print("Archivo descargado con éxito")
}
//Para crear una referencia al almacenamiento, podemos utilizar el siguiente código:
let storageRef = Storage.storage().reference()
if let user = Auth.auth().currentUser {
  let email = user.email
  let uid = user.uid
  print("Email: \(email), UID: \(uid)")
}
Auth.auth().signIn(with: credential) { (result, error) in
  if let error = error {
    print("Error al autenticar usuario: \(error.localizedDescription)")
    return
  }
  print("Usuario autenticado con éxito")
}
Auth.auth().signIn(with: credential) { (result, error) in
  if let error = error {
    print("Error al autenticar usuario: \(error.localizedDescription)")
    return
  }
  print("Usuario autenticado con éxito")
}
let provider = OAuthProvider(providerID: "google.com")
provider.scopes = ["email", "profile"]
ref.child("users").child("userId").observe(.value) { (snapshot) in
  if let value = snapshot.value as? [String: Any] {
    let name = value["name"] as? String ?? ""
    let age = value["age"] as? Int ?? 0
    print("Name: \(name), Age: \(age)")
  }
}
// Escribir datos
ref.child("users").child("userId").setValue(["name": "John", "age": 30])

// Leer datos
ref.child("users").child("userId").observeSingleEvent(of: .value) { (snapshot) in
  if let value = snapshot.value as? [String: Any] {
    let name = value["name"] as? String ?? ""
    let age = value["age"] as? Int ?? 0
    print("Name: \(name), Age: \(age)")
  }
}
// Capítulo 5: Actualización y eliminación de datos en CoreData

// Para actualizar y eliminar objetos en CoreData utilizando SwiftUI, podemos utilizar el contexto de CoreData. A continuación se muestra:

Button("Update") {
    let request: NSFetchRequest<Product> = Product.fetchRequest()
    request.predicate = NSPredicate(format: "name == %@", "iPhone")
    
    do {
        let products = try context.fetch(request)
        if let product = products.first {
            product.price = 899.99
            try context.save()
        }
    } catch {
        print(error.localizedDescription)
    }
}

Button("Delete") {
    let request: NSFetchRequest<Product> = Product.fetchRequest()
    request.predicate = NSPredicate(format: "name == %@", "iPhone")
    
    do {
        let products = try context.fetch(request)
        if let product = products.first {
            context.delete(product)
            try context.save()
        }
    } catch {
        print(error.localizedDescription)
    }
}
//Para crear nuevas instancias de objetos y guardarlas. en la base de datos, podemos utilizar el contexto de CoreData. A continuación  se muestra un ejemplo de como crear una nueva instancia de objetos y guardarla en la base de datos:
Button("Save") {
     let product = Product(context: context)
     product.name = "iPhone"
     product.price = 999.99
           do {
               try! context.save() //guardar los datos en la base de datos de forma permanente...
            } catch {
                        print(error.localizedDescription)
         }
}
//Capítulo 4: Uso de CoreData con SwiftUI
//Para recuperar y mostrar datos utilizando las vistas de SwiftUI, podemos utilizar la clase FetchRequest. A continuación se muestra un ejemplo de cómo utilizar FetchRequest para recuperar datos de CoreData:
struct ProductList: View {
          @Environment(\.managedObjectContext) var context
          @FetchRequest(entity: Product.entity(), sortDescriptors: [])
          var products: FetchedResults<Product>
          var body: some View {
                  List(products, id: \.self) { product in
                                Text(product.name)
                      }
              }
      }
/*A continuación, debemos agregar nuestro modelo de datos a ese contenedor. A continuación se muestra un ejemplo de cómo agregar un modelo de datos a un contenedor de persistencia:*/
let container = NSPersistentContainer(name: "MyApp")
let description = NSPersistentStoreDescription()
description.type = NSInMemoryStoreType
container.persistentStoreDescriptions = [description]
try! container.loadPersistentStores()
//Por último, debemos inicializar el almacén de datos. A continuación se muestra un ejemplo de cómo inicializar el almacén de datos:    
let context = persistentContainer.viewContext
/*Capítulo 3: Configuración de CoreData
Para configurar CoreData, primero debemos crear un contenedor de persistencia. A continuación se muestra un ejemplo de cómo crear un contenedor de persistencia en un archivo AppDelegate.swift:*/

lazy var persistentContainer: NSPersistentContainer = {
          let container = NSPersistentContainer(name: "MyApp")
       container.loadPersistentStores(completionHandler: { (storeDescription, error) in
       if let error = error as NSError? {
                              fatalError("Unresolved error \(error), \(error.userInfo)")
                     }
           })
                       return container
  }()
//También podemos crear nuestro modelo de datos mediante código. A continuación, se muestra un ejemplo de cómo crear una clase modelo de entidad de CoreData mediante código:

import CoreData

class Product: NSManagedObject {
    @NSManaged var name: String
    @NSManaged var price: Double
}

let productEntity = NSEntityDescription.entity(forEntityName: "Product", in: context)!
let product = Product(entity: productEntity, insertInto: context)
product.name = "iPhone"
product.price = 999.99
//Capítulo 2: Diseño de modelo de datos en CoreData

//Podemos crear nuestro modelo de datos utilizando el editor de modelo visual de Xcode. A continuación se muestra un ejemplo de cómo se ve una clase modelo de entidad de CoreData en el editor de modelo visual:

class Product: NSManagedObject {
    @NSManaged var name: String
    @NSManaged var price: Double
}
//
//  SearchableDemo.swift
//  SwiftUIDemo
//
//  Created by shiyanjun on 2023/2/17.
//

import SwiftUI

struct NavigtionViewDemo: View {
    var body: some View {
        NavigationStack {
            List {
                NavigationLink("我的组件") {
                    MyCompView()
                }
                
                NavigationLink("我的API") {
                    MyApiView()
                }
            }
            .navigationTitle("配置中心")
            .navigationBarTitleDisplayMode(.inline)
            .listStyle(PlainListStyle())
        }
    }
}

struct MyCompView: View {
    
    var body: some View {
        NavigationStack {
            List {
                NavigationLink(destination: ArticleCompView()) {
                    Text("文章组件")
                }
                NavigationLink(destination: PhotoCompView()) {
                    Text("图片组件")
                }
                NavigationLink(destination: ChartCompView()) {
                    Text("报表组件")
                }
            }
            .listStyle(PlainListStyle())
            .navigationBarTitle("我的组件", displayMode: .inline)
            .navigationBarItems(trailing: AddCompButtonView())
        }
    }
}

struct MyApiView: View {
    
    var body: some View {
        NavigationStack {
            List {
                NavigationLink(destination: ArticleApiView()) {
                    Text("文章API")
                }
                NavigationLink(destination: PhotoApiView()) {
                    Text("图片API")
                }
                NavigationLink(destination: ChartApiView()) {
                    Text("报表API")
                }
            }
            .listStyle(PlainListStyle())
            .navigationBarTitle("我的API", displayMode: .inline)
            .navigationBarItems(trailing: AddApiButtonView())
        }
    }
}

struct ArticleCompView: View {
    var body: some View {
        NavigationStack {
            Text("文章组件信息")
                .navigationTitle("文章组件信息")
        }
    }
}

struct PhotoCompView: View {
    var body: some View {
        NavigationStack {
            Text("照片组件信息")
                .navigationTitle("照片组件信息")
        }
    }
}

struct ChartCompView: View {
    var body: some View {
        NavigationStack {
            Text("报表组件信息")
                .navigationTitle("报表组件信息")
        }
    }
}

struct ArticleApiView: View {
    var body: some View {
        NavigationStack {
            Text("文章API")
                .navigationTitle("文章API")
        }
    }
}

struct PhotoApiView: View {
    var body: some View {
        NavigationStack {
            Text("照片API")
                .navigationTitle("照片API")
        }
    }
}

struct ChartApiView: View {
    var body: some View {
        NavigationStack {
            Text("报表API")
                .navigationTitle("报表API")
        }
    }
}

struct AddCompButtonView: View {
    var body: some View {
        NavigationStack {
            NavigationLink(destination: AddCompView()) {
                Image(systemName: "plus")
            }
        }
    }
}

struct AddApiButtonView: View {
    var body: some View {
        NavigationStack {
            NavigationLink(destination: AddApiView()) {
                Image(systemName: "plus")
            }
        }
    }
}

struct AddCompView: View {
    var body: some View {
        NavigationStack {
            ZStack {
                Color.orange
                Text("创建组件页面")
            }
            .navigationTitle("创建组件页面")
        }
    }
}

struct AddApiView: View {
    var body: some View {
        ZStack {
            Color.purple
            Text("创建API页面")
        }
    }
}

struct SearchableDemo_Previews: PreviewProvider {
    static var previews: some View {
        NavigtionViewDemo()
    }
}
//
//  DragView.swift
//  SwiftUIDemo
//
//  Created by shiyanjun on 2023/2/12.
//

import SwiftUI

struct DragView: View {
    @State private var location: CGPoint = CGPoint(x: 50, y: 50)
    @GestureState private var fingerLocation: CGPoint? = nil
    @GestureState private var startLocation: CGPoint? = nil // 1
    
    var simpleDrag: some Gesture {
        DragGesture()
            .onChanged { value in
                var newLocation = startLocation ?? location // 3
                newLocation.x += value.translation.width
                newLocation.y += value.translation.height
                self.location = newLocation
            }.updating($startLocation) { (value, startLocation, transaction) in
                startLocation = startLocation ?? location // 2
            }
    }
    
    var fingerDrag: some Gesture {
        DragGesture()
            .updating($fingerLocation) { (value, fingerLocation, transaction) in
                fingerLocation = value.location
            }
    }
    
    var body: some View {
        VStack {
            ZStack {
                RoundedRectangle(cornerRadius: 10)
                    .foregroundColor(.pink)
                    .frame(width: 100, height: 100)
                    .position(location)
                    .gesture(
                        simpleDrag.simultaneously(with: fingerDrag)
                    )
                if let fingerLocation = fingerLocation {
                    Circle()
                        .stroke(Color.green, lineWidth: 2)
                        .frame(width: 44, height: 44)
                        .position(fingerLocation)
                }
            }
            HStack {
                Text("X:\(String(format: "%0.f", location.x))")
                    .foregroundColor(.indigo)
                    .font(.system(.largeTitle, design: .rounded))
                Text("Y:\(String(format: "%0.f", location.y))")
                    .foregroundColor(.indigo)
                    .font(.system(.largeTitle, design: .rounded))
            }
        }
    }
}

struct DragView_Previews: PreviewProvider {
    static var previews: some View {
        DragView()
    }
}
//
//  DeviceInfoView.swift
//  SwiftUIDemo
//
//  Created by shiyanjun on 2023/2/12.
//

import SwiftUI

struct DeviceInfoView: View {
    let screenSize: CGSize = UIScreen.main.bounds.size
    let device: UIDevice = UIDevice.current
    
    var body: some View {
        VStack(alignment: .leading, spacing: 10) {
            Text("屏幕宽度:\(screenSize.width)")    // 屏幕宽度:430.000000
            Text("屏幕高度:\(screenSize.height)")   // 屏幕高度:932.000000
            Text("设备名称:\(device.name)")         // 设备名称:iPhone 14 Pro Max
            Text("系统名称:\(device.systemName)")   // 系统名称:iOS
            Text("系统版本:\(device.systemVersion)")// 系统版本:16.2
            Text("设备型号:\(device.model)")        // 设备型号:iPhone
        }
        .padding()
        .background(.orange)
        .cornerRadius(10)
    }
}

struct DeviceInfoView_Previews: PreviewProvider {
    static var previews: some View {
        DeviceInfoView()
    }
}
//
//  SwiftUIDemoApp.swift
//  SwiftUIDemo
//
//  Created by shiyanjun on 2023/1/29.
//

import SwiftUI

@main
struct LifeCycleApp: App {
    // 场景阶段环境变量
    @Environment(\.scenePhase) var scenePhase
    
    var body: some Scene {
        WindowGroup {
            ContentView()
        }
        .onChange(of: scenePhase) { phase in
            switch phase {
            case .background:
                // 应用在后台运行状态
                print("background")
            case .inactive:
                // 应用处于不活动状态
                print("inactive")
            case .active:
                // 应用处于活动状态
                print("active")
            @unknown default:
                // 应用处于默认状态
                print("default")
            }
        }
    }
}
//
//  RotationTextViewDemo.swift
//  SwiftUIDemo
//
//  Created by shiyanjun on 2023/2/9.
//

import SwiftUI

struct SealViewDemo: View {
    let textArr: [String] = "北京百度网讯科技有限公司".map({String($0)})
    @State var textSize: Double = 30.0
    @State var circleLineWidth: Double = 7.0
    @State var circleRadius: CGFloat = 233
    @State var textCircleRadius: CGFloat = 90
    @State var starSize: Double = 50.0
    @State var rotationDegress: Double = 20
    @State var firstTextPox: Double = 110
    
    init() {
        // 每个字的旋转角度 = 第一个字的旋转角度的两倍/文字个数
        self.rotationDegress = 110*2.0/Double(textArr.count)
    }
    
    var body: some View {
        ZStack {
            Color.white.edgesIgnoringSafeArea(.all)
            
            VStack {
                ZStack {
                    Circle()
                        .stroke(.red, lineWidth: circleLineWidth)
                        .frame(width: circleRadius)
                    
                    ForEach(0..<textArr.count) { index in
                        RoundTextView(
                            text: textArr[index],
                            foregroundColor: .red,
                            degrees: getDegress(firstTextPox: firstTextPox,
                                                rotationDegress: rotationDegress,
                                                index: index),
                            textSize: $textSize,
                            textCircleRadius: $textCircleRadius)
                    }
                    
                    Image(systemName: "star.fill")
                        .resizable()
                        .frame(width: starSize, height: starSize)
                        .foregroundColor(.red)
                }
                
                
                VStack(alignment: .leading) {
                    VStack(alignment: .leading) {
                        Text("文字大小:\(String(format: "%.2f", textSize))")
                            .font(.system(.headline))
                        Slider(value: $textSize, in: 20...50, step: 1)
                        
                        Text("圆环宽度:\(String(format: "%.2f", circleLineWidth))")
                            .font(.system(.headline))
                        Slider(value: $circleLineWidth, in: 1...30, step: 1)
                        
                        Text("圆环半径:\(String(format: "%.2f", circleRadius))")
                            .font(.system(.headline))
                        Slider(value: $circleRadius, in: 200...300, step: 1)
                        Text("文字圆环半径:\(String(format: "%.2f", textCircleRadius))")
                            .font(.system(.headline))
                        Slider(value: $textCircleRadius, in: 50...150, step: 1)
                    }
                    
                    VStack(alignment: .leading) {
                        Text("五角星大小:\(String(format: "%.2f", starSize))")
                            .font(.system(.headline))
                        Slider(value: $starSize, in: 20...80, step: 1)
                        
                        Text("文字间距:\(String(format: "%.2f", rotationDegress))")
                            .font(.system(.headline))
                        Slider(value: $rotationDegress, in: 15...60, step: 1)
                        
                        Text("首字位置:\(String(format: "%.2f", firstTextPox))")
                            .font(.system(.headline))
                        Slider(value: $firstTextPox, in: 90...150, step: 1)
                    }
                    
                }
            }
            .padding()
        }
    }
}

struct RotationTextViewDemo_Previews: PreviewProvider {
    static var previews: some View {
        SealViewDemo()
    }
}

// 获取当前文字的旋转角度
func getDegress(firstTextPox: Double, rotationDegress: Double, index: Int) -> Double {
    // 首字旋转角度 + 该字的索引 * 每个字的旋转角度
    return -firstTextPox + Double(index) * rotationDegress
}

struct RoundTextView: View {
    var text: String
    var foregroundColor: Color
    var degrees: Double
    @Binding var textSize: Double
    @Binding var textCircleRadius: CGFloat
    
    var body: some View {
        Text(text)
            .font(.system(size: textSize))
            .offset(y: -textCircleRadius)
            .foregroundColor(foregroundColor)
            .rotationEffect(Angle(degrees: degrees))
    }
}
//
//  MeasureSizeView.swift
//  SwiftUIDemo
//
//  Created by shiyanjun on 2023/2/8.
//

import SwiftUI

// 获取视图的尺寸
struct MeasureSizeView: View {
    // 视图的宽度
    @State private var viewWidth: Double = 0
    
    var body: some View {
        VStack {
            // 获取文本视图的宽度
            Text("Hello, World!")
                .measureSize { size in
                    viewWidth = size.width
                }
            // 展示文本视图的宽度
            Text(viewWidth, format: .number)
        }
    }
}

struct MeasureSizeView_Previews: PreviewProvider {
    static var previews: some View {
        MeasureSizeView()
    }
}

// 自定义视图尺寸修改器
struct MeasureSizeModifer: ViewModifier {
    let callback: (CGSize) -> Void
    
    func body(content: Content) -> some View {
        content
            .background {
                // 通过几何阅读器获取视图的尺寸
                GeometryReader { proxy in
                    Color.clear
                        .onAppear {
                            callback(proxy.size)
                        }
                }
            }
    }
}

extension View {
    // 自定义获取视图尺寸的修饰符
    func measureSize(_ callback: @escaping (CGSize) -> Void) -> some View {
        modifier(MeasureSizeModifer(callback: callback))
    }
}
//
//  SelectBackgroundColorView.swift
//  ApiBox
//
//  Created by shiyanjun on 2023/2/6.
//

import SwiftUI

// 视图模型类
class SelectColorViewModel: ObservableObject {
    // 记录当前用户选中的颜色,默认值白色
    @Published var selectColor: Color = .white
}

struct SelectBackgroundColorView: View {
    // 是否显示滑窗,默认不显示
    @State var showSheet: Bool = false
    // 注入视图模型实例
    @EnvironmentObject var vm: SelectColorViewModel
    
    var body: some View {
        ZStack {
            // 用户设置的背景色
            vm.selectColor
            VStack {
                Spacer()
                Button {
                    // 点击按钮展示滑窗让用户选择颜色
                    showSheet.toggle()
                } label: {
                    Text("设置背景色")
                        .frame(maxWidth: .infinity)
                        .frame(height: 45)
                        .foregroundColor(.white)
                        .background(.black)
                        .cornerRadius(10)
                }
                .sheet(isPresented: $showSheet) {
                    SheetView()
                }
                Spacer()
            }
            .padding()
        }
        .edgesIgnoringSafeArea(.all)
    }
}

// 底部滑窗
struct SheetView: View {
    // 注入视图模型实例
    @EnvironmentObject var vm: SelectColorViewModel
    // 用于关闭滑窗
    @Environment(\.presentationMode) private var presentationMode
    
    // 可供用户选择的颜色数组
    private let colors: [Color] = [.red, .green, .blue, .purple, .orange, .pink, .brown, .cyan, .teal]
    
    var body: some View {
        VStack {
            Text("请选择一种颜色")
                .font(.headline)
                .foregroundColor(.white)
                .frame(maxWidth: .infinity)
                .frame(height: 100)
            HStack {
                // 循环展示所有颜色供用户选择
                ForEach(colors, id: \.self) { color in
                    Button {
                        // 记住用户选中的颜色
                        vm.selectColor = color
                        // 关闭滑窗
                        presentationMode.wrappedValue.dismiss()
                    } label: {
                        Circle()
                            .frame(width: 30, height: 30)
                            .foregroundColor(color)
                            .overlay {
                                Circle()
                                // 用描边标识用户选中了该颜色
                                .stroke(.white, lineWidth: vm.selectColor == color ? 1 : 0)
                                // 用放大效果突出用户选的颜色
                                    .scaleEffect(vm.selectColor == color ? 1.2 : 1)
                            }
                    }
                }
            }
            Spacer()
        }
        .background(.black)
    }
}

struct SelectBackgroundColorView_Previews: PreviewProvider {
    static var previews: some View {
        SelectBackgroundColorView()
            .environmentObject(SelectColorViewModel())
    }
}
//
//  ButtonText.swift
//  SwiftUIDemo
//
//  Created by shiyanjun on 2023/2/1.
//

import SwiftUI

struct ButtonText: View {
    var body: some View {
        VStack {
            // 给文本设置圆角矩形背景
            Text("Hello!Hello!Hello!")
                .foregroundColor(.primary)
                .padding()
                .background(
                    Rectangle()
                        .fill(
                            // 线性渐变
                            LinearGradient(
                                gradient: Gradient(colors: [.red, .orange]),
                                startPoint: .leading,
                                endPoint: .trailing)
                        )
                        .cornerRadius(10)
                )
            // 给文本设置胶囊背景
            Text("Hello!Hello!Hello!")
                .foregroundColor(.primary)
                .padding()
                .background(
                    Capsule()
                        .fill(
                            // 角度渐变
                            AngularGradient(
                                gradient: Gradient(colors: [.red, .orange]),
                                center: .bottom
                            )
                        )
                        .cornerRadius(10)
                )
            // 给文本设置圆形背景
            Text("Hello!Hello!Hello!Hello!")
                .frame(width: 50, height: 50)
                .foregroundColor(.primary)
                .padding()
                .background(
                    Circle()
                        .fill(
                            // 角度渐变
                            AngularGradient(
                                gradient: Gradient(colors: [.red, .orange]),
                                center: .bottom,
                                angle: Angle(degrees: 0))
                        )
                        .cornerRadius(10)
                )
            
            
        }
    }
}

struct ButtonText_Previews: PreviewProvider {
    static var previews: some View {
        NavigationView {
            ButtonText()
        }
        .environment(\.colorScheme, .light)
    }
}
//
//  ButtonText.swift
//  SwiftUIDemo
//
//  Created by shiyanjun on 2023/2/1.
//

import SwiftUI

struct ButtonText: View {
    var body: some View {
        VStack{
            // 给文本设置圆角矩形背景
            Text("Hello!Hello!Hello!")
                .foregroundColor(.primary)
                .padding()
                .background(
                    Rectangle()
                        .foregroundColor(Color.purple)
                        .cornerRadius(10)
                )
            // 给文本设置胶囊背景
            Text("Hello!Hello!Hello!")
                .foregroundColor(.primary)
                .padding()
                .background(
                    Capsule()
                        .foregroundColor(Color.purple)
                        .cornerRadius(10)
                )
            // 给文本设置圆形背景
            Text("Hello!Hello!Hello!Hello!")
                .frame(width: 50, height: 50)
                .foregroundColor(.primary)
                .padding()
                .background(
                    Circle()
                        .foregroundColor(Color.purple)
                        .cornerRadius(10)
                )
        }
    }
}

struct ButtonText_Previews: PreviewProvider {
    static var previews: some View {
        NavigationView {
            ButtonText()
        }
        .environment(\.colorScheme, .light)
    }
}
import SwiftUI
import UIKit

extension Color {
    func toHex() -> String? {
        let uic = UIColor(self)
        guard let components = uic.cgColor.components, components.count >= 3 else {
            return nil
        }
        let r = Float(components[0])
        let g = Float(components[1])
        let b = Float(components[2])
        var a = Float(1.0)

        if components.count >= 4 {
            a = Float(components[3])
        }

        if a != Float(1.0) {
            return String(format: "%02lX%02lX%02lX%02lX", lroundf(r * 255), lroundf(g * 255), lroundf(b * 255), lroundf(a * 255))
        } else {
            return String(format: "%02lX%02lX%02lX", lroundf(r * 255), lroundf(g * 255), lroundf(b * 255))
        }
    }
}
star

Mon Oct 30 2023 05:38:49 GMT+0000 (Coordinated Universal Time)

#swiftui
star

Sun Aug 27 2023 12:36:24 GMT+0000 (Coordinated Universal Time)

#swiftui
star

Fri Aug 04 2023 13:13:30 GMT+0000 (Coordinated Universal Time)

#swift #swiftui
star

Fri Aug 04 2023 08:56:30 GMT+0000 (Coordinated Universal Time)

#swift #swiftui
star

Mon Mar 20 2023 13:30:08 GMT+0000 (Coordinated Universal Time) https://stackoverflow.com/questions/69279513/swiftui-scroll-to-horizontal-list-item

#swift #swiftui
star

Mon Feb 27 2023 00:59:39 GMT+0000 (Coordinated Universal Time)

#swift #swiftui
star

Mon Feb 27 2023 00:53:00 GMT+0000 (Coordinated Universal Time)

#swift #swiftui
star

Mon Feb 27 2023 00:50:31 GMT+0000 (Coordinated Universal Time)

#swift #swiftui
star

Mon Feb 27 2023 00:45:35 GMT+0000 (Coordinated Universal Time)

#swift #swiftui
star

Mon Feb 27 2023 00:37:29 GMT+0000 (Coordinated Universal Time)

#swift #swiftui
star

Mon Feb 27 2023 00:31:33 GMT+0000 (Coordinated Universal Time)

#swift #swiftui
star

Sun Feb 26 2023 23:59:50 GMT+0000 (Coordinated Universal Time) https://app-designer2.de

#swift #swiftui
star

Wed Feb 22 2023 05:12:56 GMT+0000 (Coordinated Universal Time)

#swift #swiftui
star

Sun Feb 12 2023 09:44:09 GMT+0000 (Coordinated Universal Time)

#swift #swiftui
star

Sun Feb 12 2023 08:32:54 GMT+0000 (Coordinated Universal Time)

#swift #swiftui
star

Sun Feb 12 2023 04:55:56 GMT+0000 (Coordinated Universal Time)

#swift #swiftui
star

Fri Feb 10 2023 05:54:54 GMT+0000 (Coordinated Universal Time)

#swift #swiftui
star

Wed Feb 08 2023 11:54:17 GMT+0000 (Coordinated Universal Time)

#swift #swiftui
star

Tue Feb 07 2023 12:09:14 GMT+0000 (Coordinated Universal Time)

#swift #swiftui
star

Wed Feb 01 2023 06:23:59 GMT+0000 (Coordinated Universal Time)

#swift #swiftui
star

Wed Feb 01 2023 05:47:27 GMT+0000 (Coordinated Universal Time)

#swift #swiftui
star

Wed Aug 10 2022 08:11:11 GMT+0000 (Coordinated Universal Time) https://blog.eidinger.info/from-hex-to-color-and-back-in-swiftui

#ios #swiftui

Save snippets that work with our extensions

Available in the Chrome Web Store Get Firefox Add-on Get VS Code extension