If you run the following UIKit app and tap the view controller's right bar button item, the footerText property will change.
How should I update the collection view's footer to display the updated footerText?
class ViewController: UIViewController {
var collectionView: UICollectionView!
var footerText = "Initial footer text"
var dataSource: UICollectionViewDiffableDataSource<Section, String>!
var snapshot: NSDiffableDataSourceSnapshot<Section, String> {
var snapshot = NSDiffableDataSourceSnapshot<Section, String>()
snapshot.appendSections(Section.allCases)
snapshot.appendItems(["A", "a"], toSection: .first)
return snapshot
}
enum Section: CaseIterable {
case first
}
override func viewDidLoad() {
super.viewDidLoad()
configureHierarchy()
configureDataSource()
}
func configureHierarchy() {
navigationItem.rightBarButtonItem = .init(title: "Change footer text", style: .plain, target: self, action: #selector(changeFooterText))
collectionView = UICollectionView(frame: view.bounds, collectionViewLayout: createLayout())
view.addSubview(collectionView)
collectionView.autoresizingMask = [.flexibleHeight, .flexibleWidth]
}
@objc func changeFooterText() {
footerText = "Secondary footer text"
}
func configureDataSource() {
let cellRegistration = UICollectionView.CellRegistration<UICollectionViewListCell, String> { cell, indexPath, itemIdentifier in
var contentConfiguration = UIListContentConfiguration.cell()
contentConfiguration.text = itemIdentifier
cell.contentConfiguration = contentConfiguration
}
dataSource = .init(collectionView: collectionView) { collectionView, indexPath, itemIdentifier in
collectionView.dequeueConfiguredReusableCell(using: cellRegistration, for: indexPath, item: itemIdentifier)
}
configureSupplementaryViewProvider()
dataSource.apply(self.snapshot)
}
func configureSupplementaryViewProvider() {
let headerRegistration = UICollectionView.SupplementaryRegistration<UICollectionViewListCell>(elementKind: UICollectionView.elementKindSectionHeader) { headerView, elementKind, indexPath in
var contentConfiguration = UIListContentConfiguration.cell()
contentConfiguration.text = "Header \(indexPath.section)"
headerView.contentConfiguration = contentConfiguration
}
let footerRegistration = UICollectionView.SupplementaryRegistration<UICollectionViewListCell>(elementKind: UICollectionView.elementKindSectionFooter) { [weak self] headerView, elementKind, indexPath in
guard let self else { return }
var contentConfiguration = UIListContentConfiguration.cell()
contentConfiguration.text = self.footerText
headerView.contentConfiguration = contentConfiguration
}
dataSource.supplementaryViewProvider = { collectionView, kind, indexPath in
if kind == UICollectionView.elementKindSectionHeader {
collectionView.dequeueConfiguredReusableSupplementary(using: headerRegistration, for: indexPath)
} else if kind == UICollectionView.elementKindSectionFooter {
collectionView.dequeueConfiguredReusableSupplementary(using: footerRegistration, for: indexPath)
} else {
nil
}
}
}
func createLayout() -> UICollectionViewLayout {
UICollectionViewCompositionalLayout { section, layoutEnvironment in
var config = UICollectionLayoutListConfiguration(appearance: .insetGrouped)
config.headerMode = .supplementary
config.footerMode = .supplementary
return NSCollectionLayoutSection.list(using: config, layoutEnvironment: layoutEnvironment)
}
}
}
What I've tried to do in footerText's didSet:
Reconfiguring the supplementary view provider:
var footerText = "Initial footer text" {
didSet {
configureSupplementaryViewProvider()
}
}
Also re-applying the snapshot:
var footerText = "Initial footer text" {
didSet {
configureSupplementaryViewProvider()
dataSource.apply(self.snapshot)
}
}
Also re-configuring the items:
var footerText = "Initial footer text" {
didSet {
configureSupplementaryViewProvider()
dataSource.apply(self.snapshot, animatingDifferences: true)
var snapshot = dataSource.snapshot()
snapshot.reconfigureItems(snapshot.itemIdentifiers)
dataSource.apply(snapshot, animatingDifferences: false)
}
}
UIKit
RSS for tagConstruct and manage graphical, event-driven user interfaces for iOS or tvOS apps using UIKit.
Posts under UIKit tag
200 Posts
Sort by:
Post
Replies
Boosts
Views
Activity
We use CollectionView with UICollectionViewLayout. On willDisplay we send all cells to back, and move to front supplementaryView. It works well, until iOS 17. But now both of these methods doesn't work. Does anybody know why? And any other way to resolve this problem.
I have an application that needs to make a USSD call, but on some devices the * and # don't work on the dialer, on others it does.
if let phoneNumber = ussdNumberTextfield.text {
let encoded = "telprompt:\(phoneNumber)".addingPercentEncoding(withAllowedCharacters: .urlQueryAllowed)!
if let url = URL(string: encoded) {
if application.canOpenURL(url){
DispatchQueue.main.async {
self.application.open(url, options: [:]) { success in
}
}
}
}
}
This crash happens online and cannot be tested and reproduced. I need help. Thank you very much.
Exception Type: EXC_BREAKPOINT (SIGTRAP)
Exception Codes: 0x0000000000000001, 0x000000018b4190d0
Exception Note: EXC_CORPSE_NOTIFY
Termination Reason: SIGNAL 5 Trace/BPT trap: 5
Terminating Process: exc handler [338]
Triggered by Thread: 7
Last Exception Backtrace:
0 CoreFoundation 0x180cd7c60 __exceptionPreprocess + 216 (NSException.m:200)
1 libobjc.A.dylib 0x198507ee4 objc_exception_throw + 56 (objc-exception.mm:565)
2 CoreAutoLayout 0x1987cb000 _AssertAutoLayoutOnAllowedThreadsOnly + 412 (NSISEngine.m:0)
3 CoreAutoLayout 0x1987cdb7c -[NSISEngine withBehaviors:performModifications:] + 32 (NSISEngine.m:1975)
4 UIKitCore 0x1831262fc -[UIView _resetLayoutEngineHostConstraints] + 80 (NSLayoutConstraint_UIKitAdditions.m:1426)
5 UIKitCore 0x1830fc0c0 -[UIView(CALayerDelegate) layoutSublayersOfLayer:] + 2376 (UIView.m:18416)
6 QuartzCore 0x18477c520 CA::Layer::layout_if_needed(CA::Transaction*) + 528 (CALayer.mm:10118)
7 QuartzCore 0x18476f294 CA::Layer::layout_and_display_if_needed(CA::Transaction*) + 132 (CALayer.mm:2480)
8 QuartzCore 0x184782cc8 CA::Context::commit_transaction(CA::Transaction*, double, double*) + 464 (CAContextInternal.mm:2612)
9 QuartzCore 0x18478b79c CA::Transaction::commit() + 708 (CATransactionInternal.mm:449)
10 QuartzCore 0x1847dfe04 CA::Transaction::release_thread(void*) + 224 (CATransactionInternal.mm:651)
11 libsystem_pthread.dylib 0x1dc052d90 _pthread_tsd_cleanup + 520 (pthread_tsd.c:388)
12 libsystem_pthread.dylib 0x1dc055c08 _pthread_exit + 80 (pthread.c:1717)
13 libsystem_pthread.dylib 0x1dc05124c _pthread_wqthread_exit + 100 (pthread.c:2559)
14 libsystem_pthread.dylib 0x1dc050e88 _pthread_wqthread + 420 (pthread.c:2593)
15 libsystem_pthread.dylib 0x1dc05092c start_wqthread + 8 (:-1)
Hello,
Is there any way to iterate all views and subviews in current xcode app and taget to particular properties to every UIButton.
I tried using folllowing code but it is not working.
for views in self.view.subviews {
if views == UIButton {
button.isPointerInteractionEnabled = true
} else {
}
}
First of all, I decided to make my project with only UIKit.
So I deleted 'Main' storyboard, Info.plist->Storyboard name, and Main storyboard file base name->Main. And I edited SceneDelegate.
So now I can display the single viewControllers, but when I try to set 'UITabBarController' to rootViewController, It cause this error(title).
I tried to make UITabBarController in ViewController, UITabBarController in SceneDelegate and some more.
// BackgroundViewController for the rootViewController
import UIKit
class BackgroundViewController: UIViewController {
let backgroundTabBarController = UITabBarController()
override func viewDidLoad() {
super.viewDidLoad()
view.backgroundColor = .white
createTabBar()
}
}
extension BackgroundViewController {
private func createTabBar() {
view.backgroundColor = .white
view.addSubview(backgroundTabBarController.view)
let firstViewController = BookSearchViewController()
let secondViewController = MainViewController()
let thirdViewController = UserStatusViewController()
let lastViewController = OrderViewController()
firstViewController.tabBarItem = UITabBarItem(title: "Search", image: UIImage(systemName: "magnifyingglass.circle.fill"), selectedImage: UIImage(systemName: "magnifyingglass.circle"))
secondViewController.tabBarItem = UITabBarItem(title: "Main", image: UIImage(systemName: "house.fill"), selectedImage: UIImage(systemName: "house"))
thirdViewController.tabBarItem = UITabBarItem(title: "My", image: UIImage(systemName: "person.fill"), selectedImage: UIImage(systemName: "person"))
lastViewController.tabBarItem = UITabBarItem(title: "Order", image: UIImage(systemName: "menucard.fill"), selectedImage: UIImage(systemName: "menucard"))
backgroundTabBarController.viewControllers = [firstViewController, secondViewController, thirdViewController, lastViewController]
backgroundTabBarController.selectedViewController = secondViewController
}
}
// SceneDelegate
import UIKit
class SceneDelegate: UIResponder, UIWindowSceneDelegate {
var window: UIWindow?
func scene(_ scene: UIScene, willConnectTo session: UISceneSession, options connectionOptions: UIScene.ConnectionOptions) {
guard let windowScene = (scene as? UIWindowScene) else { return }
window = UIWindow(windowScene: windowScene)
window?.rootViewController = BackgroundViewController()
window?.makeKeyAndVisible()
}
}
// Error code
Thread 1: "Could not find a storyboard named 'Main' in bundle NSBundle </Users/[MyDesktopName]/Library/Developer/CoreSimulator/Devices/[ApplicationName]/data/Containers/Bundle/Application/[ApplicationName]/BTY.app> (loaded)"
But anyone of this solve the problem.
How can I make UITabBarController to rootViewController?
Make UITabBarController in SceneDelegate
Make new UIViewController that have UITabBarController and set to rootViewController
Set ViewControllers with 'UINavigationController(rootViewController:)'
Present UITabBarController from other viewController
First of all, I decided to make my project with only UIKit.
So I deleted 'Main' storyboard, Info.plist->Storyboard name, and Main storyboard file base name->Main.
And I edited SceneDelegate.
So now I can display the single viewControllers, but when I try to set 'UITabBarController' to rootViewController, It cause this error(title).
I tried to make UITabBarController in ViewController, UITabBarController in SceneDelegate and some more.
How can I fix this? We can't use code-based UITabBarController in new version of Xcode now?
The documentation says the default value is false, yet when tested on two devices (iPhone 7 15.8; iPhone XS 17.4) the value is always true unless explicitly set to false. Is the documentation incorrect?
I'm using something similar to this example.
import SwiftUI
struct ContentView: View {
@State private var toggle = false
var body: some View {
CustomParentView {
Button {
toggle.toggle()
} label: {
Text(toggle.description)
}
}
}
}
struct CustomParentView<Content: View>: UIViewRepresentable {
let content: Content
@inlinable init(@ViewBuilder content: () -> Content) {
self.content = content()
}
func makeUIView(context: Context) -> UIView {
let view = UIView()
let hostingController = context.coordinator.hostingController
hostingController.view.frame = view.bounds
hostingController.view.autoresizingMask = [.flexibleWidth, .flexibleHeight]
view.addSubview(hostingController.view)
return view
}
func updateUIView(_ uiView: UIView, context: Context) {
context.coordinator.hostingController.rootView = self.content
}
class Coordinator: NSObject {
var hostingController: UIHostingController<Content>
init(hostingController: UIHostingController<Content>) {
self.hostingController = hostingController
}
}
func makeCoordinator() -> Coordinator {
return Coordinator(hostingController: UIHostingController(rootView: content))
}
}
The only different thing is I'm using UIScrollView.
When I have a @State width and call .frame(width) on the content, the content would stay with initial width even when width is changed.
I tried:
hostingController.sizingOptions = .intrinsicContentSize
This time the size would change to correct size if I pinch zoom the content, but the initial size that trigger updateUIView would be .zero. This prevents me to center the content.
Is there a way to dynamically set size and get correct rendering just like any child view of a normal SwiftUI view?
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?
It's been a really long time since I've tried this, so I'm not sure if something has changed or if I've stumbled onto a bug...
I'm trying to implement a custom Transition Animation for a UINavigationController. While documentation around this is pretty sparse this days, I was able to take the old sample from the View Controller Programming Guide:, rewriting it in Swift:
func animateTransition(using transitionContext: UIViewControllerContextTransitioning) {
let containerView = transitionContext.containerView
guard let fromVC = transitionContext.viewController(forKey: .from),
let toVC = transitionContext.viewController(forKey: .to),
let toView = transitionContext.view(forKey: .to),
let fromView = transitionContext.view(forKey: .from) else {
transitionContext.completeTransition(false)
return
}
let containerFrame = containerView.frame
var toViewStartFrame = transitionContext.initialFrame(for: toVC)
let toViewFinalFrame = transitionContext.finalFrame(for: toVC)
var fromViewFinalFrame = transitionContext.finalFrame(for: fromVC)
let fromViewStartFrame = transitionContext.initialFrame(for: fromVC)
if operation.isPresenting {
toViewStartFrame.origin.x = containerFrame.size.width
toViewStartFrame.origin.y = containerFrame.size.height
} else {
fromViewFinalFrame = CGRect(x: containerFrame.size.width,
y: containerFrame.size.height,
width: toView.frame.size.width,
height: toView.frame.size.height)
// missing from Apple's sample code
toViewStartFrame = toViewFinalFrame
}
containerView.addSubview(toView)
toView.frame = toViewStartFrame
// Add the from view to the container view on dismissal, this is missing from Apple's sample code
if !operation.isPresenting {
containerView.addSubview(fromView)
fromView.frame = fromViewStartFrame
}
UIView.animate(withDuration: transitionDuration(using: transitionContext)) {
if self.operation.isPresenting {
toView.frame = toViewFinalFrame
} else {
fromView.frame = fromViewFinalFrame
}
} completion: { completed in
let success = !transitionContext.transitionWasCancelled
if (self.operation.isPresenting && !success) || (!self.operation.isPresenting && success) {
toView.removeFromSuperview()
}
// missing from Apple's sample code
if !self.operation.isPresenting {
fromView.removeFromSuperview()
}
transitionContext.completeTransition(success)
}
}
I added a couple of things to support dismissals and pops.
In order to use it with in my app, I set the navigation controller's delegate and returned the type conforming to UIViewControllerAnimatedTransitioning, containing the above code, from navigationController(_ :, animationControllerFor operation:, from fromVC:, to toVC). I've confirmed that that all behaves as you expect.
If I use this animation controller for a modal presentation or dismissal, it works fine. For a Navigation push, again, behaves as expected. But when I use it for a navigation pop I run into a problem. The animation is performed, but once it completes, the Navigation Controller's view appears to be completely empty. In a sample app, the screen goes black. In the View Debugger, I see that the UIViewControllerWrapperView has no subviews. Another curious thing I found is that my View Controller never gets a viewWillDisappear message sent.
Is there an additional setup step that I missed in order to get this working properly?
0
I want to get notification like UIApplication.didBecomeActiveNotification and UIApplication.willResignActiveNotification when app switches in iPad Stage Controller Mode, but UIApplication.didBecomeActiveNotification, UIApplication.willResignActiveNotification just dont work, is there any method to get this notification
I am trying to sync up the selected tab bar item once a user presses back and navigates back in the web wrapper iOS app.
Here is how the app works: When a user logs in, they are presented with the Home Screen. To navigate, the select a tab item on the tab bar. This tells webkit to redirect to that URL and then that webpage is shown in the app (wrapped). A back button also appears. When a user presses the back button, the webView.goBack() method sends the user back on in the webView.backForwardList. What happens then is that the user is now on the previous page, however the tab bar has not updated. In other words, the user is back on the first tab but the second tab is highlighted.
I tried fixing this by telling the tab bar controller what item to select, however this creates a state malfunction because it also tells the webView to navigate to that url again, so in fact this means that the user isn't going back through web history, but actually is going forward while simulating going back.
I need to be able to highlight the tab bar items that sync up with the page that we have gone back to without selecting it. Does anyone have an idea for how to manually highlight or select a tab bar item without actually navigating to that tab bar item?
Thank you!
I'm working with PDFKit and trying to rotate PDFAnnotation from a PDFView:
Here is my code for a normal case(no rotated):
class ImageAnnotation: PDFAnnotation {
var image: UIImage?
init(image: UIImage?, bounds: CGRect) {
self.image = image
super.init(bounds: bounds, forType: .stamp, withProperties: nil)
}
override func draw(with box: PDFDisplayBox, in context: CGContext) {
guard let cgImage = self.image?.cgImage else { return }
context.draw(cgImage, in: bound)
}
}
And here is the way I used to rotate PDFAnnotation:
init(image: UIImage?, bounds: CGRect) {
self.image = image
super.init(bounds: bounds.applying(CGAffineTransform(rotationAngle: -CGFloat.pi/12)), forType: .stamp, withProperties: nil)
}
override func draw(with box: PDFDisplayBox, in context: CGContext) {
guard let cgImage = self.image?.cgImage else { return }
context.rotate(by: CGFloat.pi/12)
context.draw(cgImage, in: bounds)
}
But it doesn't work as expected. Can you help me? Thank you.
Hi all,
Here I want to encode OrderedDictionary to JSON file,
I use the JSONEncoder below:
let encoder = JSONEncoder()
encoder.outputFormatting = [.prettyPrinted, .withoutEscapingSlashes]
and I declare variables qwe, asd and zxc:
var qwe = OrderedDictionary<String, Int>()
qwe["bbb"] = 12
qwe["ccc"] = 13
qwe["ddd"] = 14
qwe["bbc"] = 15
var asd = Dictionary<String, Int>()
asd["bbb"] = 1
asd["ccc"] = 3
asd["ddd"] = 4
asd["bbc"] = 5
var zxc: KeyValuePairs<String, String> {
return [
"zz": "zz",
"aa": "aa",
"bb": "bb",
"cc": "cc",
"bc": "bc",
]
}
After I do try encoder.encode(qwe).write(to: path ,options: .atomic)
encoder.encode(asd).write(to: path ,options: .atomic)
encoder.encode(zxc).write(to: path ,options: .atomic)
the output JSON file format of OrderedDictionary isn't what I expected.
The output JSON of OrderDictionary is like this:
[
"bbb",
12,
"ccc",
13,
"ddd",
14,
"bbc",
15
]
On the other hand, the output JSON of Dictionary and KeyValuePairs are normal, just with different order:
Dictonary:
{
"ccc" : 3,
"bbb" : 1,
"bbc" : 5,
"ddd" : 4
}
KeyValuePairs:
{
"cc" : "cc",
"aa" : "aa",
"zz" : "zz",
"bb" : "bb",
"bc" : "bc"
}
I also Log these objects after I declare them, the Log show their structure are similar:
qwe -> ["bbb": 12, "ccc": 13, "ddd": 14, "bbc": 15]
asd -> ["ccc": 3, "bbb": 1, "bbc": 5, "ddd": 4]
zxc -> ["zz": "zz", "aa": A"aa", "bb": "bb", "cc": "cc", "bc": "bc"]
I thought the OrderedDictionary is similar to Dictionary, but does anyone know why the output of OrderedDictionary is not like this:
{"bbb": 12, "ccc": 13, "ddd": 14, "bbc": 15}
Or is there any other way I can customize the order of keys in my encoded JSON file?
Thank you so much!
I have encountered inconsistent paste behaviors in UITextView depending on whether the text is in English or Korean.
When pasting at the beginning of a text with an English sentence in UITextView, a space is added after the pasted text. In the middle, spaces are added before and after the pasted text. However, when pasting at the end, only a space is added before the pasted text.
On the other hand, when there is a Korean sentence in UITextView, pasting at the beginning results in the inclusion of "\n" at the beginning of the pasted text, while in other cases, no additional text is added upon pasting.
I'm curious to know if this behavior is intentional. I would appreciate understanding the rationale behind appending "\n" in Korean text and the absence of additional text in other cases.
On app minor update, after moving to xcode 15.2
Any thoughts on what could be causing it?
Thank you in advance.
I'm trying to create a dynamic menu on Mac Catalyst. Using a UIBarButtonitem like so to make a "pull down" button:
UIDeferredMenuElement *deferredmenuElement;
deferredmenuElement = [UIDeferredMenuElement elementWithUncachedProvider:^(void (^ _Nonnull completion)(NSArray<UIMenuElement *> * _Nonnull))
{
UIAction *actionOne = [UIAction actionWithTitle:@"Action One" image:nil identifier:nil handler:^(__kindof UIAction * _Nonnull action) {
NSLog(@"action one fired.");
}];
UIAction *actionTwo = [UIAction actionWithTitle:@"Action Two" image:nil identifier:nil handler:^(__kindof UIAction * _Nonnull action) {
NSLog(@"action two fired.");
}];
UIAction *actionThree = [UIAction actionWithTitle:@"Action Three" image:nil identifier:nil handler:^(__kindof UIAction * _Nonnull action) {
NSLog(@"action three fired.");
}];
completion(@[actionOne,actionTwo,actionThree]);
}];
UIMenu *wrappedMenu = [UIMenu menuWithChildren:@[deferredmenuElement]];
UIBarButtonItem *uiBarButtonItem = [[UIBarButtonItem alloc]initWithTitle:nil
menu:wrappedMenu];
uiBarButtonItem.image = [UIImage systemImageNamed:@"rectangle.and.pencil.and.ellipsis"];
self.navigationItem.rightBarButtonItems = @[uiBarButtonItem];
The button appears in the toolbar but when I click it to expose the menu I get a menu with on element in it that says "Loading...". The the uncached provider block is never called.
Running Ventura 13.2.1 and Xcode 14.2.
Activity image for custom activity is blank ever since iOS 17 release ,compiled in Xcode 15. The image being sent is 180x180 px. Works fine in iOS 16 running earlier Xcodes.
Attached a image of the issue showing blank icons (mail and messages are the custom activities)
Anyone facing the issue?
I am currently working on an iOS application where I want to implement the safari tabs and when I have to minimize that one to check how many numbers of tabs are opened. How can I do this?