Post not yet marked as solved
Hi, can anyone help me to solve this issue?
f you want Interface Builder to reflect UI changes that you have written in code, you must prefix your custom class with what designation?
Post not yet marked as solved
I have made an UICollectionView in which you can double tap a cell to resize it.
I'm using a CompositionalLayout, a DiffableDataSource and the new UIHostingConfiguration hosting a SwiftUI View which depends on an ObservableObject.
The resizing is triggered by updating the height property of the ObservableObject. That causes the SwiftUI View to change its frame which leads to the collectionView automatically resizing the cell. The caveat is that it does so immediately without animation only jumping between the old and the new frame of the view.
The ideal end-goal would be to be able to add a .animation() modifier to the SwiftUI View that then determines animation for both view and cell. Doing so now without additional setup makes the SwiftUI View animate but not the cell.
Is there a way to make the cell (orange) follow the size of the view (green) dynamically?
The proper way to manipulate the cell animation (as far as I known) is to override initialLayoutAttributesForAppearingItem() and finalLayoutAttributesForDisappearingItem() but since the cell just changes and doesn't appear/disappear they don't have an effect.
One could also think of Auto Layout constraints to archive this but I don’t think they are usable with UIHostingConfiguration?
I've also tried:
subclassing UICollectionViewCell and overriding apply(_ layoutAttributes: UICollectionViewLayoutAttributes) but it only effects the orange cell-background on initial appearance.
to put layout.invalidateLayout() or collectionView.layoutIfNeeded() inside UIView.animate() but it does not seem to have an effect on the size change.
Any thoughts, hints, ideas are greatly appreciated ✌️ Cheers!
Here is the code I used for the first gif:
struct CellContentModel {
var height: CGFloat? = 100
}
class CellContentController: ObservableObject, Identifiable {
let id = UUID()
@Published var cellContentModel: CellContentModel
init(cellContentModel: CellContentModel) {
self.cellContentModel = cellContentModel
}
}
class DataStore {
var data: [CellContentController]
var dataById: [CellContentController.ID: CellContentController]
init(data: [CellContentController]) {
self.data = data
self.dataById = Dictionary(uniqueKeysWithValues: data.map { ($0.id, $0) } )
}
static let testData = [
CellContentController(cellContentModel: CellContentModel()),
CellContentController(cellContentModel: CellContentModel(height: 80)),
CellContentController(cellContentModel: CellContentModel())
]
}
class CollectionViewController: UIViewController {
enum Section {
case first
}
var dataStore = DataStore(data: DataStore.testData)
private var layout: UICollectionViewCompositionalLayout!
private var collectionView: UICollectionView!
private var dataSource: UICollectionViewDiffableDataSource<Section, CellContentController.ID>!
override func loadView() {
createLayout()
createCollectionView()
createDataSource()
view = collectionView
}
}
// - MARK: Layout
extension CollectionViewController {
func createLayout() {
let itemSize = NSCollectionLayoutSize(widthDimension: .fractionalWidth(1), heightDimension: .estimated(50))
let Item = NSCollectionLayoutItem(layoutSize: itemSize)
let groupSize = NSCollectionLayoutSize(widthDimension: .fractionalWidth(0.8), heightDimension: .estimated(300))
let group = NSCollectionLayoutGroup.horizontal(layoutSize: groupSize, subitems: [Item])
let section = NSCollectionLayoutSection(group: group)
layout = .init(section: section)
}
}
// - MARK: CollectionView
extension CollectionViewController {
func createCollectionView() {
collectionView = .init(frame: .zero, collectionViewLayout: layout)
let doubleTapGestureRecognizer = DoubleTapGestureRecognizer()
doubleTapGestureRecognizer.doubleTapAction = { [unowned self] touch, _ in
let touchLocation = touch.location(in: collectionView)
guard let touchedIndexPath = collectionView.indexPathForItem(at: touchLocation) else { return }
let touchedItemIdentifier = dataSource.itemIdentifier(for: touchedIndexPath)!
dataStore.dataById[touchedItemIdentifier]!.cellContentModel.height = dataStore.dataById[touchedItemIdentifier]!.cellContentModel.height == 100 ? nil : 100
}
collectionView.addGestureRecognizer(doubleTapGestureRecognizer)
}
}
// - MARK: DataSource
extension CollectionViewController {
func createDataSource() {
let cellRegistration = UICollectionView.CellRegistration<UICollectionViewCell, CellContentController.ID>() { cell, indexPath, itemIdentifier in
let cellContentController = self.dataStore.dataById[itemIdentifier]!
cell.contentConfiguration = UIHostingConfiguration {
TextView(cellContentController: cellContentController)
}
.background(.orange)
}
dataSource = .init(collectionView: collectionView) { collectionView, indexPath, itemIdentifier in
return collectionView.dequeueConfiguredReusableCell(using: cellRegistration, for: indexPath, item: itemIdentifier)
}
var initialSnapshot = NSDiffableDataSourceSnapshot<Section, CellContentController.ID>()
initialSnapshot.appendSections([Section.first])
initialSnapshot.appendItems(dataStore.data.map{ $0.id }, toSection: Section.first)
dataSource.applySnapshotUsingReloadData(initialSnapshot)
}
}
class DoubleTapGestureRecognizer: UITapGestureRecognizer {
var doubleTapAction: ((UITouch, UIEvent) -> Void)?
override func touchesBegan(_ touches: Set<UITouch>, with event: UIEvent) {
if touches.first!.tapCount == 2 {
doubleTapAction?(touches.first!, event)
}
}
}
struct TextView: View {
@StateObject var cellContentController: CellContentController
var body: some View {
Text(cellContentController.cellContentModel.height?.description ?? "nil")
.frame(height: cellContentController.cellContentModel.height, alignment: .top)
.background(.green)
}
}
Post not yet marked as solved
I made an UICollectionView that uses a CompositionalLayout, DiffableDataSource, the new UIHostingConfiguration and an ObservableObject. You can resize cells by double tapping them (see gif + example code). The resizing is triggered by updating the ObservableObject.
Now I want to set an animation mainly to animate the shrinking as well as the size change of the last cell but I can't seem to find the right way to do so.
By default there is no animation when shrinking and on the last cell:
While there are many guides on how to create dynamically resizeable cells they all either use changes in Autolayout constraints (which can't be used with UIHostingConfiguration - correct me if I'm wrong)
or they add an optional part to the view inside UIHostingConfiguration with "if some condition {MyAdditionalView(); .transition(someTransition)}" instead of changing its frame.
I also tried these different ways to manipulate the animation but with no success:
setting an animation modifier .animation(): this makes a fading animation appear and the view inside the hosting configuration starts to jump (It seems to be anchored in the centre of the cell).
setting a transition modifier .transition(): this has no effect on the animation.
subclassing UICompositionalLayout and overriding initialLayoutAttributesForAppearingItem(at itemIndexPath: IndexPath) as well as finalLayoutAttributesForDisappearingItem(at itemIndexPath: IndexPath): this has no effect on the animation.
subclassing UICollectionViewCell and overriding apply(_ layoutAttributes: UICollectionViewLayoutAttributes): this only effects the orange cell-background on initial appearance.
using snapshot.reloadItems([ItemIdentifier]) or snapshot.reconfigureItems([ItemIdentifier]): they have no effect on the animation and lead to inconsistent behaviour when combined with ObservableObject.
setting collectionView.selfSizingInvalidation = .enabledIncludingConstraints: no effect. Setting it to .disabled stops the orange cells from resizing altogether.
Is there a way to customize the size change animation of a cell using UIHostingConfiguration and ObservableObject?
Code without animation:
struct CellContentModel {
var height: CGFloat? = 100
}
class CellContentController: ObservableObject, Identifiable {
let id = UUID()
@Published var cellContentModel: CellContentModel
init(cellContentModel: CellContentModel) {
self.cellContentModel = cellContentModel
}
}
class DataStore {
var data: [CellContentController]
var dataById: [CellContentController.ID: CellContentController]
init(data: [CellContentController]) {
self.data = data
self.dataById = Dictionary(uniqueKeysWithValues: data.map { ($0.id, $0) } )
}
static let testData = [
CellContentController(cellContentModel: CellContentModel()),
CellContentController(cellContentModel: CellContentModel(height: 80)),
CellContentController(cellContentModel: CellContentModel())
]
}
class CollectionViewController: UIViewController {
enum Section {
case first
}
var dataStore = DataStore(data: DataStore.testData)
private var layout: UICollectionViewCompositionalLayout!
private var collectionView: UICollectionView!
private var dataSource: UICollectionViewDiffableDataSource<Section, CellContentController.ID>!
override func loadView() {
createLayout()
createCollectionView()
createDataSource()
view = collectionView
}
}
// - MARK: Layout
extension CollectionViewController {
func createLayout() {
let itemSize = NSCollectionLayoutSize(widthDimension: .fractionalWidth(1), heightDimension: .estimated(50))
let Item = NSCollectionLayoutItem(layoutSize: itemSize)
let groupSize = NSCollectionLayoutSize(widthDimension: .fractionalWidth(0.8), heightDimension: .estimated(300))
let group = NSCollectionLayoutGroup.horizontal(layoutSize: groupSize, subitems: [Item])
let section = NSCollectionLayoutSection(group: group)
layout = .init(section: section)
}
}
// - MARK: CollectionView
extension CollectionViewController {
func createCollectionView() {
collectionView = .init(frame: .zero, collectionViewLayout: layout)
let doubleTapGestureRecognizer = DoubleTapGestureRecognizer()
doubleTapGestureRecognizer.doubleTapAction = { [unowned self] touch, _ in
let touchLocation = touch.location(in: collectionView)
guard let touchedIndexPath = collectionView.indexPathForItem(at: touchLocation) else { return }
let touchedItemIdentifier = dataSource.itemIdentifier(for: touchedIndexPath)!
dataStore.dataById[touchedItemIdentifier]!.cellContentModel.height = dataStore.dataById[touchedItemIdentifier]!.cellContentModel.height == 100 ? nil : 100 // <- this triggers the resizing
}
collectionView.addGestureRecognizer(doubleTapGestureRecognizer)
}
}
// - MARK: DataSource
extension CollectionViewController {
func createDataSource() {
let cellRegistration = UICollectionView.CellRegistration<C, CellContentController.ID>() { cell, indexPath, itemIdentifier in
let cellContentController = self.dataStore.dataById[itemIdentifier]!
cell.contentConfiguration = UIHostingConfiguration {
TextView(cellContentController: cellContentController)
}
.background(.orange)
}
dataSource = .init(collectionView: collectionView) { collectionView, indexPath, itemIdentifier in
return collectionView.dequeueConfiguredReusableCell(using: cellRegistration, for: indexPath, item: itemIdentifier)
}
var initialSnapshot = NSDiffableDataSourceSnapshot<Section, CellContentController.ID>()
initialSnapshot.appendSections([Section.first])
initialSnapshot.appendItems(dataStore.data.map{ $0.id }, toSection: Section.first)
dataSource.applySnapshotUsingReloadData(initialSnapshot)
}
}
class DoubleTapGestureRecognizer: UITapGestureRecognizer {
var doubleTapAction: ((UITouch, UIEvent) -> Void)?
override func touchesBegan(_ touches: Set<UITouch>, with event: UIEvent) {
if touches.first!.tapCount == 2 {
doubleTapAction?(touches.first!, event)
}
}
}
struct TextView: View {
@StateObject var cellContentController: CellContentController
var body: some View {
Text(cellContentController.cellContentModel.height?.description ?? "nil")
.frame(height: cellContentController.cellContentModel.height)
.background(.green)
}
}
Post not yet marked as solved
I would like to have a fullscreen "view" that slides up from the bottom after a user action, and that can be swiped down smoothly like a "sheet".
I understand that there are sheets that are swipable, but dont really cover the fullscreen, and then that there is fullscreencover which does cover the full screen but is not swipable.
In apple music, whenever you click on a song, a fullscreen "modal" slides up from the bottom, and is swipable. How can I achieve that. I'm guessing if apple does it on their apps, they allow users to have the possibility to achieve the same results.
Post not yet marked as solved
Hello,
We need to add UIView Layer containing Some dynamic text like Sound DB-A Calculations during live video recording and saved it in files.
How can we do that?
Post not yet marked as solved
I need to set a specific background colour to the selected date in datePicker. Currently only a tint appears when we click on any date in the calendar, is there a way to customise this background tint ?
Post not yet marked as solved
A type of question I see often is "which UI framework is best? SwitUI, UIKit, AppKit, etc?"
And the answer is, of course, usually "it depends" or "a mix, depending on what you need".
I wanted to re-frame that question with specific parameters.
Let's say you were writing Apple Photos for the Mac from the ground up, starting today. For the sake of discussion, it's going to be functionally identical to the Photos app that exists on the Mac today. Which means it:
looks and feels like a true, native macOS app
should be very performant in terms of rendering and scrolling through a library that may contain hundreds of thousands of photos
maintains a large database which can be synced over iCloud
etc
When you go to write that first line of UI code, which UI framework are you reaching for, and why? If more than one, which ones would you use for each piece, and why?
Especially interested to hear any viewpoints from Apple folks in this thought exercise!
Post not yet marked as solved
I want to add segments into a running HKWorkout. My understanding is that I should use the addWorkoutEvents method in my HKWorkoutBuilder. Here is a sample of my code:
func saveSegment(forStep step: GymWorkoutEventStep) {
let dateInterval = DateInterval(start: step.startDate ?? Date(), end: Date())
let metadata = [
HKMetadataKeyWasUserEntered: true
]
let event = HKWorkoutEvent(type: .segment, dateInterval: dateInterval, metadata: metadata)
builder?.addWorkoutEvents([event], completion: { success, error in
print(success ? "Success saving segment" : error.debugDescription)
})
}
I’m trying to implement the same feature that the native Apple Watch “Workout” app has by adding a segment when a user double taps the screen. My code seems to work as I see “Success saving segment” in the console. However, once the workout is finished, the Apple Fitness app doesn’t show these segments. What am I missing? Also, is there a way to add distance and pace to each segment using MetadataKey’s or is this not an option?
Thanks for any help you can provide.
Post not yet marked as solved
I am building an app for my business, my business is pet care and I want my clients to be able to make a reservation from the app and for me to receive the form entries I only want to use storyboard in Xcode 13 how would I do this?
Post not yet marked as solved
Hi guys, when updated to iOS 15 , my app got this issue. Keyboard's globe button (🌐 at left bottom corner) was disappeared, but we could click it.
Does anyone have an idea of what could be happening here?
Post not yet marked as solved
How do I take the camera keyboard off my email app??
Post not yet marked as solved
In iOS 15 SDK you added the new FocusState API in SwiftUI. However there is no discussion or explanation anywhere that I could find, which explains:
What exactly is "focus"?
What isn't focus?
What is the relationship between FocusState and accessibility focus?
What is the relationship between whether a SecureField is being edited, and whether it's "focused"?
Example:
Lets say my tvOS app has an on-screen keyboard, where the user uses the remote's directional controls to move focus around to the letter buttons. To enter their password, they focus the password field, then click the center button to activate it. Now that it's active, they move focus to each letter of their password and click on each one: P... A... S... S... W... R... D... !... then they move focus to the "Submit" button and click.
In this case, while the SecureField is being edited, focus moves around to a bunch of different buttons.
The point of this example is that, if SecureField had a public "isBeingEdited" property, then it would be TRUE even while the field is not focused.
However most Workday's designers interpret "focused" as being totally equivalent to "isBeingEdited" because in a web browser, tabbing out of a field makes it stop being edited.
What is Apple's intent here? When not using a remote or physical keyboard or screen-reader, how is focus supposed to relate to whether a field is being edited? Does this relationship change when a user now has a bluetooth keyboard connected and Full Keyboard Access is turned ON? How does this correlate with accessibility focus?
I cannot find any documentation from Apple that explains what focus is, or how this is supposed to work in SwiftUI in the various different scenarios where the concept of "focus" is relevant. Do you have a link to something current that explains how it's supposed to work so that we will know if there's a bug?
Last question: how can we make the iOS simulator treat the physical keyboard as if it was a bluetooth keyboard to be used for focus-based keyboard navigation?
Post not yet marked as solved
Hello Apple-Team!
I am looking for the projectfiles which are used in the WWDC Session wwdc20-10039, "Build document-based apps in SwiftUI“.
Regards
Post not yet marked as solved
During the presentation (19:43) it says the NSTextLayoutFragment 'Layout information for one or more elements'. But from the documentation it seems that you can only generate a layout fragment from one NSTextElement. Besides there is only one property that associates a text element. What does it mean by 'parent element' anyway?
Post not yet marked as solved
I am trying to set the focus on the .searchable text entry field using @FocuseState and .focused($focusedField, equals: .search) technique demonstrated by Tanu in her WWDC21-10023 talk, but I'm not sure if it is a focusable element or how to programmatically set it. My attempt:
//based on a technique presented in https://developer.apple.com/videos/play/wwdc2021/1002 and Paul Hudson's article https://www.hackingwithswift.com/quick-start/swiftui/how-to-add-a-search-bar-to-filter-your-data
import SwiftUI
enum Field: Hashable {
case search
}
struct ContentView: View {
let itemsToSearch = ["John", "Mark", "Adam", "Carol", "Ismael", "Vanessa", "Aniq"]
@FocusState private var focusedField: Field?
@State private var searchText = ""
var body: some View {
NavigationView {
List {
ForEach(searchResults, id: \.self) { itemsToSearch in
NavigationLink(destination: Text(itemsToSearch)) {
Text(itemsToSearch)
}
}
}
.searchable(text: $searchText, placement: .navigationBarDrawer(displayMode: .always)) {
ForEach(searchResults, id: \.self) { result in
Text("\(result)").searchCompletion(result)
}
.focused($focusedField, equals: .search)
.onAppear {
focusedField = .search
}
}
}
}
var searchResults: [String] {
if searchText.isEmpty {
return itemsToSearch
} else {
return itemsToSearch.filter { $0.contains(searchText) }
}
}
}
struct ContentView_Previews: PreviewProvider {
static var previews: some View {
ContentView()
}
}
Can someone clarify if this is possible, and if so, where I am going wrong? Thanks in advance.
Laith
Post not yet marked as solved
Are SF Symbols and other fonts provided available for commercial use? For example, in a marketing website.
Post not yet marked as solved
I would like to compare what I'm doing (wrongly, it seems) to the video. Where's the demo project?
In short, I'm seeing that the runtime is complaining with
[SwiftUI] Publishing changes from background threads is not allowed; make sure to publish values from the main thread (via operators like receive(on:)) on model updates.
despite using @MainActor.
And, it isn't clear where to instantiate the model object. I get a warning
Expression requiring global actor 'MainActor' cannot appear in default-value expression of property '_manager'; this is an error in Swift 6
So while this is very promising, it is hard to discover the correct and modern way to implement asynchronous behavior in SwiftUI.
Post not yet marked as solved
After upgrading to ios15, there are many crashes. What is the reason??
-[UIView _layoutEngine_didAddLayoutConstraint:roundingAdjustment:mutuallyExclusiveConstraints:] + 468
-[UIView _tryToAddConstraint:roundingAdjustment:mutuallyExclusiveConstraints:] + 212
-[UIView(UIConstraintBasedLayout) nsli_addConstraint:]
-[UIView(UIConstraintBasedLayout) addConstraints:]_block_invoke + 176
0x000000019b069000 + 34296
-[UIView(UIConstraintBasedLayout) addConstraints:] + 196
-[UIInputWindowControllerHostingItem updateVisibilityConstraintsForPlacement:] + 440
-[UIInputWindowControllerHostingItem updateViewConstraints] + 6888
-[UIInputWindowControllerHosting updateViewConstraints] +
-[UIInputWindowController updateViewConstraints] + 92
-[UIInputWindowController changeToInputViewSet:] + 2252
___43-[UIInputWindowController setInputViewSet:]_block_invoke.1285 + 40
___77-[UIInputWindowController moveFromPlacement:toPlacement:starting:completion:]_block_invoke.1042 + 1600
-[UIViewAnimationBlockDelegate _didEndBlockAnimation:finished:context:] + 724
-[UIViewAnimationState sendDelegateAnimationDidStop:finished:] + 248
-[UIViewAnimationState animationDidStop:finished:] + 244
0x00000001861eb000 + 821768
libdispatch.dylib
__dispatch_client_callout + 20
Post not yet marked as solved
[
wwdc20-10640
https://developer.apple.com/forums/tags/wwdc20-10640
Discuss WWDC20 Session 10640 - Design for the iPadOS pointer
)
Post not yet marked as solved
I'm reworking my app and update code and design. Because my app is one both iPhone and iPad, i'm using Splitview to handle the configurations. But my app has 4 section that I manage using a Tab bar and each tab has a SplitView.
As you can see in images, the problem is that if I attach directly the UISplitViewController to UITabBarController you don't see two columns but only one (the primary or secondary view) both iPhone landscape orientation and iPad.
A solution that I found is to attach the splitviewcontroller to a view that contains a ContainerViewController e connect the split view to this container. If you do this, you see the split view work correctly ma the problem is the customization of appearance (look at image 3)
So may questions are:
why I have to embed a split view in a container view controller and i can't connect it directly to tabbar as we done until now?
Is there an other better solution then put a split view in a containerView?
Thank you
)