UI Frameworks

RSS for tag

Discuss the different user interface frameworks available for your app.

Posts under UI Frameworks tag

112 Posts
Sort by:
Post not yet marked as solved
0 Replies
98 Views
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) } }
Posted Last updated
.
Post not yet marked as solved
0 Replies
144 Views
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)     } }
Posted Last updated
.
Post not yet marked as solved
0 Replies
107 Views
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.
Posted
by aurelien_.
Last updated
.
Post not yet marked as solved
0 Replies
86 Views
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?
Posted
by Orel94.
Last updated
.
Post not yet marked as solved
0 Replies
84 Views
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 ?
Posted
by iOSDev22.
Last updated
.
Post not yet marked as solved
3 Replies
303 Views
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!
Posted
by stevenf.
Last updated
.
Post not yet marked as solved
0 Replies
164 Views
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.
Posted
by VaDJaN.
Last updated
.
Post not yet marked as solved
1 Replies
792 Views
Hi! I am working on the UI/UX project for Apple apps(iPhone/watchOS etc.) using FIGMA. I don't have any Apple device from where I could use 'SF Font' family natively. I have tried the alternative fonts but none of them appealed to me and my client too. I also downloaded their resources but still it changes the file after I edit the text. Thanks in Advance.
Posted
by aman1.
Last updated
.
Post not yet marked as solved
2 Replies
667 Views
When using conditionals in view bodies, can I preserve identity between the true and false sides of the conditional by adding an explicit id? struct DogTreat: Identifiable { var expirationDate: Date var serialID: String var id: String { serialID } } ... struct WrapperView: View { ... var treat: DogTreat var isExpired: Bool { treat.expirationDate < .now } var body: some View { if isExpired { DogTreatView(treat) .id(treat.id) .opacity(0.75) else { DogTreatView(treat) .id(treat.id) } } ... } Does this perform / behave the same as struct WrapperView: View { ... var treat: DogTreat var isExpired: Bool { treat.expirationDate < .now } var body: some View { DogTreatView(treat) .opacity(isExpired ? 0.75 : 1.0) } ... }
Posted Last updated
.
Post not yet marked as solved
1 Replies
157 Views
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?
Posted Last updated
.
Post marked as solved
2 Replies
773 Views
The sessions talks about a new subtitle ability for UIMenus (“These buttons also benefit from improvements in menus like the ability for menu items to have subtitles for greater clarity.”) but I cannot find documentation on how to enable said subtitle. Even using the example code with the new .singleSelection option does not display any subtitle.. Anyone did succeed in doing so?
Posted
by Pomanks.
Last updated
.
Post not yet marked as solved
1 Replies
417 Views
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 )
Posted
by Rufy.
Last updated
.
Post not yet marked as solved
5 Replies
972 Views
Hi, How can I use a Table view to build a data grid for a dynamic set of data? Say, I have a 2D collection of data elements (a matrix, basically) with variable number of columns, and a 1D collection of column labels (a vector). For the sake of simplicity, let's assume that all data elements are Strings. let data: [[String]]; let columnLabels: [String] How can I build TableColumn definitions without key paths? Thanks!
Posted
by ilia_saz.
Last updated
.
Post not yet marked as solved
3 Replies
535 Views
When I use UICollectionView on iPhone13 and the latest devices, [collectionView scrollToItemAtIndexPath:[NSIndexPath indexPathForRow:0 inSection:section] atScrollPosition:UICollectionViewScrollPositionCenteredHorizontally animated:YES] will cause caton. animated:YES has no animation effect, but this method works well on other devices, They are IOS 15.0.2 systems - (void)topClick:(UIButton *)sender{         if (sender.selected) {         return;     }          NSArray *array = [NSArray array];     if (sender == self.topLuck) {         array = self.luckList;     } else if (sender == self.topLuxurious){         array = self.luxuriousList;     } else if (sender == self.topVip){         array = self.vipList;     } else if (sender == self.topPk){         array = self.pkList;     } else if (sender == self.packetBtn){         array = self.packetList;     }     NSInteger section = [self.datas indexOfObject:array]; //    [self didScrollToSection:section];          if (section < self.datas.count) {         [self.giftCollectionView scrollToItemAtIndexPath:[NSIndexPath indexPathForRow:0 inSection:section] atScrollPosition:UICollectionViewScrollPositionCenteredHorizontally animated:YES];     } } - (UICollectionView *)giftCollectionView{     if (!_giftCollectionView) {         LiveGiftPickerLayout *layout = [LiveGiftPickerLayout new];         layout.scrollDirection = UICollectionViewScrollDirectionHorizontal;         layout.sectionInset = UIEdgeInsetsMake(0, 10, 0, 10);         CGFloat width = floor((kScreen_Width - 20)/4);         layout.itemSize = CGSizeMake(width, width);         layout.minimumLineSpacing = 0;         layout.minimumInteritemSpacing = 0;         _giftCollectionView = [[UICollectionView alloc] initWithFrame:CGRectZero collectionViewLayout:layout];         _giftCollectionView.dataSource = self;         _giftCollectionView.delegate = self;         _giftCollectionView.backgroundColor = [UIColor clearColor];         _giftCollectionView.showsHorizontalScrollIndicator = NO;         _giftCollectionView.pagingEnabled = YES;         [_giftCollectionView registerClass:[GiftPickerCollectionViewCell class] forCellWithReuseIdentifier:[GiftPickerCollectionViewCell currentIdentifier]];     }     return _giftCollectionView; }
Posted
by funny-qwq.
Last updated
.
Post not yet marked as solved
4 Replies
471 Views
Have spent 2 hours on this without success, and have not found any info on-line. I've put together a list of items (regular swiftui list) and when I add a Navigation Link, it modifies the list item view to add a ">" symbol to the right of the list item. This is the current code from the list view (calls a sub-view - that works perfect, but I don't want the ">" symbol appearing on each item. List ($viewModel.teams) { Team in NavigationLink(destination: GroupMembersView(user: user, team: Team)) { GroupsCellView(team: Team) }.buttonStyle(PlainButtonStyle()) }.listStyle(.plain) Here is a picture of the nav view & undesired symbol (symbol appears on the right hand side of every item in list): How can I remove this symbol? -thanks!
Posted
by Mopi.
Last updated
.