Setting rightview on subclass of UITextField after initialization - ios

I try to set the rightView after UITextField initialized, but it gets nil. Here's my class:
class MyTextField: UITextField, UIGestureRecognizerDelegate {
public required init?(coder aDecoder: NSCoder) {
super.init(coder: aDecoder)
prepare()
}
public override init(frame: CGRect) {
super.init(frame: frame)
prepare()
}
public convenience init() {
self.init(frame: .zero)
}
open private(set) var errorUIImageView = UIImageView(image: (resourceName: "ic_error_red"))
open func prepare() {
print("prepare")
let tap = UITapGestureRecognizer(target: self, action: Selector(("handleTap:")))
tap.numberOfTapsRequired = 1
tap.delegate = self
errorUIImageView.isUserInteractionEnabled = true
errorUIImageView.addGestureRecognizer(tap)
self.rightView = errorUIImageView // setting the rightView here
}
#IBInspectable
open var detail: String? {
get {
return detailLabel.text
}
set(value) {
detailLabel.text = value
if let v: String = value {
self.rightViewMode = .always
if self.rightView == nil {
print("nil") // this line is reached!
}
}
else {
self.rightViewMode = .never;
}
}
}
#IBInspectable
open var detailColor = UIColor.red {
didSet {
if let v: String = detailLabel.text {
detailLabel.attributedText = NSAttributedString(string: v, attributes: [NSForegroundColorAttributeName: detailColor])
}
}
}
#IBInspectable
open private(set) lazy var detailLabel = UILabel(frame: .zero)
func handleTap(sender: UITapGestureRecognizer) {
print("tapped")
}
}
Most of the code is taken from Material

If you edited your implementation after displaying it for the first time in interface builder, you might have to refresh all views.

Related

iOS - Custom UISwitch in Class

