HomeiOS Development10 little UIKit ideas you need to know

10 little UIKit ideas you need to know


On this article I’ve gathered my high 10 favourite trendy UIKit ideas that I would positively wish to know earlier than I begin my subsequent challenge.

UIKit

Customized UIColor with darkish mode help


Darkish mode and lightweight mode should not observe the very same design patterns, typically you would like to make use of a border when your app is in gentle mode, however in darkish mode you would possibly wish to cover the additional line.


One potential answer is to outline a customized UIColor based mostly the given UITraitCollection. You may verify the userInterfaceStyle property of a trait to verify for darkish look fashion.


extension UIColor {
    static var borderColor: UIColor {
        .init { (trait: UITraitCollection) -> UIColor in
            if trait.userInterfaceStyle == .darkish {
                return UIColor.clear
            }
            return UIColor.systemGray4
        }
    }
}


Based mostly on this situation you may simply return totally different colours each for gentle and darkish mode. You may create your individual set of static coloration variables by extending the UIColor object. It is a will need to have little trick in case you are planning to help darkish mode and also you’d wish to create customized colours. 🌈








Observing trait assortment modifications


This subsequent one can also be associated to darkish mode help, typically you’d wish to detect look modifications of the person interface and that is the place the traitCollectionDidChange operate could be useful. It is accessible on views, controllers and cells too, so it is fairly an common answer.


class MyCustomView: UIView {
    override func traitCollectionDidChange(_ previousTraitCollection: UITraitCollection?) {
        guard traitCollection.hasDifferentColorAppearance(comparedTo: previousTraitCollection) else {
            return
        }
        layer.borderColor = UIColor.borderColor.cgColor
    }
}


For instance, inside this operate you may verify if the trait assortment has a unique look fashion and you may replace your CoreGraphics layers based on that. The CoreGraphics framework is a low stage software and if you happen to work with layers and colours it’s a must to manually replace them if it involves darkish mode help, however the traitCollectionDidChange methodology might help you numerous. 💡








UIButton with context menus


Creating buttons acquired quite a bit simpler with iOS 15, however do you know you could additionally use a button to show a context menu? It is very straightforward to current a UIMenu you simply should set the menu and the showsMenuAsPrimaryAction property of the button to true.


import UIKit

class TestViewController: UIViewController {
    
    weak var button: UIButton!

    override func loadView() {
        tremendous.loadView()
     
        let button = UIButton(body: .zero)
        button.translatesAutoresizingMaskIntoConstraints = false
        view.addSubview(button)
        self.button = button

        NSLayoutConstraint.activate([
            button.centerYAnchor.constraint(equalTo: view.centerYAnchor),
            button.leadingAnchor.constraint(equalTo: view.leadingAnchor),
            button.trailingAnchor.constraint(equalTo: view.trailingAnchor),
            button.heightAnchor.constraint(equalToConstant: 44),
        ])
    }

    override func viewDidLoad() {
        tremendous.viewDidLoad()

        button.setTitle("Open menu", for: .regular)
        button.setTitleColor(.systemGreen, for: .regular)
        button.menu = getContextMenu()
        button.showsMenuAsPrimaryAction = true
    }

    func getContextMenu() -> UIMenu {
        .init(title: "Menu",
              youngsters: [
                UIAction(title: "Edit", image: UIImage(systemName: "square.and.pencil")) { _ in
                    print("edit button clicked")
                },
                UIAction(title: "Delete", image: UIImage(systemName: "trash"), attributes: .destructive) { _ in
                    print("delete action")
                },
              ])
    }
    
}


This manner the UIButton will act as a menu button, you may assign varied actions to your menu merchandise. I imagine this API is particularly helpful in some instances, these days I desire to make use of context menus as an alternative of swipe-to-x-y actions, as a result of it is a bit extra handy for the person if we visually present them (normally with 3 dots) that there are further actions accessible on a given UI component. 🧐





