I have the following lines of code to show multiple instances of View (MyTextView)
import SwiftUI
struct ContentView: View {
@State var myTextViews = [MyTextView]()
var body: some View {
VStack {
Button {
} label: {
Text("Show me your current text strings")
}.padding(.vertical, 10.0)
VStack {
ForEach(0 ..< myTextViews.count, id: \.self) { _ in
MyTextView()
}
}
Button {
myTextViews.append(MyTextView())
} label: {
Text("Add me!")
}.padding(.vertical, 10.0)
}
}
}
struct MyTextView: View {
@State var text = ""
var body: some View {
ZStack {
TextField("Enter some text", text: $text)
}.padding(.horizontal, 50.0)
}
}
According to the screenshot, I have three instances, each of which contains TextField. After I tap the top button (Show me your current...), I want to show the result from each TextField. How can I do that? Thanks.
Selecting any option will automatically load the page
Post
Replies
Boosts
Views
Activity
I have three sets of Text and TextField. And I need to filter each TextField entry. I have gotten a function to filter the TextField entry from this website (https://zenn.dev/yorifuji/articles/swiftui-textfield-filter). Finally, I have the following lines of code.
import SwiftUI
struct ContentView: View {
@State var username = ""
@State var password = ""
@State var tenantID = ""
var body: some View {
VStack {
makeForm(label: "Username: ", placeHolder: "123456", text: $username)
makeForm(label: "Password: ", placeHolder: "abcdefg", text: $password)
makeForm(label: "Shop ID: ", placeHolder: "123456", text: $tenantID)
}.padding(.horizontal, 40.0)
}
@ViewBuilder
private func makeForm(label: String, placeHolder: String, text: Binding<String>) -> some View {
HStack {
let newText = Binding<String>(
get: { text.wrappedValue },
set: { filter(value: $0) }
)
Text(label)
TextField(placeHolder, text: newText)
}
}
func filter(value: String) -> String {
let validCodes = "0123456789abcdefghijklmnopqrstuvwxyzABCDEFGHIJKLMNOPQRSTUVWXYZ"
let sets = CharacterSet(charactersIn: validCodes)
return String(value.unicodeScalars.filter(sets.contains).map(Character.init))
}
}
Well, I don't know how to use the Binding with get and set, which I believe is what I need. Yet, I get a warning at the following line.
set: { filter(value: $0) }
What I need to do is set the filtered value to each TextField. What am I doing wrong? Thanks.
I'm a bit confused about the minimum macOS version required to run Xcode 14. I don't know what the minimum macOS version to run it. In the meantime, it seems that macOS 13 beta requires a Mac computer with the Apple silicon. As for Xcode 14 beta, its details say "Xcode 14 beta includes everything you need to create amazing apps for all Apple platforms. It includes SDKs for iOS 16, iPadOS 16, tvOS 16, watchOS 9, and macOS 13." What does that mean as far as macOS 13 is concerned? Do we need a Mac with the Apple silicon to run Xcode 14? Thanks.
I have a simple case as follows.
class Monster: ObservableObject {
static let shared = Monster()
@Published var selectionChanged = false
}
struct ContentView: View {
@ObservedObject var monster = Monster.shared
@State private var isOn = false
var body: some View {
VStack {
Button {
monster.selectionChanged.toggle()
} label: {
Text("Tap me")
}
.padding(.vertical, 60.0)
SecondView()
}
}
}
struct SecondView: View {
@StateObject var monster = Monster.shared
var body: some View {
VStack {
Text("Hello")
}.onChange(of: monster.selectionChanged) { _ in
print("GGGG")
}
}
}
So SecondView receives a call from Monster with through onChange.. Is there a simpler approach where SecondView receives a call without it? Thanks.
In UIKit, it's just the matter of setting table view's allowsSelection to false if you don't want to allow selection. If each row has a button, it can still be clicked on. Can we do that in SwiftUI?
I have the following simple SwiftUI project.
import SwiftUI
struct ContentView: View {
@State private var fruits = ["Apple", "Banana", "Mango", "Watermelon", "Pineapple", "Strawberry", "Orange"]
@State private var isEditable = true
var body: some View {
List {
ForEach(fruits, id: \.self) { fruit in
HStack {
Text(fruit)
.onDrag {
return NSItemProvider()
}
Spacer()
Button {
print("Hello")
} label: {
Text("Tap me")
}
}
}
.onMove(perform: move)
}
.onTapGesture(perform: {
return
})
.listStyle(.plain)
}
func move(from source: IndexSet, to destination: Int) {
fruits.move(fromOffsets: source, toOffset: destination)
withAnimation {
isEditable = false
}
}
}
The tap gesture prevents row interaction. So I won't even be able to tap the button. How can I disable row selection while allowing interaction inside the list row?
List {
}
.onAppear {
UITableView.appearance().allowsSelection = false
UITableViewCell.appearance().selectionStyle = .none
}
The lines of code above don't work, either.
Thanks.
I have an array of dictionaries. And I need to sort this array in an ascending order.
someArray = someArray.sorted { lValue, rValue in lValue.categoryName < rValue.categoryName }
So one of the dictionaries is categoryName. Now, I have a case where the category name of an array element is something specific, say 'price,' then that element must be listed at the end as an exception to the rule above. Is that possible? Thanks.
I have downloaded the UniversalMac_13.0_22A379_Restore.ipsw file. How do we use this file to install the new OS? Thanks.
I have revisited AVCaptureSession in UIKit to capture a snapshot with the FaceTime camera. And my sample app will crash when AVCaptureSession starts running. Does anyone know how to fix it? The console says the following purple warning.
-[AVCaptureSession startRunning] should be called from background thread. Calling it on the main thread can lead to UI unresponsiveness
import UIKit
import AVFoundation
class CaptureViewController: UIViewController, AVCapturePhotoCaptureDelegate {
var captureSession: AVCaptureSession!
var cameraDevices: AVCaptureDevice!
var imagePhotoOutput: AVCapturePhotoOutput!
enum CameraCase {
case front
case back
}
// MARK: - IBAction
@IBAction func selectTapped(_ sender: UIButton) {
snapPicture()
}
// MARK: - Life cycle
override func viewDidLoad() {
super.viewDidLoad()
}
override func viewWillAppear(_ animated: Bool) {
super.viewWillAppear(animated)
prepareCamera(cameraCase: .front)
}
// MARK: - Camera
func prepareCamera(cameraCase: CameraCase) {
/* removing existing layers */
if let sublayers = self.view.layer.sublayers {
for sublayer in sublayers {
if sublayer.isKind(of: AVCaptureVideoPreviewLayer.self) {
sublayer.removeFromSuperlayer()
}
}
}
/* creating a capture session */
captureSession = AVCaptureSession()
if cameraCase == .front {
guard let device = AVCaptureDevice.DiscoverySession(deviceTypes: [.builtInWideAngleCamera], mediaType: AVMediaType.video, position: .back).devices.first else { return }
let videoInput = try? AVCaptureDeviceInput(device: device)
if captureSession.canAddInput(videoInput!) {
captureSession.addInput(videoInput!)
imagePhotoOutput = AVCapturePhotoOutput() // setting output destination
captureSession.addOutput(imagePhotoOutput) // adding photo output to session
}
} else {
guard let device = AVCaptureDevice.DiscoverySession(deviceTypes: [.builtInWideAngleCamera], mediaType: AVMediaType.video, position: .front).devices.first else { return }
let videoInput = try? AVCaptureDeviceInput(device: device)
if captureSession.canAddInput(videoInput!) {
captureSession.addInput(videoInput!)
imagePhotoOutput = AVCapturePhotoOutput() // setting output destination
captureSession.addOutput(imagePhotoOutput) // adding photo output to session
}
}
/* creating a capture layer */
let captureVideoLayer: AVCaptureVideoPreviewLayer = AVCaptureVideoPreviewLayer.init(session: captureSession)
captureVideoLayer.frame = CGRect(x: 0, y: 0, width: view.frame.size.width, height: view.frame.size.height)
captureVideoLayer.videoGravity = AVLayerVideoGravity.resizeAspect
/* adding video capture layer to the view layer */
self.view.layer.addSublayer(captureVideoLayer)
/* starting capture session */
captureSession.startRunning() //<<<<<<<<<<<<<<<<<<<<<<<<<<< The console shows a purple warning here.
}
}
How do you save a picture from the capture-screen with AVCaptureSession to Photo? My capture-screen looks like a square as show below.
Yet I've ended up with an 1080 × 1920 image as shown below. I have an iPhone XR, and I always end up with 1080 × 1920 images. How come the aspect ration never changes?
My code has the following lines
import UIKit
import AVFoundation
class CaptureViewController: UIViewController, AVCapturePhotoCaptureDelegate {
var captureSession: AVCaptureSession!
var cameraDevices: AVCaptureDevice!
var imagePhotoOutput: AVCapturePhotoOutput!
enum CameraCase {
case front
case back
}
// MARK: - IBAction
@IBAction func takePictureTapped(_ sender: UIButton) {
snapPicture()
}
// MARK: - Life cycle
override func viewDidLoad() {
super.viewDidLoad()
}
override func viewWillAppear(_ animated: Bool) {
super.viewWillAppear(animated)
prepareCamera(cameraCase: .back)
}
// MARK: - Camera
func prepareCamera(cameraCase: CameraCase) {
/* removing existing layers */
if let sublayers = self.view.layer.sublayers {
for sublayer in sublayers {
if sublayer.isKind(of: AVCaptureVideoPreviewLayer.self) {
sublayer.removeFromSuperlayer()
}
}
}
/* creating a capture session */
captureSession = AVCaptureSession()
guard let device = AVCaptureDevice.DiscoverySession(deviceTypes: [.builtInWideAngleCamera], mediaType: AVMediaType.video, position: cameraCase == .front ? .front : .back).devices.first else { return }
let videoInput = try? AVCaptureDeviceInput(device: device)
if captureSession.canAddInput(videoInput!) {
captureSession.addInput(videoInput!)
imagePhotoOutput = AVCapturePhotoOutput() // setting output destination
captureSession.addOutput(imagePhotoOutput) // adding photo output to session
}
/* creating a capture layer */
let previewLayer: AVCaptureVideoPreviewLayer = AVCaptureVideoPreviewLayer.init(session: captureSession)
previewLayer.frame = CGRect(x: 0.0, y: 200.0, width: view.frame.width, height: view.frame.height - 500.0)
previewLayer.videoGravity = AVLayerVideoGravity.resize
/* adding video capture layer to the view layer */
self.view.layer.addSublayer(previewLayer)
/* starting capture session */
DispatchQueue.global(qos: .background).async {
self.captureSession.startRunning()
}
}
func snapPicture() {
let settingsForMonitoring = AVCapturePhotoSettings()
imagePhotoOutput?.capturePhoto(with: settingsForMonitoring, delegate: self as AVCapturePhotoCaptureDelegate)
}
// MARK: - Delegate methods
func photoOutput(_ output: AVCapturePhotoOutput, didFinishProcessingPhoto photo: AVCapturePhoto, error: Error?) {
if error == nil {
guard let imageData = photo.fileDataRepresentation() else {
print("Error while generating image from photo capture data.");
return
}
if let image = UIImage(data: imageData) {
saveImage(image)
}
}
}
// MARK: - Saving an image to Photo Library
func saveImage(_ image: UIImage) {
UIImageWriteToSavedPhotosAlbum(image, self, #selector(image(_:didFinishSavingWithError: contextInfo:)), nil)
}
@objc func image(_ image: UIImage, didFinishSavingWithError error: Error?, contextInfo: UnsafeRawPointer) {
if let error = error {
print("An error has occurred: \(error.localizedDescription)")
} else {
print("Saved...")
}
}
}
Thanks.
I'm using the custom URL scheme to open my app through Safari. When the app appears, the status bar shows 'Safari' at the top-left corner. Is there a way of stopping the app from showing Safari's name? I don't want the user to tap the name and go back to Safari. There is nothing special in my SceneDelegate. So I wonder if it's probably the matter of settings in the Settings app? Thanks.
I have a simple app that implements a custom URL scheme. When I enter the scheme for my app in Safari, the app will launch itself. So far, so good... Now, when I initiate the app switcher, I have my app and the web browser (Safari). Is there a way of not showing them in the app switcher? Or can I at least stop the web browser from appearing in the app switcher? Is it even possible for me to terminate Safari programmatically from my app, provided that that is not going to violate the app store guidelines? Thanks.
Drawing a pie isn't difficult if I do it with Path.
import SwiftUI
struct ContentView8: View {
var body: some View {
PieSlice(start: .degrees(-90), end: .degrees(120))
.fill(.pink)
}
}
struct PieSlice: Shape {
let start: Angle
let end: Angle
func path(in rect: CGRect) -> Path {
var path = Path()
let center = CGPoint(x: rect.midX, y: rect.midY)
path.move(to: center)
path.addArc(center: center, radius: rect.midX, startAngle: start, endAngle: end, clockwise: false)
return path
}
}
Actually, I want to animate this pie such that it will gradually deploy starting at -90 degrees. In the code above, I suppose I cannot animate the pie because the PieSlice guy isn't a View. Or can I? If I can't, is there an alternative way of drawing a pie so that I can animate it?
Thanks a million.
Señor Tomato Source
Hostage Negotiator at
Tomato Source Association of North America
I use the ForEach enumeration to list a View horizontally. And I get the following picture.
So far, so good... If I select the 5th object or 6th one, something odd (< More) appears. I don't know where it comes from. I have never seen it before. How does it happen? I wonder how I can remove it? I have searched the net for a clue to no avail. I don't even know how to describe it.
The following is my code.
import SwiftUI
struct ContentView: View {
@State var selectedTab = 0
@State var addTapped = false
@State var refresh = false
@State var people = [
Person(name: "Alice", systemImage: "person.circle.fill"),
Person(name: "Jane", systemImage: "person.circle.fill"),
Person(name: "Dave", systemImage: "person.circle.fill"),
Person(name: "Susan", systemImage: "person.circle.fill"),
Person(name: "Robert", systemImage: "person.circle.fill"),
Person(name: "Daniel", systemImage: "person.circle.fill")
]
var body: some View {
VStack(alignment: .leading, spacing: 0) {
ScrollView(.horizontal) {
HStack(spacing: 20) {
ForEach(0..<people.count, id: \.self) { num in
VStack {
let person = people[num]
Image(systemName: person.systemImage)
.resizable()
.aspectRatio(contentMode: .fit)
.frame(height: 32)
Text(person.name)
.fixedSize()
}
.foregroundColor(selectedTab == num ? Color.blue : Color.gray)
.onTapGesture {
self.selectedTab = num
}
}
}
}.padding(.horizontal, 10)
Spacer()
.frame(height: 2)
Rectangle().fill(.gray)
.frame(height: 1)
TabView(selection: $selectedTab) {
ForEach(0..<people.count, id: \.self) { num in
let person = people[num]
Text(person.name)
.tag(person.id)
}
}
}
}
}
struct Person: Identifiable {
let id = UUID()
let name: String
let systemImage: String
}
Muchos thankos.
I'm trying to export a document file. It contains a codable struct named NoteGroup.
struct NoteGroup: Codable {
let id: UUID
let name: String
let createAt: Date
let children: [NoteChild]
init(id: UUID = .init(), name: String = "", createAt: Date = .init(), children: [NoteChild]) {
self.id = id
self.name = name
self.createAt = createAt
self.children = children
}
}
, which contains another object named NoteChild. I have a FileDocument struct as follows.
import SwiftUI
import UniformTypeIdentifiers
struct Document: FileDocument {
var document: NoteGroup
static var readableContentTypes = [UTType.frogType]
init(document: NoteGroup = NoteGroup(children: [NoteChild(id: UUID(), name: "", createAt: Date())])) {
self.document = document
}
init(configuration: ReadConfiguration) throws {
self.init()
}
func fileWrapper(configuration: WriteConfiguration) throws -> FileWrapper {
do {
let data = try getDocumentData()
let jsonFileWrapper = FileWrapper(regularFileWithContents: data)
let filename = "Note.frog"
jsonFileWrapper.filename = filename
let fileWrapper = FileWrapper(directoryWithFileWrappers: [filename: jsonFileWrapper])
return fileWrapper
} catch {
throw error
}
}
private func getDocumentData() throws -> Data {
let encoder = JSONEncoder()
do {
let data = try encoder.encode(document)
return data
} catch {
throw error
}
}
}
extension UTType {
public static let frogType = UTType(exportedAs: "com.example.frog")
}
And I export a file like the following.
import SwiftUI
import UniformTypeIdentifiers
struct ContentView: View {
@State private var showingExporter = false
@State var doc = Document()
var body: some View {
VStack {
Button("Tap to export") {
showingExporter.toggle()
}
.fileExporter(
isPresented: $showingExporter,
document: doc,
contentType: .frogType
) { result in
switch result {
case .success(let file):
print(file)
case .failure(let error):
print(error)
}
}
}.onAppear {
doc = Document(document: NoteGroup(id: UUID(), name: "Kyle", createAt: Date(), children: [NoteChild(id: UUID(), name: "Nancy", createAt: Date())]))
}
}
}
Well, I have read this topic. And I've watched this video about Uniform Type Identifiers. Thanks to the video, I am able to export a file. Yet, I end up with a folder (Frog.frog), not a packaged file. There is a JSON file in it, though. What am I doing wrong? It's for iOS. La vida no es facil. Muchos thankos.
I have created a simple case to make my point as follows.
import SwiftUI
struct ContentView: View {
var body: some View {
ZStack {
Color.yellow.ignoresSafeArea()
VStack(alignment: .leading) {
ForEach(Fruit.allCases, id: \.self) { fruit in
DisclosureGroup(fruit.rawValue) {
VStack {
Text("1")
Text("2")
Text("3")
}
}
.contextMenu {
Button("Hello", action: {
})
}
}
}.padding(.horizontal, 20)
}
}
}
enum Fruit: String, CaseIterable {
case apple = "Apple"
case grape = "Grape"
case lemon = "Lemon"
case orange = "Orange"
case peach = "Peach"
case pineapple = "Pineapple"
case watermelon = "Watermelon"
}
struct ContentView_Previews: PreviewProvider {
static var previews: some View {
ContentView()
}
}
What I want to do is show the contextual menu when the user long-presses a fruit name, which works. Yet, if I long-press a child inside the disclosure view, I also get the contextual menu, which is unintentional. Is there a simple way by which I can stop the contextual menu to appear if long-press a child inside the disclosure view?
Muchos thankos