I suggest you to check Apple documentation layoutIfNeeded()
and layoutSubviews() . You'll have better understanding after reading them. The magic happens when you write searchBar.layoutIfNeeded()
instance method. Another solution is searchBar.layoutSubviews()
but Apple documentation says:
You should not call this method directly. If you want to force a
layout update, call the setNeedsLayout() method instead to do so prior
to the next drawing update. If you want to update the layout of your
views immediately, call the layoutIfNeeded() method.
According to @Jeyamahesan's answer. When you modify the code like below you do not need to separate the code in viewDidLoad() and ViewDidAppear().
Example:
import UIKit
class MainController: UIViewController {
private var searchBar: UISearchBar!
override func viewDidLoad() {
super.viewDidLoad()
searchBar = UISearchBar()
searchBar.frame = CGRect(x: 15, y: 100, width: 350, height: 50)
searchBar.layoutIfNeeded()
self.view.addSubview(searchBar)
let searchTextField:UITextField = searchBar.subviews[0].subviews.last as! UITextField
searchTextField.layer.cornerRadius = 15
searchTextField.textAlignment = NSTextAlignment.left
let image:UIImage = UIImage(named: "Search")!
let imageView:UIImageView = UIImageView.init(image: image)
searchTextField.leftView = nil
searchTextField.placeholder = "Search"
searchTextField.rightView = imageView
searchTextField.rightViewMode = UITextFieldViewMode.always
}
}
My approach to solve the issue:
MainView.swift
import UIKit
class MainView: UIView {
override init(frame: CGRect) {
super.init(frame: frame)
setupUI()
}
required init?(coder aDecoder: NSCoder) {
super.init(coder: aDecoder)
}
private func setupUI() {
backgroundColor = UIColor.lightGray
setupSubViews()
setupAutoLayout()
}
// MARK: Initialize UI Elements
private let searchBar: UISearchBar = {
let searchBar = UISearchBar()
searchBar.isTranslucent = false
searchBar.barTintColor = ColorPalette.LuminousDay.white
searchBar.layoutIfNeeded()
return searchBar
}()
private let searchImageView: UIImageView = {
let image = UIImage(named: "Search")
let imageView = UIImageView(image: image)
imageView.contentMode = .scaleAspectFit
return imageView
}()
private lazy var searchBarTextField: UITextField = { [unowned self] in
let textField = self.searchBar.value(forKey: "searchBarTextField") as! UITextField
textField.font = FontBook.SourceSansPro.Weight.semiBold.setFont(size: 24)
textField.textColor = ColorPalette.LuminousDay.charm
textField.tintColor = ColorPalette.LuminousDay.charm
textField.clearButtonMode = .never
textField.leftViewMode = .never
textField.leftView = nil
textField.rightViewMode = .always
textField.rightView = self.searchImageView
return textField
}()
private func setupSubViews() {
addSubview(searchBar)
searchBar.addSubview(searchBarTextField)
searchBarTextField.addSubview(searchImageView)
}
private func setupAutoLayout() {
searchBar.anchor(top: safeAreaLayoutGuide.topAnchor, bottom: nil,
leading: safeAreaLayoutGuide.leadingAnchor, trailing: safeAreaLayoutGuide.trailingAnchor,
centerX: nil, centerY: nil,
centerXconstant: nil, centerYconstant: nil,
size: CGSize.zero, padding: UIEdgeInsets(top: 50, left: 0, bottom: 0, right: 0))
searchImageView.setSize(size: CGSize(width: 16, height: 16))
}
}
MainController.swift
import UIKit
class MainController: UIViewController {
override func loadView() {
view = MainView()
}
override func viewDidLoad() {
super.viewDidLoad()
}
}