Do not be afraid of subclassing views


UIKit is an OOP framework and I extremely suggest to subclass customized views as an alternative of multi-line view configuration code snippets inside your view controller. The earlier code snippet is a good instance for the alternative, so let’s repair that actual fast.


import UIKit

class MenuButton: UIButton {

    @accessible(*, unavailable)
    override init(body: CGRect) {
        tremendous.init(body: body)
        
        self.initialize()
    }

    @accessible(*, unavailable)
    required public init?(coder: NSCoder) {
        tremendous.init(coder: coder)
        
        self.initialize()
    }
   
    public init() {
        tremendous.init(body: .zero)
        
        self.initialize()
    }
    
    open func initialize() {
        self.translatesAutoresizingMaskIntoConstraints = false

        setTitle("Open menu", for: .regular)
        setTitleColor(.systemGreen, for: .regular)
        menu = getContextMenu()
        showsMenuAsPrimaryAction = true
    }
    
    func getContextMenu() -> UIMenu {
        .init(title: "Menu",
              youngsters: [
                UIAction(title: "Edit", image: UIImage(systemName: "square.and.pencil")) { _ in
                    print("edit button clicked")
                },
                UIAction(title: "Delete", image: UIImage(systemName: "trash"), attributes: .destructive) { _ in
                    print("delete action")
                },
              ])
    }

    func layoutConstraints(in view: UIView) -> [NSLayoutConstraint] {
        [
            centerYAnchor.constraint(equalTo: view.centerYAnchor),
            leadingAnchor.constraint(equalTo: view.leadingAnchor),
            trailingAnchor.constraint(equalTo: view.trailingAnchor),
            heightAnchor.constraint(equalToConstant: 44),
        ]
    }
}


class TestViewController: ViewController {
    
    weak var button: MenuButton!

    override func loadView() {
        tremendous.loadView()
     
        let button = MenuButton()
        view.addSubview(button)
        self.button = button
        NSLayoutConstraint.activate(button.layoutConstraints(in: view))
    }

    override func viewDidLoad() {
        tremendous.viewDidLoad()
        
    }
}


As you may see the code contained in the view controller is closely diminished and a lot of the button configuration associated logic is now encapsulated contained in the MenuButton subclass. This strategy is nice as a result of you may focus much less on view configuration and extra on what you are promoting logic contained in the view controller. It’s going to additionally enable you to suppose in reusable parts.

One further notice right here is that I are likely to create my interfaces from code that is why I mark the pointless init strategies with the @accessible(*, unavailable) flag so different individuals in my group cannot name them by chance, however that is only a private desire. 😅






At all times giant navigation title


I do not learn about you, however for me all of the apps have glitches if it involves the big title function within the navigation bar. For private tasks I’ve acquired sick and bored with this and I merely power the big title show mode. It is comparatively easy, this is do it.


import UIKit

class TestNavigationController: UINavigationController {

    override init(rootViewController: UIViewController) {
        tremendous.init(rootViewController: rootViewController)
        
        initialize()
    }

    @accessible(*, unavailable)
    required init?(coder aDecoder: NSCoder) {
        tremendous.init(coder: aDecoder)

        initialize()
    }
    
    open func initialize() {
        navigationBar.prefersLargeTitles = true
        navigationItem.largeTitleDisplayMode = .all the time
        
        
        navigationBar.tintColor = .systemGreen
        
        let navBarAppearance = UINavigationBarAppearance()
        navBarAppearance.backgroundColor = .systemBackground
        navigationBar.standardAppearance = navBarAppearance
        navigationBar.scrollEdgeAppearance = navBarAppearance
    }
}

class TestViewController: UIViewController {
    
    override func loadView() {
        tremendous.loadView()
        
        
        view.addSubview(UIView(body: .zero))
        
        
    }
}

let controller = TestNavigationController(rootViewController: TestViewController())