version: Xcode 12.3
My project uses UISwitch heavily. Therefore, I am creating a custom Class to customize it.
I would like to set UISwitch default thumbTintColor and backgroundColor, and update these colors when the switch is togged on (isOn property).
I've found a solution but it does not work when I return to the viewController. The switch doesn't retain the setting:
subviews[0].subviews[0].backgroundColor = UIColor.white
I can't set isOn because it's read-only property.
Is there anyway that I can set the value change? I want something like below in the customSwitch Class:
Switch off: thumbTintColor = UIColor.yellow, backgroundColor =
UIcolor.black
Switch on: thumbTintColor = UIColor.red, backgroundColor =
UIcolor.white
below is my custom Class, can anyone help? thanks.
import Foundation
#IBDesignable
class CustomSwitch: UISwitch {
private var previousValue = false
private var returnPreviousValue = false
override var isOn: Bool {
return returnPreviousValue ? previousValue : super.isOn
}
required init?(coder aDecoder: NSCoder) {
super.init(coder: aDecoder)
previousValue = isOn
addTarget(self, action: #selector(_didChange), for: .valueChanged)
}
override init(frame: CGRect) {
super.init(frame: frame)
addTarget(self, action: #selector(_didChange), for: .valueChanged)
}
override func setOn(_ on: Bool, animated: Bool) {
super.setOn(on, animated: animated)
previousValue = on
}
#objc func _didChange() {
let isOn = self.isOn
if isOn == previousValue {
return
}
returnPreviousValue = true
willChangeValue(forKey: "on")
returnPreviousValue = false
previousValue = isOn
didChangeValue(forKey: "on")
}
}
Code
#IBDesignable
class CustomSwitch: UISwitch {
required init?(coder aDecoder: NSCoder) {
super.init(coder: aDecoder)
self.initialSetUp()
}
convenience init() {
self.init(frame: .zero)
}
override init(frame: CGRect) {
super.init(frame: frame)
self.initialSetUp()
}
private func initialSetUp() {
self.addTarget(self, action: #selector(refreshUI), for: .valueChanged)
self.refreshUI()
}
#objc private func refreshUI() {
/// Be aware that this is more of a hack than a solution
/// And can break in any upcoming release
let targetSubview = self.subviews.first?.subviews.first
if self.isOn {
self.thumbTintColor = .red
targetSubview?.backgroundColor = .white
}
else {
self.thumbTintColor = .yellow
targetSubview?.backgroundColor = .black
}
}
}
Usage
let customSwitch = CustomSwitch()
self.view.addSubview(customSwitch)
customSwitch.translatesAutoresizingMaskIntoConstraints = false
NSLayoutConstraint.activate([
customSwitch.centerXAnchor.constraint(equalTo: self.view.centerXAnchor),
customSwitch.centerYAnchor.constraint(equalTo: self.view.centerYAnchor),
])

Select and deselect reusable views

I create a custom view in xib file. I add 3 views(which inherited from custom) in viewController. Initially they have white color, but when i click on first view it should be changed other color and if i click on second view, the first view should be back in white color.
I need help to change first view color back to white when second view is selected.
My code for customView here
class SubscriptionView: UIView {
#IBOutlet weak var title: UILabel!
#IBOutlet weak var subTitle: UILabel!
#IBOutlet weak var checkMark: UIImageView!
var isSelect: Bool = false
let nibName = "SubscriptionView"
var contentView: UIView?
required init?(coder aDecoder: NSCoder) {
super.init(coder: aDecoder)
commonInit()
}
override init(frame: CGRect) {
super.init(frame: frame)
commonInit()
}
override func awakeFromNib() {
super.awakeFromNib()
addGestureRecognizer(UITapGestureRecognizer(target: self, action: #selector(tapAction)))
}
func commonInit() {
guard let view = loadViewFromNib() else {
return
}
view.frame = self.bounds
view.layer.masksToBounds = true
view.layer.cornerRadius = 14
view.layerBorderColor = AppColor.amaranth
view.layerBorderWidth = 0.5
self.addSubview(view)
contentView = view
}
func loadViewFromNib() -> UIView? {
let bundle = Bundle(for: type(of: self))
let nib = UINib(nibName: nibName, bundle: bundle)
return nib.instantiate(withOwner: self, options: nil).first as? UIView
}
public func selectedView(_ isSelect: Bool) {
self.isSelect = isSelect
title.textColor = isSelect ? UIColor.white : AppColor.amaranth
subTitle.textColor = isSelect ? UIColor.white : AppColor.amaranth
checkMark.alpha = isSelect ? 1.0 : 0.0
contentView!.backgroundColor = isSelect ? AppColor.amaranth : UIColor.white
}
#objc private func tapAction() {
///????? selectedView
}
}
Here is a very simple example using the Delegate / Protocol pattern.
Define a Protocol:
// Protocol / Delegate pattern
protocol SubscriptionViewDelegate {
func gotTap(from sender: SubscriptionView)
}
Have your view controller conform to that protocol. In your custom SubscriptionView class, when the user taps you will tell the delegate that a tap was received, and the controller will loop through the SubscriptionView objects setting the "selected" state to true or false, based on the tapped view.
class SubscriptionsViewController: UIViewController, SubscriptionViewDelegate {
let theStackView: UIStackView = {
let v = UIStackView()
v.translatesAutoresizingMaskIntoConstraints = false
v.axis = .vertical
v.alignment = .fill
v.distribution = .fill
v.spacing = 20
return v
}()
// array to track the "subscription" views
var arrayOfSubscriptionViews: [SubscriptionView] = [SubscriptionView]()
override func viewDidLoad() {
super.viewDidLoad()
view.backgroundColor = .yellow
// add a stack view to hold the "subscription" views
view.addSubview(theStackView)
NSLayoutConstraint.activate([
theStackView.topAnchor.constraint(equalTo: view.safeAreaLayoutGuide.topAnchor, constant: 20.0),
theStackView.leadingAnchor.constraint(equalTo: view.safeAreaLayoutGuide.leadingAnchor, constant: 20.0),
theStackView.trailingAnchor.constraint(equalTo: view.safeAreaLayoutGuide.trailingAnchor, constant: -20.0),
])
// instantiate 3 "subscription" views
for _ in 1...3 {
// instantiate view
let v = SubscriptionView()
// set self as its delegate
v.delegate = self
// add it to our stack view
theStackView.addArrangedSubview(v)
// append it to our tracking array
arrayOfSubscriptionViews.append(v)
}
}
func gotTap(from sender: SubscriptionView) {
// just for dev / debugging
print("got tap from", sender)
// loop through the subscription views,
// setting the sender selected to TRUE
// the others to FALSE
arrayOfSubscriptionViews.forEach {
$0.selectedView($0 == sender)
}
}
}
// Protocol / Delegate pattern
protocol SubscriptionViewDelegate {
func gotTap(from sender: SubscriptionView)
}
class SubscriptionView: UIView {
#IBOutlet weak var title: UILabel!
#IBOutlet weak var subTitle: UILabel!
#IBOutlet weak var checkMark: UIImageView!
var isSelect: Bool = false
var delegate: SubscriptionViewDelegate?
let nibName = "SubscriptionView"
var contentView: UIView?
required init?(coder aDecoder: NSCoder) {
super.init(coder: aDecoder)
commonInit()
}
override init(frame: CGRect) {
super.init(frame: frame)
commonInit()
}
override func awakeFromNib() {
super.awakeFromNib()
}
func commonInit() {
guard let view = loadViewFromNib() else {
return
}
view.frame = self.bounds
view.layer.masksToBounds = true
view.layer.cornerRadius = 14
view.layer.borderColor = UIColor.red.cgColor // AppColor.amaranth
view.layer.borderWidth = 0.5
self.addSubview(view)
contentView = view
selectedView(false)
addGestureRecognizer(UITapGestureRecognizer(target: self, action: #selector(tapAction)))
}
func loadViewFromNib() -> UIView? {
let bundle = Bundle(for: type(of: self))
let nib = UINib(nibName: nibName, bundle: bundle)
return nib.instantiate(withOwner: self, options: nil).first as? UIView
}
public func selectedView(_ isSelect: Bool) {
self.isSelect = isSelect
title.textColor = isSelect ? UIColor.white : .red // AppColor.amaranth
subTitle.textColor = isSelect ? UIColor.white : .red // AppColor.amaranth
checkMark.alpha = isSelect ? 1.0 : 0.0
// contentView!.backgroundColor = isSelect ? AppColor.amaranth : UIColor.white
contentView!.backgroundColor = isSelect ? UIColor.red : UIColor.white
}
#objc private func tapAction() {
// for dev / debugging
print("sending tap from", self)
// tell the delegate self got tapped
delegate?.gotTap(from: self)
}
}
I only made minor changes to your SubscriptionView class, so you should be able to use it as-is with your existing .xib

how to prevent zooming of parantView while zooming of imageView

i have created CustomeView that contain Scroll-view.inside scroll view there is one container view that contain image view plus two button(Okay and cancel).
Following is my view-hierarchy.
CustomeView -> ScrollView -> ContainerView -> (imageView + OtherComponent).
There are two problem i faced.
while zoom in-out imageview,CustomeView is also zoomed in-out with
respect to Scrollview.
other component postion is changed while zoom in-out.
class cameraPreview : UIView , UIScrollViewDelegate {
var selectedImage : UIImage!
var backGroundView = UIView()
var imageScrollview = UIScrollView()
var metaData : [String:Any]?
let backgroundImageView = UIImageView()
var closeButton : UIButton = {
let button = UIButton(type: UIButtonType.custom)
button.setImage(UIImage(named:"closeWhite"), for: .normal)
button.addTarget(self, action: #selector(closeClick), for: .touchUpInside)
return button
}()
var okButton : UIButton = {
let button = UIButton()
button.setTitle("OK", for: .normal)
button.titleLabel?.font = UIFont.systemFont(ofSize: 15)
button.setTitleColor(UIColor.black, for: .normal)
button.backgroundColor = UIColor.white
button.layer.cornerRadius = 15
button.addTarget(self, action: #selector(okClick), for: .touchUpInside)
return button
}()
override init(frame: CGRect) {
super.init(frame: frame)
commoninit()
}
required public init?(coder aDecoder: NSCoder) {
super.init(coder: aDecoder)
commoninit()
}
required init(image:UIImage,frame:CGRect,metaData:[String:Any]?) {
super.init(frame: frame)
self.selectedImage = image
self.metaData = metaData
commoninit()
}
override func layoutSubviews() {
}
func commoninit() {
backGroundView.backgroundColor = UIColor.white
backgroundImageView.contentMode = .scaleAspectFit
self.addSubview(imageScrollview)
imageScrollview.addSubview(backGroundView)
backGroundView.addSubview(backgroundImageView)
backGroundView.addSubview(closeButton)
backGroundView.addSubview(okButton)
imageScrollview.snp.makeConstraints { (make) in
make.edges.equalTo(self)
}
backGroundView.snp.makeConstraints { (make) in
make.edges.equalTo(imageScrollview)
make.height.width.equalTo(self)
}
backgroundImageView.snp.makeConstraints { (make) in
make.edges.equalTo(backGroundView)
}
okButton.snp.makeConstraints { (make) in
make.width.equalTo(80)
make.height.equalTo(30)
make.centerX.equalTo(backGroundView.snp.centerX)
make.bottom.equalTo(backGroundView).offset(-20)
}
closeButton.snp.makeConstraints { (make) in
make.width.height.equalTo(30)
make.left.equalTo(20)
make.top.equalTo(10)
}
backgroundImageView.image = selectedImage
imageScrollview.delegate = self
imageScrollview.minimumZoomScale = 1.0
imageScrollview.maximumZoomScale = 6.0
}
func viewForZooming(in scrollView: UIScrollView) -> UIView? {
return backgroundImageView
}
#objc func closeClick(sender:UIButton) {
self.removeFromSuperview()
}
#objc func okClick(sender:UIButton) {
if let topCotroller = UIApplication.shared.gettopMostViewController() {
self.removeFromSuperview()
let mediaDetailController = UploadDetailsViewController.instantiate(fromAppStoryboard: .Upload)
mediaDetailController.mediaImage = selectedImage
if metaData != nil {
mediaDetailController.exifDictionary = metaData![kCGImagePropertyExifDictionary as String] as? [String : AnyObject]
}
topCotroller.navigationController?.pushViewController(mediaDetailController, animated: true)
}
}
}
Following is code to add cameraPreview inside current ControllerView
let imagePreview = cameraPreview(image: image, frame: UIScreen.main.bounds,metaData:metaData)
self.view.addSubview(imagePreview)
your other component is zoom in-out because you put those component inside ScrollView.if you simply put those component out side of ScrollView than your component will not zoom in-out with respect to ScrollView.
Following is Source Code.
class cameraPreview : UIView , UIScrollViewDelegate {
var selectedImage : UIImage!
var backGroundView = UIView()
var imageScrollview = UIScrollView()
var metaData : [String:Any]?
let backgroundImageView = UIImageView()
var closeButton : UIButton = {
let button = UIButton(type: UIButtonType.custom)
button.setImage(UIImage(named:"closeWhite"), for: .normal)
button.addTarget(self, action: #selector(closeClick), for: .touchUpInside)
return button
}()
var okButton : UIButton = {
let button = UIButton()
button.setTitle("OK", for: .normal)
button.titleLabel?.font = UIFont.systemFont(ofSize: 15)
button.setTitleColor(UIColor.black, for: .normal)
button.backgroundColor = UIColor.white
button.layer.cornerRadius = 15
button.addTarget(self, action: #selector(okClick), for: .touchUpInside)
return button
}()
override init(frame: CGRect) {
super.init(frame: frame)
commoninit()
}
required public init?(coder aDecoder: NSCoder) {
super.init(coder: aDecoder)
commoninit()
}
required init(image:UIImage,frame:CGRect,metaData:[String:Any]?) {
super.init(frame: frame)
self.selectedImage = image
self.metaData = metaData
commoninit()
}
override func layoutSubviews() {
}
func commoninit() {
self.backgroundColor = UIColor.white
backGroundView.backgroundColor = UIColor.clear
backgroundImageView.contentMode = .scaleAspectFit
self.addSubview(imageScrollview)
imageScrollview.addSubview(backGroundView)
backGroundView.addSubview(backgroundImageView)
self.addSubview(closeButton)
self.addSubview(okButton)
imageScrollview.snp.makeConstraints { (make) in
make.edges.equalTo(self)
}
backGroundView.snp.makeConstraints { (make) in
make.edges.equalTo(imageScrollview)
make.height.width.equalTo(self)
}
backgroundImageView.snp.makeConstraints { (make) in
make.edges.equalTo(backGroundView)
}
okButton.snp.makeConstraints { (make) in
make.width.equalTo(80)
make.height.equalTo(30)
make.centerX.equalTo(self)
make.bottom.equalTo(self).offset(-20)
}
closeButton.snp.makeConstraints { (make) in
make.width.height.equalTo(30)
make.left.equalTo(20)
make.top.equalTo(10)
}
backgroundImageView.image = selectedImage
imageScrollview.delegate = self
imageScrollview.minimumZoomScale = 1.0
imageScrollview.maximumZoomScale = 6.0
}
func viewForZooming(in scrollView: UIScrollView) -> UIView? {
return backgroundImageView
}
#objc func closeClick(sender:UIButton) {
self.removeFromSuperview()
}
#objc func okClick(sender:UIButton) {
if let topCotroller = UIApplication.shared.gettopMostViewController() {
self.removeFromSuperview()
let mediaDetailController = UploadDetailsViewController.instantiate(fromAppStoryboard: .Upload)
mediaDetailController.mediaImage = selectedImage
if metaData != nil {
mediaDetailController.exifDictionary = metaData![kCGImagePropertyExifDictionary as String] as? [String : AnyObject]
}
topCotroller.navigationController?.pushViewController(mediaDetailController, animated: true)
}
}
}

Swift iOS -How to Achieve Multi line SegmentedControl with different Font Sizes

I have SegmentedControl with 2 lines using:
// AppDelegate
UILabel.appearanceWhenContainedInInstancesOfClasses([UISegmentedControl.self]).numberOfLines = 0
The problem is the line fonts are the same exact size. I need to change the titleTextAttributes for each line so that the second line is smaller then the first line.
I know I can use this for both lines:
segmentedControl.setTitleTextAttributes([NSAttributedStringKey.font : UIFont.systemFont(ofSize: 17))
How can I do this?
// The SegmentedControl
let segmentedControl: UISegmentedControl = {
let segmentedControl = UISegmentedControl(items: ["Pizza\n123.1K", "Turkey Burgers\n456.2M", "Gingerale\n789.3B"])
segmentedControl.translatesAutoresizingMaskIntoConstraints = false
segmentedControl.tintColor = UIColor.orange
segmentedControl.backgroundColor = .white
segmentedControl.isHighlighted = true
segmentedControl.addTarget(self, action: #selector(selectedIndex(_:)), for: .valueChanged)
return segmentedControl
}()
You'll want to create a custom control by subclassing UIControl. Here's a quick example:
CustomSegmentedControl.swift
import UIKit
import CoreImage
public class CustomSegmentedControl: UIControl {
public var borderWidth: CGFloat = 1.0
public var selectedSegementIndex = 0 {
didSet {
self.styleButtons()
}
}
public var numberOfSegments: Int {
return self.segments.count
}
private var buttons: [UIButton] = []
private var stackView = UIStackView(frame: CGRect.zero)
private var stackBackground = UIView(frame: CGRect.zero)
private var segments: [NSAttributedString] = [] {
didSet {
for subview in self.stackView.arrangedSubviews {
subview.removeFromSuperview()
}
self.buttons = []
for i in 0..<segments.count {
let segment = segments[i]
self.createAndAddSegmentButton(title: segment)
}
self.styleButtons()
}
}
override public init(frame: CGRect) {
super.init(frame: frame)
self.setup()
}
public required init?(coder aDecoder: NSCoder) {
super.init(coder: aDecoder)
self.setup()
}
private func setup() {
self.addSubview(stackBackground)
self.stackBackground.constrainToBounds(of: self)
self.addSubview(stackView)
self.stackView.constrainToBounds(of: self)
self.stackView.axis = .horizontal
self.stackView.distribution = .fillEqually
self.stackView.spacing = borderWidth
self.layer.cornerRadius = 5.0
self.layer.borderWidth = borderWidth
self.clipsToBounds = true
self.stackBackground.backgroundColor = tintColor
}
private func createAndAddSegmentButton(title: NSAttributedString) {
let button = createSegmentButton(title: title)
self.buttons.append(button)
self.stackView.addArrangedSubview(button)
}
private func createSegmentButton(title: NSAttributedString) -> UIButton {
let button = UIButton(frame: CGRect.zero)
button.titleLabel?.numberOfLines = 0
button.titleLabel?.textAlignment = .center
button.setAttributedTitle(title, for: .normal)
button.addTarget(self, action: #selector(self.actSelected(button:)), for: .touchUpInside)
return button
}
override public var tintColor: UIColor! {
willSet {
self.layer.borderColor = newValue.cgColor
self.stackBackground.backgroundColor = newValue
}
}
public func setSegments(_ segments: [NSAttributedString]) {
self.segments = segments
}
#objc private func actSelected(button: UIButton) {
guard let index = self.buttons.index(of: button) else {
print("invalid selection should never happen, would want to handle better than this")
return
}
self.selectedSegementIndex = index
self.sendActions(for: .valueChanged)
}
private func styleButtons() {
for i in 0..<self.buttons.count {
let button = self.buttons[i]
if i == selectedSegementIndex {
button.backgroundColor = self.tintColor
button.titleLabel?.textColor = self.backgroundColor ?? .white
} else {
button.backgroundColor = self.backgroundColor
button.titleLabel?.textColor = self.tintColor
}
}
}
}
extension UIView {
func constrainToBounds(of view: UIView) {
self.translatesAutoresizingMaskIntoConstraints = false
let attrs: [NSLayoutAttribute] = [.leading, .top, .trailing, .bottom]
let constraints = attrs.map { (attr) -> NSLayoutConstraint in
return NSLayoutConstraint(item: self,
attribute: attr,
relatedBy: .equal,
toItem: view,
attribute: attr,
multiplier: 1.0,
constant: 0)
}
NSLayoutConstraint.activate(constraints)
}
}
ViewController.swift
import UIKit
class ViewController: UIViewController {
#IBOutlet weak var customSegment: CustomSegmentedControl!
private var segments: [NSAttributedString] = []
override func viewDidLoad() {
super.viewDidLoad()
// Do any additional setup after loading the view, typically from a nib.
self.customSegment.backgroundColor = .white
self.customSegment.tintColor = .orange
let pizza = createText(title: "Pizza", subTitle: "123K")
let turkey = createText(title: "Turkey Burgers", subTitle: "456.2M")
let gingerAle = createText(title: "Gingerale", subTitle: "789.3B")
self.segments = [pizza, turkey, gingerAle]
self.customSegment.setSegments(self.segments)
self.customSegment.addTarget(self, action: #selector(self.segmentSelectionChanged(control:)), for: .valueChanged)
}
#objc private func segmentSelectionChanged(control: CustomSegmentedControl) {
let segment = self.segments[control.selectedSegementIndex]
print("selected segment = \(segment.string)")
}
func createText(title: String, subTitle: String) -> NSAttributedString {
let titleStr = NSMutableAttributedString(string: "\(title)\n", attributes: [NSAttributedStringKey.font: UIFont.systemFont(ofSize: 16)])
let subStr = NSAttributedString(string: subTitle, attributes: [NSAttributedStringKey.font: UIFont.systemFont(ofSize: 10)])
titleStr.append(subStr)
return titleStr
}
}

UISearchBar's text move to bottom when input content?

I customized a UISearchbar, the code is like this:
class CustomSearchBar: UIView {
lazy var searchBar: MySearchBar = {
let search = MySearchBar()
search.tintColor = UIColor.orange
search.barTintColor = UIColor.yellow
search.searchBarStyle = .minimal
search.searchTextPositionAdjustment = UIOffset(horizontal: 10, vertical: 0)
return search
}()
lazy var cancelButton: UIButton = {
let button = UIButton(type: .custom)
button.setTitle("取消", for: .normal)
button.setTitleColor(UIColor.black, for: .normal)
return button
}()
override init(frame: CGRect) {
super.init(frame: frame)
setupUI()
setupConstraints()
}
required init?(coder aDecoder: NSCoder) {
fatalError("init(coder:) has not been implemented")
}
private func setupUI() {
addSubview(searchBar)
addSubview(cancelButton)
}
private func setupConstraints() {
searchBar.snp.makeConstraints { (make) in
make.left.equalToSuperview().offset(20)
make.top.equalToSuperview().offset(6)
make.height.equalTo(32)
make.width.equalToSuperview().offset(-80)
}
cancelButton.snp.makeConstraints { (make) in
make.left.equalTo(searchBar.snp.right).offset(13)
make.centerY.equalTo(searchBar)
}
}
}
class MySearchBar: UISearchBar {
override init(frame: CGRect) {
super.init(frame: frame)
}
required init?(coder aDecoder: NSCoder) {
fatalError("init(coder:) has not been implemented")
}
func indexOfSearchFieldInSubviews() -> Int! {
var index: Int!
let searchBarView = subviews[0]
for (i, view) in searchBarView.subviews.enumerated() {
if view.isKind(of: UITextField.self) {
index = i
break
}
}
return index
}
override func draw(_ rect: CGRect) {
if let index = indexOfSearchFieldInSubviews() {
let searchField: UITextField = subviews[0].subviews[index] as! UITextField
searchField.leftView = UIImageView(image: UIImage(named: "Search_icon"))
searchField.font = UIFont.systemFont(ofSize: 14)
searchField.borderStyle = .none
searchField.layer.masksToBounds = true
searchField.layer.cornerRadius = 4
searchField.backgroundColor = barTintColor
searchField.contentVerticalAlignment = .center
searchField.placeholder = "input something"
}
}
}
we can see that it is very simple. Just added a searchBar and cancelButton.
Then I added it to navigationBar as subView, make it becomeFirstResponder in viewController.
class ViewController: UIViewController {
lazy var customeSearchBar = CustomSearchBar()
override func viewDidLoad() {
super.viewDidLoad()
navigationController?.navigationBar.addSubview(customeSearchBar)
customeSearchBar.snp.makeConstraints { (make) in
make.left.right.equalToSuperview()
make.centerY.equalToSuperview()
make.height.equalTo(44)
}
customeSearchBar.searchBar.becomeFirstResponder()
}
}
At first, I input content is ok.
When I continue input content, then the issue shows up:
It looks like the content move to the bottom. I tried to find something to fix the problem. But I didn't get it.
It is a strange thing that works fine in simulate and some iPhone. But one of my phone works wrong.

Resources