Paging Steve Breen! 😄
I've seen this question asked a zillion times but I've never seen an answer.
Is it possible to configure compositional layout to give you a grid of N columns (say 2 or 3) where each item in each row/group self-size their height, but the heights of those items are then set to be the height of the tallest item in their row.
This is easy to do if you ignore the self-sizing requirement (just use a fixed or absolute item height), but on the surface this doesn't even appear to be possible if you require self-sizing.
What I've Tried
Configuring a layout where the items are set to a fractional height of 1.0 and their group is set to an estimated height (ex: 100). I was hoping compositional layout would interpret this as, "Please self-size the height of the group and make each item 100% of that height." Unfortunately, compositional layout just uses the estimate you provide for the height as the actual height and no self-sizing occurs at all. Sad panda. 🐼
Use visibleItemsInvalidationHandler to attempt to identify which items share a row and reset their heights to be the height of the tallest item in that row. Sadly, the handler doesn't really have access to the data it needs to do this, nor is it allowed to change frames, nor is it called on the first layout pass, nor does it appear to be supported at all for layouts containing estimated items. In fact, if you try to use it with layouts that support self-sizing, you'll get this error message:
[UICompositionalLayout] note: the section invalidation handler cannot currently mutate visible items for layouts containing estimated items. Please file an enhancement request on UICollectionView.
Wishing upon a star. Oh, and I also filed a radar asking: FB11776888
Here's a visual aid:
I have a little test program as well, but unfortunately I can't upload it here. Happy to share if it would be helpful. Here are a couple snippets:
#1
// This doesn't work
private func makeLayout1() -> UICollectionViewCompositionalLayout {
// Item
let itemSize = NSCollectionLayoutSize(widthDimension: .fractionalWidth(0.5), heightDimension: .fractionalHeight(1))
let item = NSCollectionLayoutItem(layoutSize: itemSize)
// Group
let groupSize = NSCollectionLayoutSize(widthDimension: .fractionalWidth(1), heightDimension: .estimated(100))
let group = NSCollectionLayoutGroup.horizontal(layoutSize: groupSize, repeatingSubitem: item, count: 2)
group.interItemSpacing = .fixed(10)
// Section
let section = NSCollectionLayoutSection(group: group)
return UICollectionViewCompositionalLayout(section: section)
}
#2
// This self-sizes the heights of the items, but allows the items in each row to be different heights rather than providing any way to constrain them to the height of the tallest self-sized item in each row
private func makeLayout2() -> UICollectionViewCompositionalLayout {
// Item
let itemSize = NSCollectionLayoutSize(widthDimension: .fractionalWidth(0.5), heightDimension: .estimated(100))
let item = NSCollectionLayoutItem(layoutSize: itemSize)
// Group
let groupSize = NSCollectionLayoutSize(widthDimension: .fractionalWidth(1), heightDimension: .estimated(100))
let group = NSCollectionLayoutGroup.horizontal(layoutSize: groupSize, repeatingSubitem: item, count: 2)
group.interItemSpacing = .fixed(10)
// Section
let section = NSCollectionLayoutSection(group: group)
return UICollectionViewCompositionalLayout(section: section)
}
Options?
My guess is that compositional layout simply doesn't support layouts that require a "partial second pass" per group, where the frames of the items can be updated based on information collected during self-sizing the other items in the group (to, for example, force them all to a common height, or align them top/bottom/centered within their group).
If that's the case (not supported), I would love a suggestion for where I might override the layout to provide this capability.
Thank you! ❤️
Explore the various UI frameworks available for building app interfaces. Discuss the use cases for different frameworks, share best practices, and get help with specific framework-related questions.
Post
Replies
Boosts
Views
Activity
Before iOS 16.1 my app was woking good, if the user set the app language to other language than his device language, my app, widget + extensions all use this language...
After iOS 16.1 if user set the app language to other language than his device language, my app works with this language but the widget + extensions works with the device language, not my app language...
For Example:
@Environment(\.locale.languageCode) private var userLocal
before iOS 16.1 userLocal would be the app local, after iOS 16.1 it return the device local
Any idea why Apple did that? is this a bug?
How to set the widget language to match my app language now? even set .environment(\.locale, dose not work when use Strings(table: because it's still get the bundle that match device language.
I am new to Swift and iOS development. I am trying to wrap a web app where the orientation is dependent on the URL. I have the code working with Stack Overflow as an example where "https://stackoverflow.com" displays in portrait and all other pages change to landscape after being loaded. I have a URL observer that triggers when the URL changes and calls requestGeometryUpdate. I'm running into the following problem:
When changing the orientation with requestGeometryUpdate, the orientation changes, but if the device is physically rotated after the change, the orientation changes again. I would like to make the orientation change locked and permanent until a new page is loaded.
Any help would be much appreciated. My code is below:
import SwiftUI
import WebKit
struct TestView: View {
private let urlString: String = "https://stackoverflow.com/"
var body: some View {
TestWebView(url: URL(string: urlString)!)
.background(Color.black)
.scrollIndicators(.hidden)
.ignoresSafeArea([.all])//stretchs webview over notch on iphone
.defersSystemGestures(on:.bottom)//deprioritizes multitasking indicator
.statusBar(hidden: true)//hides time and battery
}
}
class TestController: UIViewController {
var webview: WKWebView!
var webViewURLObserver: NSKeyValueObservation?
override func viewDidLoad() {
super.viewDidLoad()
let winScene = UIApplication.shared.connectedScenes.first
let windowScene = winScene as! UIWindowScene
webview = WKWebView(frame: self.view.frame)
webview.autoresizingMask = [.flexibleWidth,.flexibleHeight]//makes webview fit screen in portrait and landscape
self.view.addSubview(self.webview)
webViewURLObserver = self.webview.observe(\.url, options: .new) { webview, change in
let url=change.newValue!!;//! converts from optional to string
print(url)
let arr = url.absoluteString.split(separator: "stackoverflow.com").map(String.init)
var portrait=false
if(arr.count>1){
let path = arr[1];
if path=="/"{
portrait=true
}
}
if portrait==true {
windowScene.requestGeometryUpdate(.iOS(interfaceOrientations: .portrait)) { error in print(error)}
}
else{
windowScene.requestGeometryUpdate(.iOS(interfaceOrientations: .landscape)) { error in print(error)}
}
self.setNeedsUpdateOfSupportedInterfaceOrientations()
}
}
}
// WebView Struct
struct TestWebView: UIViewControllerRepresentable {
let url: URL
func makeUIViewController(context: Context) -> TestController {
let webviewController = TestController()
return webviewController
}
func updateUIViewController(_ webviewController: TestController, context: Context) {
let request = URLRequest(url: url)
webviewController.webview.scrollView.contentInsetAdjustmentBehavior = .never
webviewController.webview.load(request)
}
}
struct TestView_Previews: PreviewProvider {
static var previews: some View {
TestView()
}
}
Any one getting any issues with NavigaitonLink to seemingly innocuous views freezing when tapped on? 1 CPU at 100% memory steadily increasing until app gets killed by the system. Will freeze if any NavigationLink on the view is tapped if certain views are linked to using NavigaitonLink.
I note some people have been getting similar freezes if they use @AppStorage, but I'm not using @AppStorage. I do use CoreData tho. tho I have some views that use core data that don't freeze.
https://developer.apple.com/forums/thread/708592?page=1#736374022
has anyone experienced similar issues? or know the cause. it doesn't seem to be any of my code because if I pause the debugger it stops on system code.
Hi!
I have two problems with FileImport and FileExporter
Every time the file modal has been closed I get in the console this error/warning
[DocumentManager] The view service did terminate with error: Error Domain=_UIViewServiceErrorDomain Code=1 "(null)" UserInfo={Terminated=disconnect method}
The modal for FileExporter shows the label "Move", why? I'm creating a new file, not moving an existing one, since there is already the modifier FileMover. Is it correct? Can't be confusing for a user to see the label "Move"? Am I using it in the wrong way?
Can please someone help me with these two problems?
In a SwiftUI project I try to display a background image with ignoring safe area insets (to make it go edge to edge). However, the background scales incorrectly and doesn't respect its aspect ratio.
Here is a small code example of the view structure that I'm using:
struct ContentView: View {
var body: some View {
ZStack {
Text("Lorem ipsum dolor sit amet, consectetur adipiscing elit, sed do eiusmod tempor incididunt ut labore et dolore magna aliqua.").padding()
}.frame(maxHeight: .infinity).background(Image("dots").resizable().ignoresSafeArea().scaledToFill())
}
}
And an example image for testing (when using this image you can clearly see the circles become more like ovals in the SwiftUI app):
Screenshot:
The standard Command-A keyboard shortcut in a UITextView is broken in Mac Catalyst 16/ Ventura with either TextKit 2 or TextKit 1 for long texts.
In iOS 16 the selection is instant but on MacOS with Catalyst a beachball is displayed for more than 50 seconds and the app consumes gigabytes of memory.
Earlier versions of Mac Catalyst work fine.
To duplicate this just create a small storyBoard app with an editable UITextView and paste a long document around 1Mb then use the standard Select All Command either from the keyboard or the app menu.
l I use Tale of Two Cities which is about 800k to test in my app.
Is there any workaround for this?
I made a test with a new XIB-based project using this code
func applicationDidFinishLaunching(_ aNotification: Notification) {
guard let content = window.contentView else {
print("Error: cannot access windows contentview!")
return
}
let tv = NSTextView(frame: NSMakeRect(100, 300, 200, 40))
tv.string = "Text subview"
tv.font = NSFont.systemFont(ofSize: 30.0)
content.addSubview(tv)
let chartView = NSHostingView(rootView: myChart())
chartView.setFrameSize(content.frame.size)
content.addSubview(chartView)
content.printView(self)
}
"myChart" is s sample view using Charts.
The window does show the text and the chart but the print shows the text only.
How can I get the SwiftUI-View printed?
My goal is a PDF output of a SwiftUI view.
There are already several older threads with similar questions but no solution, yet.
I've seen several posts regarding NavigationStack in a NavigationSplitView. All had specific issues and some were marked as resolved. I couldn't get any of the suggested solutions working on macOS so I'll present some stripped down examples, all part of FB11842563:
1. Sidebar Selection
struct SidebarSelection: View {
@State var selection: Int?
@State var path: [Int] = []
var body: some View {
NavigationSplitView {
List(1...20, id: \.self, selection: $selection) { number in
Text("I like \(number)")
}
} detail: {
NavigationStack(path: $path) {
VStack {
Image(systemName: "x.squareroot")
.imageScale(.large)
.foregroundColor(.accentColor)
Text("This is the NavigationStack root")
}
.padding()
.navigationDestination(for: Int.self) { number in
Text("You chose \(number)")
}
}
}
.onChange(of: selection) { newValue in
print("You clicked \(newValue)")
if let newValue {
path.append(newValue)
}
}
.onChange(of: path) { newValue in
print("Path changed to \(path)")
}
}
}
If we run this and click:
„I like 5“
„I like 6“
„I like 7“
We would expect the detail view to show:
„You chose 5“
„You chose 6“
„You chose 7“
And the console to show:
You clicked Optional(5)
Path changed to [5]
You clicked Optional(6)
Path changed to [5, 6]
You clicked Optional(7)
Path changed to [5, 6, 7]
What we actually see in the detail view is:
„You chose 5“
„This is the NavigationStack root“
„You chose 7“
And the console shows:
Update NavigationRequestObserver tried to update multiple times per frame.
You clicked Optional(5)
Path changed to [5]
You clicked Optional(6)
Path changed to []
You clicked Optional(7)
Path changed to [7]
2. Sidebar and Stack Selection
Now we copy the list to the navigationDestination:
struct SidebarAndStackSelection: View {
@State var selection: Int?
@State var path: [Int] = []
var body: some View {
NavigationSplitView {
List(1...20, id: \.self, selection: $selection) { number in
Text("I like \(number)")
}
} detail: {
NavigationStack(path: $path) {
VStack {
Image(systemName: "x.squareroot")
.imageScale(.large)
.foregroundColor(.accentColor)
Text("This is the NavigationStack root")
}
.padding()
.navigationDestination(for: Int.self) { number in
VStack {
Text("You chose \(number)")
List(1...20, id: \.self, selection: $selection) { number in
Text("I like \(number)")
}
}
}
}
}
.onChange(of: selection) { newValue in
print("You clicked \(newValue)")
if let newValue {
path.append(newValue)
}
}
.onChange(of: path) { newValue in
print("Path changed to \(path)")
}
}
}
We repeat our test from above, clicking either on the sidebar or in the detail view and we expect the same outcome. This time the detail view shows the expected screen and the path is not completely wiped out but it is also not appended:
Update NavigationRequestObserver tried to update multiple times per frame.
You clicked Optional(5)
Path changed to [5]
You clicked Optional(6)
Path changed to [6]
You clicked Optional(7)
Path changed to [7]
3. Sidebar and Stack Selection, initialized
Same as before, but now we initialize the view with a non-empty path:
SidebarAndStackSelection(path: [1])
The app freezes on launch, CPU is at 100 percent and the console shows only:
Update NavigationRequestObserver tried to update multiple times per frame.
Update NavigationRequestObserver tried to update multiple times per frame.
The SwiftUI instruments seem to show heavy activity of the Stack and the SplitView:
4. Selection only in Stack
Once we remove the selection from the sidebar everything works as expected (adding the NavigationStack to the root view to be able to click on a number):
struct SidebarWithoutSelectionButStack: View {
@State var selection: Int?
@State var path: [Int] = []
var body: some View {
NavigationSplitView {
List(1...20, id: \.self) { number in
Text("I like \(number)")
}
} detail: {
NavigationStack(path: $path) {
List(1...20, id: \.self, selection: $selection) { number in
Text("I like \(number)")
}
.padding()
.navigationDestination(for: Int.self) { number in
VStack {
Text("You chose \(number)")
List(1...20, id: \.self, selection: $selection) { number in
Text("I like \(number)")
}
}
}
}
}
.onChange(of: selection) { newValue in
print("You clicked \(newValue)")
if let newValue {
path.append(newValue)
}
}
.onChange(of: path) { newValue in
print("Path changed to \(path)")
}
}
}
Problem of course is, that now the sidebar is useless.
I added a keyboard toolbar inside ZStack. And it works right after appears as expected
But after opening and closing another view over the .sheet modifier, The keyboard toolbar doesn't show anymore.
ZStack { . .. TextField() .toolbar { ToolbarItemGroup(placement: .keyboard) { .... } } } .sheet(isPresent: $binding) { Some other view }
Seems it happened after upgrading to iOS 16. Does anybody has the solution?
Thanks
I have added additional localizations into my iOS app. iOS is not available in those languages. So I did as it is suggested that you redirect customers to app settings view UIApplication.openSettingsURLString and there they can select another app language.
Unfortunately they do not see language selection if they do not have set at least 2 Preferred languages in General -> Languages & Region. Also it does not matter what languages they have there. If my app does not support those then it still shows all localizations available.
Is there somehow to force it? So it would be visible always? Since most people in my country have iPhones only in English but would like to use Apps in their native language.. Since they do not have 2 preferred languages they cant see the selection :(
UILargeContentViewerInteraction, added in iOS 13, works out of the box on the tab bar in a UITabBarController, and it's easy to set up on a custom view using the UILargeContentViewerItem properties on UIView. But how do I set it up on a UITabBar that's not connected to a UITabBarController? There don't appear to be any relevant properties on UITabBarItem.
To try this, I made a sample app, added a tab bar, set up some items, set their largeContentSizeImage properties for good measure, ran the app, set text size to a large accessibility value, and long-pressed on the items, and I get no large content viewer.
I also tried adding a UILargeContentViewerInteraction to the tab bar, and implemented the viewControllerForInteraction method in the delegate.
Generic parameter 'V' could not be inferred ERROR
Hello Apple Community,
With a backend development background, I was always reluctant to do any front end. Especially with my bad experience with html & css, my negative opinion towards UI only got stronger.
When starting a new project at my current company, I was forced to do SwiftUI for iOS. After a few small (I mean really small) hiccups, I really understood the concept and it all became natural.
This positive experience made me want to try other front end frameworks which work for web. I dipped my toes into Jetpack Compose, C# UWP/WPF, Rust with EGUI.
I was really impressed with the performance and possibilities of Rust (EGUI) compiled to WASM. I was especially impressed that you do not have to use any HTML or CSS rather the rendering is completely up to you just like with a desktop application. I was always disappointed of the necessity of html, but with the rise of WASM in the recent years, I really hope there will be amazing alternatives using WASM & WEBGL.
Rust with EGUI is good and all but lets be honest to our self: With the ease of SwiftUI, its obvious why all the best looking applications are on iOS.
Its time for SwiftUI in web.
The advantages for the developers are obvious:
Arguably better UI Framework
No Html DOM stuff
Friendlier for new developers
One framework & language for multiple platforms
etc ...
But whats in for Apple? Why "waste" resources?
In my opinion the most important thing is: Increased Developer adoption
What is your opinion on this topic?
Would you use SwiftUI for web?
What are you currently using for web?
Do you prefer any other frontend framework over SwiftUI? (not considering the platform)
Here are the sample codes:
import SwiftUI
struct Item: Identifiable, Hashable {
var id = UUID()
var text: String
}
struct Player: Identifiable {
var id = UUID()
var score: String
}
struct TestView: View {
@State var sidebarItems: [Item] = [
.init(text: "1"),
.init(text: "2")
]
@State var players: [Player] = [
.init(score: "2"),
.init(score: "3"),
.init(score: "6"),
.init(score: "1")]
@State private var selectedItem: Item?
var body: some View {
NavigationSplitView(columnVisibility: .constant(.all)) {
List(sidebarItems, selection: $selectedItem) { item in
Text(item.text)
}
Button("shuffle") {
withAnimation(.easeIn) {
players.shuffle()
sidebarItems.shuffle()
}
}
} content: {
List {
ForEach(players) { player in
Text(player.score)
}
}
} detail: {
Text("Detail")
}
}
}
struct TestView_Previews: PreviewProvider {
static var previews: some View {
TestView()
}
}
But as a result. Animation working fine on content but not on sidebar
Hello,
we have weird crash in our app that mostly seems to happen right after launch. It is quite rare and so far I haven’t been able to reproduce it (the info below comes from Crashlytics).
The main error message I have is this:
failed to demangle witness for associated type 'Property' in conformance 'SwiftUI.StateObject<AppBlock.QuickBlockActivityViewModel>.(unknown context at $18f34e5b8).Box: DynamicPropertyBox' from mangled name ' � ��yxG' - subject type x does not conform to protocol ObservableObject
And here is the stack trace:
Crashed: com.apple.main-thread
0 libsystem_kernel.dylib 0x7200 __pthread_kill + 8
1 libsystem_pthread.dylib 0x71ac pthread_kill + 268
2 libsystem_c.dylib 0x20ca0 abort + 180
3 libswiftCore.dylib 0x3d7304 swift::fatalError(unsigned int, char const*, ...) + 134
4 libswiftCore.dylib 0x3d7324 swift::warningv(unsigned int, char const*, char*) + 30
5 libswiftCore.dylib 0x3ee678 swift_getAssociatedConformanceWitnessSlowImpl(swift::TargetWitnessTable<swift::InProcess>*, swift::TargetMetadata<swift::InProcess> const*, swift::TargetMetadata<swift::InProcess> const*, swift::TargetProtocolRequirement<swift::InProcess> const*, swift::TargetProtocolRequirement<swift::InProcess> const*) + 2078
6 libswiftCore.dylib 0x3ecb9c swift_getAssociatedTypeWitness + 236
7 SwiftUI 0x5b838 OUTLINED_FUNCTION_49 + 640
8 SwiftUI 0xa8d68 OUTLINED_FUNCTION_513 + 16260
9 SwiftUI 0x58244 OUTLINED_FUNCTION_177 + 10892
10 SwiftUI 0x95524 OUTLINED_FUNCTION_1160 + 6632
We are using the view model (QuickBlockActivityViewModel) in a SwiftUI view that is part of collection view using the new UIHostingConfiguration from iOS 16.
Our view model is a subclass of view model for older iOS versions that conforms to ObservableObject and is marked as @MainActor.
And the view model is used like this:
@StateObject private var viewModel = QuickBlockActivityViewModel()
Internally the view model uses Combine to monitor a couple of states from other parts of the app to modify its properties.
I developed an app with 10 widgets but some iPhone, iPad or macOS
users report that my widgets or the "App Name" don't appear in the
widgets list when they tried to add the widgets of my app.
There's no way I can replicate the problem, but the number of the users that report this issue is growing up every day.
It’s not clear if the problem is caused by the iPhone model, a crash on the widget preview or other factors.
My widgets previews are built reading static data, so this data is the same in every conditions.
I suggest my users to do the following steps:
Start the app and go to check again if "App name" appears among widget List
Close every app and restart the device; then start the app and
go to check again if "App name" appears among widget List
Temporarily change system language and turn on Bold Text and go to check again if "App Name" appears among widget List
Uninstall and reinstall the app, start the app and go to check again if "App Name" appears among widget List
But all users who have tried these steps say that the app still does not appear in the list of widgets.
The following code is the one I use inside the main widgets swift file called TodayWidgetExtension:
import WidgetKit
import SwiftUI
struct PlaceholderView : View {
var body: some View {
Text("loading")
}
}
//MARK: - Main widget bundle configuration
@main
struct WidgetBundle: WidgetBundle {
@WidgetBundleBuilder
var body: some Widget {
//MARK: - 1
Widget1Large()
Widget1Medium()
Widget1Small()
if #available(iOSApplicationExtension 16.0, *) {
Widget1Accessory()
}
//MARK: - 2
Widget2Large()
//MARK: - 3
#if !targetEnvironment(macCatalyst)
Widget3Medium()
#endif
//MARK: - 4
Widget4Large()
//MARK: - 5
Widget5Medium()
//MARK: - 6
Widget6Large()
Widget6Medium()
}
}
struct todaywidgetextension_Previews: PreviewProvider {
static var previews: some View {
PlaceholderView()
.previewContext(WidgetPreviewContext(family: .systemSmall))
}
}
The only thing that I've noticed debugging the widgets extension is
that, even if I don't add any of them to my iPhone screen, Xcode tells
me that widgets occupied 20mb of memory (the limit for widgets is 30mb).
I tried removing all the widgets from the above code leaving only one
(Widget1Small for example), but Xcode continues to tell me that 20mb of
memory are still occupied.
I hope that someone can help me.
Thank you.
I'm implementing a Timer in my app and I want the countdown to show up as a Live Activity. It works, but I get a very weird expanding effect on the Text view. The screenshots below show the issue, I can't tell if it's a bug or if I'm doing something wrong.
My goal is to shrink the live activity black area so that it's a smaller, more reasonable size. There's no reason for it to be as large as it is on the trailing side.
The Live Activity code (very basic):
} dynamicIsland: { context in
} compactTrailing: {
// Important bit is here
Text(Date(), style: .timer)
}
}
Which renders like this, with a lot of space after the timer:
Adding a background color shows the view is expanding:
Text(Date(), style: .timer)
.background(.red)
And if I replace the timer with a standard text view, then no issue:
Text("Hello")
.background(.red)
Getting out of live activities and showing a standard timer view, there is no expansion issue:
struct TestView: View {
var body: some View {
Text(Date(), style: .timer)
.background(.red)
}
}
So... I'm stumped. Any advice is appreciated.
//
// AppDelegate.swift
// HelloCocoa
//
import Cocoa
@main
class AppDelegate: NSObject, NSApplicationDelegate {
func applicationDidFinishLaunching(_ aNotification: Notification) {
let myAlert = NSAlert()
myAlert.messageText = "Alert Title"
let messageAttributedString = NSAttributedString(string: "Hello,world", attributes: [.font : NSFont.systemFont(ofSize: 12, weight: .bold)])
let myTextField = NSTextField(labelWithAttributedString: messageAttributedString)
myTextField.allowsEditingTextAttributes = true
myTextField.isSelectable = true
myAlert.accessoryView = myTextField
myAlert.runModal()
}
func applicationWillTerminate(_ aNotification: Notification) {
// Insert code here to tear down your application
}
func applicationSupportsSecureRestorableState(_ app: NSApplication) -> Bool {
return true
}
}
The alert appears like this:
but when I clicks on the textfield, the text's color become black:
Adding foregroundColor key to attribute dictionary works for me but I really want to know why NSTextfield has such behavior
i saw there is a way to track hands with vision, but is there also a way to record that movement and export it to fbx? Oh and is there a way to set only one hand to be recorded or both at the same time? Implementation will be in SwiftUI