You simply should set two properties (you may subclass UINavigationController or set these inside your view controller, however I desire subclassing) plus it’s a must to add an empty view to your view hierarchy to stop collapsing in case you are planning to make use of a UIScrollView, UITableView or UICollectionView contained in the view controller.


Since this tip can also be based mostly on my private desire, I’ve additionally included a number of extra customization choices within the snippet. When you check out the initialize methodology you may see change the tint coloration and the background coloration of the navigation bar. 👍






Customized separators for navigation and tab bars


Since many apps desire to have a personalized navigation bar and tab bar look it is fairly a typical observe when it’s a must to additionally add a separator line to differentiate person interface parts a bit extra. That is how one can resolve it by utilizing a single bar separator class.


import UIKit 

class BarSeparator: UIView {
    
    let peak: CGFloat = 0.3

    init() {
        tremendous.init(body: CGRect(x: 0, y: 0, width: 0, peak: peak))
        
        translatesAutoresizingMaskIntoConstraints = false
        backgroundColor = .systemGray4
    }
    
    @accessible(*, unavailable)
    required init?(coder: NSCoder) {
        tremendous.init(coder: coder)
    }
    
    func layoutConstraints(for navigationBar: UINavigationBar) -> [NSLayoutConstraint] {
        [
            widthAnchor.constraint(equalTo: navigationBar.widthAnchor),
            heightAnchor.constraint(equalToConstant: CGFloat(height)),
            centerXAnchor.constraint(equalTo: navigationBar.centerXAnchor),
            topAnchor.constraint(equalTo: navigationBar.bottomAnchor),
        ]
    }
    
    func layoutConstraints(for tabBar: UITabBar) -> [NSLayoutConstraint] {
        [
            widthAnchor.constraint(equalTo: tabBar.widthAnchor),
            heightAnchor.constraint(equalToConstant: CGFloat(height)),
            centerXAnchor.constraint(equalTo: tabBar.centerXAnchor),
            topAnchor.constraint(equalTo: tabBar.topAnchor),
        ]
    }
}

class MyNavigationController: UINavigationController {
    
   override func viewDidLoad() {
        tremendous.viewDidLoad()
        
        let separator = BarSeparator()
        navigationBar.addSubview(separator)
        NSLayoutConstraint.activate(separator.layoutConstraints(for: navigationBar))
    }
}

class MyTabBarController: UITabBarController {
    
    override func viewDidLoad() {
        tremendous.viewDidLoad()
        
        let separator = BarSeparator()
        tabBar.addSubview(separator)
        NSLayoutConstraint.activate(separator.layoutConstraints(for: tabBar))
    }   
}


This manner you may reuse the BarSeparator part so as to add a line to the underside of a navigation bar and to the highest of a tab bar. This snippet follows the very same rules that I confirmed you earlier than, so you have to be accustomed to the subclassing ideas by now. 🤓





Customized tab bar gadgets


I struggled rather a lot with tab bar merchandise icon alignment, however this the best way I can simply present / cover the title and align the icons to the middle of the bar if there are not any labels.


import UIKit

class MyTabBarItem: UITabBarItem {
    
    override var title: String? {
        get { hideTitle ? nil : tremendous.title }
        set { tremendous.title = newValue }
    }
        
    non-public var hideTitle: Bool {
        true
    }

    non-public func offset(_ picture: UIImage?) -> UIImage? {
        if hideTitle {
            return picture?.withBaselineOffset(fromBottom: 12)
        }
        return picture
    }
    
    
    
    public comfort init(title: String?, picture: UIImage?, selectedImage: UIImage?) {
        self.init()

        self.title = title
        self.picture = offset(picture)
        self.selectedImage = offset(selectedImage)
    }

    override init() {
        tremendous.init()
    }

    @accessible(*, unavailable)
    required init?(coder aDecoder: NSCoder) {
        fatalError("init(coder:) has not been applied")
    }
}


tabBarItem = MyTabBarItem(title: "Residence", picture: UIImage(systemName: "home"), selectedImage: nil)


