Is there a way to optimize a List in SwiftUI?
There is a problem with selection not working properly when the List has many rows.
If you scroll to multi-select and up, some rows in the middle are not selected.
I have an issue where selecting an unselected row deselects nearby rows.
Is there any way for selection to work reliably even for a List of many rows?
I would like to find a solution that is stable even when multiple lines are selected, like mail and note, which are the default apps in ios.
ps. I am using CoreData.
@State var selectedItem = Set<MyEntity>()
List(selection: $selectItem){
ForEach(items, id: \.self){ item in
ContactsRow(contactsData: item)
}
}
.environment(\.editMode, $editMode)
SwiftUI
RSS for tagProvide views, controls, and layout structures for declaring your app's user interface using SwiftUI.
Post
Replies
Boosts
Views
Activity
In the recent WWDC 2022, FreeForm app was introduced and in that app in the tool picker there was a Fill Tool.
I want to put that fill tool (or any similar filling tool) in my xcode app that I am building. But when I use pencilkit PKToolPicker, there is not Fill Tool.
So how to get this fill tool in my app.
Any leads would be helpful. Thanks.
Overview
I am bit confused regarding drag and drop on SwiftUI
I think there are 2 approaches but I am stuck with both approaches
WWDC22
When using the new draggable, dropDestination, Transferable API, only single items are draggable. Multiple items in a list are not draggable. I have filed a feedback FB10128110
WWDC21
I have faced a couple of issues for drag and drop introduced in WWDC21 (onDrag, onDrop, itemIdentifier), the Feedback ids are FB9854301, FB9854569, FB9855245, FB9855532, FB9855567, FB9855575. It contains sample projects, would really appreciate if someone could have a look it.
Note: All feedbacks include a sample project with detail steps and some even have screenshots and videos
Questions:
If my approach is wrong or if I am missing something?
Unfortunately I didn't manage to get a SwiftUI lab session (got cancelled), so please help me with these issues.
After updating to NavigationStack with nested navigation links (with navigation links in a navigation destination), I see a lot of warnings in Xcode 14 beta:
Update NavigationAuthority bound path tried to update multiple times per frame.
Update NavigationAuthority possible destinations tried to update multiple times per frame.
The app often freezes when navigated with a NavigationLink. Do others see these problems?
Hi
I really liked the video by Paul Lettieri, creating a replacement for HStack that gives equal width to each, so I wrote one for my app. But the app doesn't compile for me. It gives me "Trailing closure passed to parameter of type 'HorizontalAlignment' that does not accept a closure" against the top VStack, not the place where the equal lengths HStack replacement appears.
This is my version of his struct:
extension LayoutSubviews {
func maxSize() -> CGSize {
let subviewSizes = map { $0.sizeThatFits(.unspecified) }
return subviewSizes.reduce(CGSize.zero) { CGSize(width: Swift.max($0.width, $1.width), height: Swift.max($0.height, $1.height)) }
}// maxSize()
func spacing() -> [Double] {
return indices.map { index in
guard index < count - 1 else { return 0.0 }
return self[index].spacing.distance(to: self[index + 1].spacing, along: .horizontal)
}
}// spacing()
}// extension LayoutSubviews
struct EqualWidthHStack: Layout {
func sizeThatFits(proposal: ProposedViewSize, subviews: Subviews, cache: inout ()) -> CGSize {
let maxsize = subviews.maxSize()
let totalSpacing = subviews.spacing().reduce(0) { $0 + $1 }
return CGSize(width: maxsize.width * Double(subviews.count) + totalSpacing, height: maxsize.height)
}// sizeThatFits
func placeSubviews(in bounds: CGRect, proposal: ProposedViewSize, subviews: Subviews, cache: inout ()) {
let maxsize = subviews.maxSize()
let spacing = subviews.spacing()
let sizeProposal = ProposedViewSize(width: maxsize.width, height: maxsize.height)
var x = bounds.minX + maxsize.width / 2
for index in subviews.indices {
subviews[index].place(at: CGPoint(x: x, y: bounds.midX), anchor: .center, proposal: sizeProposal)
x += maxsize.width + spacing[index]
}
}// placeSubviews
}// EqualWidthHStack
I wrote this trivial View to test it:
struct ContentView: View {
var body: some View {
VStack {
HStack {
Button("Hi") { print("Hi!") }
Button("Hello") { print("Hello!") }
Button("Good evening") { print("Good evening!") }
}
EqualWidthHStack {
Button("Hi") { print("Hi!") }
Button("Hello") { print("Hello!") }
Button("Good evening") { print("Good evening!") }
}
Image(systemName: "globe")
.imageScale(.large)
.foregroundColor(.accentColor)
Text("Hello, world!")
}
}
}
I'm using Version 14.0 beta 2 (14A5229c) of Xcode. I was having a problem with the exact same message in another app with a much more complex main view.
I hope someone can tell me what to do or what is going on here.
Regards,
Mark
The Problem
In our brand new SwiftUI project (Multiplatform app for iPhone, iPad and Mac) we are using a ScrollView with both .horizontal and .vertical axes enabled. In the end it all looks like a spreadsheet.
Inside of ScrollView we are using LazyVStack with pinnedViews: [.sectionHeaders, .sectionFooters]. All Footer, Header and the content cells are wrapped into a LazyHStack each. The lazy stacks are needed due to performance reasones when rows and columns are growing.
And this exactly seems to be the problem. ScrollView produces a real layout mess when scrolling in both axes at the same time.
Tested Remedies
I tried several workarounds with no success.
We built our own lazy loading horizontal stack view which shows only the cells whose indexes are in the visible frame of the scrollview, and which sets dynamic calculated leading and trailing padding.
I tried the Introspect for SwiftUI packacke to set usesPredominantAxisScrolling for macOS and isDirectionalLockEnabled for iOS. None of this works as expected.
I also tried a workaround to manually lock one axis when the other one is scrolling. This works fine on iOS but it doesn't on macOS due to extreme poor performance (I think it's caused by the missing NSScrollViewDelegate and scroll events are being propagated via NotificationCenter).
Example Screen Recordings
To give you a better idea of what I mean, I have screenshots for both iOS and macOS.
Example Code
And this is the sample code used for the screenshots. So you can just create a new Multiplatform project and paste the code below in the ContentView.swift file. That's all.
import SwiftUI
let numberOfColums: Int = 150
let numberOfRows: Int = 350
struct ContentView: View {
var items: [[Item]] = {
var items: [[Item]] = [[]]
for rowIndex in 0..<numberOfRows {
var row: [Item] = []
for columnIndex in 0..<numberOfColums {
row.append(Item(column: columnIndex, row: rowIndex))
}
items.append(row)
}
return items
}()
var body: some View {
Group {
ScrollView([.horizontal, .vertical]) {
LazyVStack(alignment: .leading, spacing: 1, pinnedViews: [.sectionHeaders, .sectionFooters]) {
Section(header: Header()) {
ForEach(0..<items.count, id: \.self) { rowIndex in
let row = items[rowIndex]
LazyHStack(spacing: 1) {
ForEach(0..<row.count, id: \.self) { columnIndex in
Text("\(columnIndex):\(rowIndex)")
.frame(width: 100)
.padding()
.background(Color.gray.opacity(0.2))
}
}
}
}
}
}
.edgesIgnoringSafeArea([.top])
}
.padding(.top, 1)
}
}
struct Header: View {
var body: some View {
LazyHStack(spacing: 1) {
ForEach(0..<numberOfColums, id: \.self) { idx in
Text("Col \(idx)")
.frame(width: 100)
.padding()
.background(Color.gray)
}
Spacer()
}
}
}
struct Item: Hashable {
let id: String = UUID().uuidString
var column: Int
var row: Int
}
Can You Help?
Okay, long story short...
Does anybody knows a real working solution for this issue?
Is it a known SwiftUI ScrollView bug?
If there were a way to lock one scrolling direction while the other is scrolled, then I could deal with that. But at the moment, unfortunately, it is not usable for us.
So any solution is highly appreciated! Ideally an Apple engineer can help. 😃
NOTE: Unfortunately Apple does not allow URLs to anywhere. I also have two screen recordings for both iOS and macOS. So, if you would like to watch them, please contact me.
Hi there,
In a SwiftUI View, I have a
@State var test: Double?
and a TextField like that :
TextField("Test", value: $test, formatter: NumberFormatter())
the variable test is constantly nil and never being populated with the Double value of the entered text.
Is it a bug or a concept error of mine ??
Thanks!
Error Code: error build: Command CompileSwift failed with a nonzero exit code
My Code:
.backgroundTask(.appRefresh("checkValidity")) {
// scheduleAppRefresh()
// checkRecords()
}
Hi everybody,
given the following case using SwiftUI:
Button("testButton", action: noop)
.accessibilityRepresentation{representation: {
Slider(value: $sliderData.sliderValue)
})
.accessibilityIdentifier("testSlider")
I'm trying to control the slider using XCUITest via slider.adjust(toNormalizedSliderPosition: 0.2)
and receive the following error message:
Failed: Unable to get expected attributes for slider, found {
"XC_kAXXCAttributeMaxScrubberPosition" = {
X = 0;
Y = 0;
};
"XC_kAXXCAttributeMinScrubberPosition" = {
X = 0;
Y = 0;
};
Similarly, print (slider.normalizedSliderPosition) leads to the error message "Failed to determine current position of slider "0 %".
Is there a way to set and read the value of accessibilityRepresentation-Sliders with XCUITest?
Thanks!
I would like to include the bottom sheet from the iPhone "find my" and "maps" app in my app. During my research I came across the new modifier .presentationDetents for sheets. The only problem here is that you can no longer interact with the main screen when the sheet is active. In my app, however, I would like the sheet to be active all the time like in the iPhone apps mentioned and that you can still interact with the main screen like in the iPhone apps with the map. I would be very happy about help. Greetings
Is there a way to keep the menu open after tapping on a button or toggle inside it instead of automatically minimizing it on every tap?
This isn't a feature that's going to production ever, by the way.
My code is something like this:
struct MyView: View {
@State var toggleA = true
@State var toggleB = true
@State var toggleC = true
var body: some View {
NavigationView {
SwiftUI.Form {
Text("Hello")
}
.navigationTitle("My View")
.navigationBarTitleDisplayMode(.inline)
.navigationBarItems(trailing: {
Menu {
Toggle("A", isOn: $toggleA)
Toggle("B", isOn: $toggleB)
Toggle("C", isOn: $toggleC)
} label: {
Image(systemName: "ellipsis.circle")
}
}())
}
}
}
struct Preview: PreviewProvider {
static var previews: some View {
MyView()
}
}
I'm seeing a runtime warning in Xcode 14 Beta 5 that says "This method should not be called on the main thread as it may lead to UI unresponsiveness."
This is happening on the @main entry point of my app. See below:
The warning shown gives me no insight into what's actually going wrong. I think it may be due to some Core Location code that runs when the app first opens, but is there a way for me to get some more insight into what's causing this?
Or is this possibly an Xcode 14/iOS 16 bug, and this is not an issue to worry about? I'm not getting any warnings on Xcode 13/iOS 15.
I'd like to use .fullScreenCover() or .sheet() to present a View, depending on the current horizontalSizeClass.
If starting the following code in an iPhone (in portrait mode = .compact) or in an iPad (= .regular), the View is correctly displayed in a Sheet (iPhone) or in a FullScreenCover (iPad).
However when using SplitScreen mode on an iPad (and thus switching between .compact and .regular the View remains in the container it was originally displayed.
How can I correctly update this when switching between sizes on-the-fly?
struct ContentView: View {
@Environment(\.horizontalSizeClass) var horizontalSizeClass
var body: some View {
Group {
Text("hidden behind modal")
}
.modal(isPresented: .constant(true)) {
if horizontalSizeClass == .regular {
Rectangle()
.fill(Color.red)
.edgesIgnoringSafeArea(.all)
} else {
Rectangle()
.fill(Color.blue)
.edgesIgnoringSafeArea(.all)
}
}
}
}
struct Modal<ModalContent: View>: ViewModifier {
@Environment(\.horizontalSizeClass) var horizontalSizeClass
@Binding var isPresented: Bool
@ViewBuilder let modalContent: ModalContent
func body(content: Content) -> some View {
if horizontalSizeClass == .regular {
content
.fullScreenCover(isPresented: $isPresented) {
modalContent
.overlay {
Text("horizontalSizeClass: regular")
}
}
} else {
content
.sheet(isPresented: $isPresented) {
modalContent
.overlay {
Text("horizontalSizeClass: compact")
}
}
}
}
}
extension View {
public func modal<Content: View>(isPresented: Binding<Bool>, @ViewBuilder content: @escaping () -> Content) -> some View {
modifier(Modal(isPresented: isPresented, modalContent: content))
}
}
Hi everyone,
I am experiencing an issue with Toolbar and NavigationView on iOS 16.
Here are two small views to explain my bug:
struct ContentView: View {
var body: some View {
NavigationView {
VStack {
NavigationLink(destination: OtherView()) {
Text("Link to OtherView")
}
}
}
}
}
struct OtherView: View {
var body: some View {
ScrollView {
Text("ScrollView")
}
.toolbar {
ToolbarItem(placement: .bottomBar) {
Text("Great Toolbar")
}
}
}
}
The toolbar of OtherView is displayed but is empty:
If I replace NavigationView with NavigationStack, it works well:
However, I should use a NavigationView because my app is available on iOS 15.
Would you know how to solve this?
Thank you, regards
Hi,
In my apps, the recent iOS 16.0 beta 7 (20A5356a) broke the .timer DateStyle property of the Text view, in a SwiftUI widget.
In previous OS and beta, Text(Date(), style: .timer) was correctly displaying an increasing counter.
In iOS 6.0 beta 7, Text(Date(), style: .timer) does not update anymore, (and is offset to the left).
The other DateStyle (like .offset, .relative, ...) seems to update correctly.
Anyone noticed that (very specific) problem ?
Hi there!
After a few months off, I'm starting a new app.
I'm making a TabView like this:
import SwiftUI
struct ContentView: View {
@State private var tab: Tab = .adventures
var body: some View {
TabView(selection: $tab) {
Text("Explore")
.tag(Tab.explore)
.tabItem {
Label("Explore", systemImage: "airplane.circle")
}
Text("Profile")
.tag(Tab.profile)
.tabItem {
Label("Profile", systemImage: "person")
}
}
}
enum Tab {
case explore, profile
}
}
As you noticed, I want airplane.circle and person SF Symbols on the TabView but SwiftUI is showing airplane.circle.fill and person.fill in the preview canvas and also when I run the app in the simulator.
Why it is forcing me to show those icons?
Xcode version: 13.4.1
SF Symbols version: 3.3
iOS deployment target: 15.0
Thank you.
I'm having trouble getting the "Save to Files" option to work with ShareLink. Here's a simple example:
struct Item: Transferable {
public static var transferRepresentation: some TransferRepresentation {
FileRepresentation(exportedContentType: .jpeg) { item in
// Write a jpeg to disk
let url = URL.documentsDirectory.appending(path: "item.jpeg")
let jpegData = UIImage(named: "testImg")!.jpegData(compressionQuality: 1)!
try! jpegData.write(to: url)
return SentTransferredFile(url)
}
}
}
struct ContentView: View {
var body: some View {
ShareLink(item: Item(), preview: SharePreview("Test Item"))
}
}
The ShareSheet presents all of the usual options, but tapping "Save to Files" briefly presents an empty modal before immediately dismissing.
The following errors are logged to the console:
2022-09-12 14:19:57.481592-0700 ExportTest[3468:1374472] [NSExtension] Extension request contains input items but the extension point does not specify a set of allowed payload classes. The extension point's NSExtensionContext subclass must implement `+_allowedItemPayloadClasses`. This must return the set of allowed NSExtensionItem payload classes. In future, this request will fail with an error.
2022-09-12 14:19:58.047009-0700 ExportTest[3468:1374472] [ShareSheet] cancelled request - error: The operation couldn’t be completed. Invalid argument
Sharing finished with error: Error Domain=NSPOSIXErrorDomain Code=22 "Invalid argument" at SwiftUI/SharingActivityPickerBridge.swift:266
2022-09-12 14:19:58.584374-0700 ExportTest[3468:1379359] [AXRuntimeCommon] AX Lookup problem - errorCode:1100 error:Permission denied portName:'com.apple.iphone.axserver' PID:3472 (
0 AXRuntime 0x00000001ca77b024 _AXGetPortFromCache + 932
1 AXRuntime 0x00000001ca77d1d8 AXUIElementPerformFencedActionWithValue + 772
2 UIKit 0x00000002258b3284 3CB83860-AA42-3F9A-9B6E-2954BACE3DAC + 778884
3 libdispatch.dylib 0x0000000105078598 _dispatch_call_block_and_release + 32
4 libdispatch.dylib 0x000000010507a04c _dispatch_client_callout + 20
5 libdispatch.dylib 0x00000001050820fc _dispatch_lane_serial_drain + 988
6 libdispatch.dylib 0x0000000105082e24 _dispatch_lane_invoke + 420
7 libdispatch.dylib 0x000000010508fcac _dispatch_workloop_worker_thread + 740
8 libsystem_pthread.dylib 0x00000001ed9e8df8 _pthread_wqthread + 288
9 libsystem_pthread.dylib 0x00000001ed9e8b98 start_wqthread + 8
)
Additionally, this error is logged when the ShareSheet is first presented (before tapping Save to Files):
[ShareSheet] Couldn't load file URL for Collaboration Item Provider:<NSItemProvider: 0x282a1d650> {types = (
"public.jpeg"
)} : (null)
Has anybody had luck getting custom Transferable representations to work with ShareLink?
HI,
I have an issue displaying SwiftUI previews with Xcode 14.
My project has iOS and an watchOS Target. It also includes a lot of SPM, most of them only used by the PhoneApp. The project build successfully for both iOS and watchOS.
I can see that when building the watch target, only SPM that are included in this target are build for for watchOS
The issue is when I try to build a swiftUI preview of the watch target. In this case I can see on the build for Preview log that Xcode try to build ALL spm defined in the Xcode project, including the one that are not used by the watch Target,
As a lot if spm are for iOS only, and doesn't build for watchOS, the build for preview fails, and I'm unable to preview my swiftUI views on the AppeWatch.
Note that my project is working fine on Xcode 13.
This issue is easy to reproduce in any Xcode projects containing a iOS and watchOS target by adding a SPM that is only for iOS.
Any workaround to fix this issue ?
I recently updated my xcode and compiled my application developed in SwiftUI.
The SwiftUI List started to behave different.
List has Selection parameter for EditMode selection. However, now the list items are being selected and highlighted with grey highlighted color, even in a non-edit default mode.
Ideally, it should only select the list item in edit mode. It is how it worked before. But now when the list item is tapped in non-edit mode, it is getting selected.
Please, let me know how to make list with selection to highlight only in editmode.
import SwiftUI
struct ContentView: View {
struct Ocean: Identifiable, Hashable {
let name: String
let id = UUID()
}
private var oceans = [
Ocean(name: "Pacific"),
Ocean(name: "Atlantic")
]
@State private var multiSelection = Set<UUID>()
var body: some View {
NavigationView {
VStack {
List(oceans, selection: $multiSelection) { ocean in
Text(ocean.name)
}
.toolbar { EditButton() }
}
.padding()
.buttonStyle(PlainButtonStyle())
}
}
}
Hi everyone,
I am running into a navigation-related issue that appears to be new in iOS 16/SwiftUI 4. The code below illustrates the problem:
struct ContentView: View {
@State private var input: String = ""
var body: some View {
NavigationStack {
VStack {
Spacer()
NavigationLink("Navigate") {
Text("Nested View")
}
Spacer()
TextEditor(text: $input)
.border(.red)
.frame(height: 40)
}
.padding()
}
}
}
The initial view consists of a navigation link and a text editor at the bottom of the screen. I run the app on an iPhone (or the simulator) in iOS 16 and click on the text editor at the bottom of the screen. This invokes the virtual keyboard, which pushes up the text field. Next, I click on "Navigate" to navigate to the nested view. I navigate immediately back, which brings back the initial view without the keyboard. Unfortunately, the text field isn't pushed back to the bottom and is now located in the middle of the screen. (see attached image)
Did anyone experience similar issues? Is there a workaround I could use to force a re-layout of the initial view upon return from the navigation link?
Thanks,
Matthias