hide tabBar when a view controller is pushed

use hidesBottomBarWhenPushed variable.

don’t use “tabBarController?.tabBar.isHidden = true”. Because tabBar does not show when the view controller is popped.

And you need to set hidesBottomBarWhenPushed when the view controller ‘init’. It doesn’t work if it’s set afterwards.

How to use previews of SwiftUI with UIKit easily

Use UIViewPreview which implements UIViewRepresentable ⬇️

https://gist.github.com/mattt/ff6b58af8576c798485b449269d43607#file-uiviewpreview-swift

final class ProfitStatusStockCell: UICollectionViewCell {
}

#if DEBUG
import SwiftUI
struct ProfitStatusStockCell_Preview: PreviewProvider {
    static var previews: some View {
        UIViewPreview {
            let view = ProfitStatusStockCell()
            let viewModel = ProfitStatusStockModel(image: RoundLogo.Image(nil, placeholder: .stock), title: "카카오", value: "-28,765원", percent: "(-0.43%)", trend: .down)
            view.viewModel = viewModel
            return view.withContentSize(.init(width: 303, height: ProfitStatusStockCell.height))
        }
        .previewLayout(.sizeThatFits)

        UIViewPreview {
            let view = ProfitStatusStockCell()
            let viewModel = ProfitStatusStockModel(image: RoundLogo.Image(nil, placeholder: .stock), badgeImage: .image(Asset.Icons.icExchangeUpbit12.image.withRenderingOriginal), title: "카카오", value: "-28,765원", percent: "(-0.43%)", trend: .down)
            view.viewModel = viewModel
            return view.withContentSize(.init(width: 303, height: ProfitStatusStockCell.height))
        }
        .previewLayout(.sizeThatFits)
    }
}
#endif

Light/Dark mode cgcolor

layer’s cgcolor doesn’t get updated when color appearance changes. So you need to set manually when trait collection changes

override func traitCollectionDidChange(_ previousTraitCollection: UITraitCollection?) {
        super.traitCollectionDidChange(previousTraitCollection)
        if traitCollection.hasDifferentColorAppearance(comparedTo: previousTraitCollection) {
            contentView.layer.borderColor = textField.isEditing ? activeBorderColor : inactiveBorderColor
        }
    }

6 tabs using UITabBarController

https://stackoverflow.com/questions/10313845/can-we-add-more-than-five-tab-bar-in-ios-sdk

final class TabBarController: UITabBarController, UITabBarControllerDelegate {

private var needsChangeTraitCollection: Bool {
         tabBarItems.count > 5
     }

...
override var traitCollection: UITraitCollection {
        if needsChangeTraitCollection > 5 {
            let traitCollection = super.traitCollection
            let regularTraitCollection = UITraitCollection(horizontalSizeClass: .regular)
            return UITraitCollection(traitsFrom: [traitCollection, regularTraitCollection])
        } else {
            return super.traitCollection
        }
    }
...
}

But there was a problem. When the other view controller is presented and the dark mode changes and the view controller is dismissed, the tab bar became to be only 5 tabs. But it was okay if tabBarController is the top view controller and the dark mode changes. So only when the traitCollection changes as the tabBarController is presenting other view controller the bug happened. So I forced to change trait collection when the tab bar controller’s viewWillAppear because it’s okay if the trait collection changes when the tab bar controller is on top.

final class TabBarController: UITabBarController, UITabBarControllerDelegate {
...
override func viewWillAppear(_ animated: Bool) {
         super.viewWillAppear(animated)

         if needsChangeTraitCollection {
             traitCollectionDidChange(traitCollection)
         }
     }
...
}

Calling traitCollectionDidChange when the real traitCollection is not changed does not trigger layoutSubviews.

And then another problem occurred. Even when the tabBar is shown and dark mode changes, the layout became strange…. It forces to change traitCollection from compact to regular before layout subviews.

override func viewWillLayoutSubviews() {
         if needsChangeTraitCollection {
             traitCollectionDidChange(traitCollection)
         }
         super.viewWillLayoutSubviews()
     }

keyboard of grandparent view controller shows up when the other view controller is presented

The specific reason why keyboard is presented when the grand child(presentedViewController’s presentedViewController) view controller is presented is not found. But when the text of textfield is empty, this doesn’t happen. I set breakpoint on the resignFirstResponder, and I found when the text is empty resignFirstResponder is called when the view controller will disappear and not when the text is not empty.

Therefore I called resignFirstResponder manually when viewWillDisapper