I would additionally like to say that SF Symbols are superb. If you’re not utilizing these form of icons simply but I extremely suggest to have a look. Apple made a very nice job with this assortment, there are such a lot of beautiful icons that you should use to visually enrich your app, so do not miss out. 😊






loadView vs viewDidLoad


Lengthy story quick, you need to all the time instantiate and place constraints to your views contained in the loadView methodology and configure your views contained in the viewDidLoad operate.

I all the time use implicitly unwrapped weak optionally available variables for customized views, because the addSubview operate will create a powerful reference to the view when it’s added to the view hierarchy. We do not wish to have retain cycles, proper? That’d be actual unhealthy for our software. 🙃


import UIKit

class MyCollectionViewController: ViewController {
    
    weak var assortment: UICollectionView!

    override func loadView() {
        tremendous.loadView()
        
        view.addSubview(UIView(body: .zero))
        
        let assortment = UICollectionView(body: .zero, collectionViewLayout: UICollectionViewFlowLayout())
        assortment.translatesAutoresizingMaskIntoConstraints = false
        view.addSubview(assortment)
        self.assortment = assortment
        NSLayoutConstraint.activate([
            
        ])
    }
    
    override func viewDidLoad() {
        tremendous.viewDidLoad()
        
        assortment.backgroundColor = .systemBackground
        assortment.alwaysBounceVertical = true
        assortment.dragInteractionEnabled = true
        assortment.dragDelegate = self
        assortment.dropDelegate = self

        if let flowLayout = assortment.collectionViewLayout as? UICollectionViewFlowLayout {
            flowLayout.sectionHeadersPinToVisibleBounds = true
        }
        
        assortment.register(MyCell.self,
                            forCellWithReuseIdentifier: MyCell.identifier)
    }


Anyway, I would go along with a customized subclass for the gathering view right here as nicely and possibly outline a configure methodology then name that one as an alternative of putting every thing on to the controller. The choice is all the time up-to-you, I am simply attempting to indicate you the some potential options. 😉





Stack views & auto-layout anchors


Reap the benefits of stack views and auto structure anchors as a lot as potential. If you’re going to create person interfaces programmatically in Swift with the assistance of UIKit, then it will be a vital talent to grasp these methods in any other case you are going to battle quite a bit.


I have already got a tutorial about utilizing auto structure programmatically and one other one about mastering auto-layout anchors, they had been revealed a number of years in the past, however the ideas are nonetheless legitimate and the code nonetheless works. I even have yet another article that you need to learn if you wish to study about constructing varieties utilizing stack views. Studying these form of issues helped me quite a bit to create complicated screens hassle-free. I am additionally utilizing yet another “finest observe” to create assortment views.


When SwiftUI got here out I had the sensation that finally I would do the identical with UIKit, however in fact Apple had the mandatory tooling to help the framework with view builders and property wrappers. Now that we’ve got SwiftUI I am nonetheless not utilizing it as a result of I really feel prefer it lacks various options even in 2022. I do know it is nice and I’ve created a number of prototypes for screens utilizing it, but when it involves a posh software my intestine tells me that I ought to nonetheless go along with UIKit. 🤐





Create a reusable parts library


My last recommendation on this tutorial is that you need to construct a customized Swift bundle and transfer all of your parts there. Perhaps for the primary time it will eat various time however in case you are engaged on a number of tasks it would velocity up improvement course of in your second, third, and many others. app.


You may transfer all of your customized base lessons right into a separate library and create particular ones in your software. You simply should mark them open, you should use the supply API to handle what can be utilized and what ought to be marked as unavailable.


I’ve various tutorials concerning the Swift Package deal Supervisor on my weblog, it is a nice solution to get accustomed to it and you can begin constructing your individual library step-by-step. 😊



RELATED ARTICLES

LEAVE A REPLY

Please enter your comment!
Please enter your name here

Most Popular

Recent Comments