I have some problem. I have UITableView and header of tableView is searchController with 1 red view (Inside of this view will be some icon).
After staring of search appears cancel button.
And now I press cancel button and search bar resize to full screen size and red view is disappear.
How to solve this problem?
Here is my headerView class:
lazy var searchController = UISearchController(searchResultsController: nil).then {
//return UISearchController().then {
$0.dimsBackgroundDuringPresentation = false
$0.searchBar.placeholder = "Искать по имени"
$0.searchBar.tintColor = .black
$0.searchBar.searchBarStyle = .minimal
$0.searchBar.backgroundColor = .white
UIBarButtonItem.appearance(whenContainedInInstancesOf: [UISearchBar.self]).setTitleTextAttributes([NSFontAttributeName : UIFont.appleSystemRegular(15)], for: .normal)
$0.searchBar.setValue("Отмена", forKey:"_cancelButtonText")
}
lazy var contentView: UIView = {
let view = UIView()
view.backgroundColor = .red
return view
}()
override init(frame: CGRect) {
super.init(frame: frame)
setupViews()
setupConstrains()
}
required init?(coder aDecoder: NSCoder) {
fatalError("init(coder:) has not been implemented")
}
fileprivate func setupViews() {
addSubview(contentView)
addSubview(searchController.searchBar)
}
func setupConstrains() {
searchController.searchBar.frame = CGRect(x: 0, y: 0, width: self.frame.width - 80, height: 44)
contentView.frame = CGRect(x: self.frame.width - 65, y: 0, width: 50, height: 44)
}
Remove searchcontroller and try to search only searchbar delegate.
func searchBar(searchBar: UISearchBar, textDidChange searchText: String) {
}
Related
I´ve tried to change background color inside class SearchBarView: UIView {}:
searchBar.searchTextField.backgroundColor = .clear
searchBar.backgroundColor = .clear
and tryed something like that inside MainViewController:
searchBar.searchTextField.backgroundColor = .clear
searchBar.backgroundColor = .clear
searchBar.layer.backgroundColor = UIColor.clear.cgColor
but, unfortunately I still see this lines inside my custom searchBar.
How can I get rid of these lines?
My SearchBarView class:
class SearchBarView: UIView {
lazy var searchBar = createSearchBar()
override init(frame: CGRect) {
super.init(frame: frame)
addSubview(searchBar)
searchBar.snp.makeConstraints { make in
make.leading.equalTo(32)
make.centerY.equalToSuperview()
make.height.equalTo(34)
make.width.equalTo(300)
}
}
required init?(coder: NSCoder) {
fatalError("init(coder:) has not been implemented")
}
}
fileprivate extension SearchBarView {
private func createSearchBar() -> UISearchBar {
let searchBar = UISearchBar()
searchBar.placeholder = " Search"
searchBar.searchTextField.font = UIFont(name: "MarkPro", size: 15)
searchBar.searchTextField.backgroundColor = .clear
let textFieldInsideSearchBar = searchBar.value(forKey: "searchField") as? UITextField
let imageV = textFieldInsideSearchBar?.leftView as! UIImageView
imageV.image = imageV.image?.withRenderingMode(UIImage.RenderingMode.alwaysTemplate)
imageV.tintColor = UIColor(hexString: "FF6E4E")
return searchBar
}
}
My MainViewController class:
class MainViewController: UIViewController {
private var searchBarView: SearchBarView!
override func viewDidLoad() {
super.viewDidLoad()
setupSearchBarView()
}
private func setupSearchBarView() {
searchBarView = SearchBarView(frame: CGRect(x: 0, y: 0, width: 0, height: 0))
view.addSubview(searchBarView)
searchBarView.searchBar.clipsToBounds = true
searchBarView.searchBar.layer.cornerRadius = 17
searchBarView.searchBar.layer.maskedCorners = [.layerMinXMinYCorner, .layerMaxXMinYCorner, .layerMinXMaxYCorner, .layerMaxXMaxYCorner]
searchBarView.searchBar.searchTextField.clipsToBounds = true
let directionalMargins = NSDirectionalEdgeInsets(top: 0, leading: 24, bottom: 0, trailing: 0)
searchBarView.searchBar.directionalLayoutMargins = directionalMargins
searchBarView.snp.makeConstraints { make in
make.leading.equalToSuperview()
make.top.equalTo(categoriesView.snp.bottom)
make.trailing.equalToSuperview()
make.height.equalTo(60)
}
}
}
If you want to make the top and bottom border lines on the textfield disappear (the dark gray ones), you will want to tweak the text field's border properties rather than the background colors. Try something like this:
searchBar.searchTextField.layer.borderWidth = 0
or
searchBar.searchTextField.layer.borderColor = UIColor.clear.cgColor
and adapt it to fit how you've set up the relevant subviews in your custom search bar.
Set the searchBar background image to empty. This eliminates all background issues you may have such as unwanted lines. For more info reference Apple docs: https://developer.apple.com/documentation/uikit/uisearchbar/1624276-backgroundimage
searchBar.backgroundImage = UIImage()
I set custom view to titleView of UINavigationBar.
When I just set the view with frame, it works fine.
However if I add any subview to a view that I set to a title view, it just does not appear.
A view added to titleView
class NavigationBarSearchBar: UIView {
let view: UIView = {
let v = UIView(frame: CGRect(x: 0, y: 0, width: 100, height: 20))
v.translatesAutoresizingMaskIntoConstraints = false
return v
}()
override init(frame: CGRect) {
super.init(frame: frame)
setupSubviews()
}
required init?(coder aDecoder: NSCoder) {
fatalError("init(coder:) has not been implemented")
}
private func setupSubviews() {
addSubview( view )
[
view.widthAnchor.constraint(equalToConstant: 20),
view.heightAnchor.constraint(equalToConstant: 20),
view.centerYAnchor.constraint(equalTo: centerYAnchor),
view.centerXAnchor.constraint(equalTo: centerXAnchor)
].forEach { $0.isActive = true }
}
}
Declaration on View Controller
private lazy var searchBar: UIView = {
let sb = NavigationBarSearchBar(frame: CGRect(x: 0, y: 0, width: CGFloat.greatestFiniteMagnitude, height: 40))
return sb
}()
Set the custom view to nav bar
navigationItem.titleView = searchBar
lazy var searchBar:UISearchBar = UISearchBar(frame: CGRectMake(0, 0, 200, 20))
searchBar.sizeToFit()
navigationItem.titleView = searchBar
Create a view with Frame and add to navigationItem
var viewTitle = UIView(frame: CGRect(x: 0, y: 0, width: 50, height: 30))
viewTitle.backgroundColor = UIColor.red
navigationItem?.titleView = viewTitle
So I have a UIBarbuttonItem that I am currently designing based off of a layout that I have done.
import Foundation
import UIKit
class LocationManager: UIBarButtonItem {
var viewController: MainViewController?
lazy var customButton : UIButton = {
let customButton = UIButton(type: .system)
customButton.setImage(UIImage(named: "downArrow"), for: .normal)
customButton.imageEdgeInsets = UIEdgeInsetsMake(0, 20, 0, -10)
guard let customFont = UIFont(name: "NoirPro-SemiBold", size: 20) else {
fatalError("""
Failed to load the "CustomFont-Light" font.
Make sure the font file is included in the project and the font name is spelled correctly.
"""
)
}
customButton.semanticContentAttribute = UIApplication.shared
.userInterfaceLayoutDirection == .rightToLeft ? .forceLeftToRight : .forceRightToLeft
customButton.titleLabel?.font = customFont
customButton.setTitleColor(UIColor.black, for: .normal)
return customButton
}()
override init() {
super.init()
setupViews()
}
#objc func setupViews(){
customView = customButton
}
required init?(coder aDecoder: NSCoder) {
fatalError("init(coder:) has not been implemented")
}
}
I correctly do the job of using both an image and title and setting the image insets for the button and on load the appearance is great. However, when I leave the screen and come back it seems as though everything is thrown out of wack the image gets moved back and sometimes there will be two images and one will have a distorted size.
Is there anything wrong with my custom button implementation that I am missing.
I have included images for before and after
I suggest you to make your custom button class, then make title and image by adding subviews. In this case UIImageView and UILabel. Because UIButton inherits from UIView you can easy do this. I've never had problems using this way.
Here is the code I've written for you:
import UIKit
class ViewController: UIViewController {
lazy var customButton: CustomButton = {
let button = CustomButton(frame: CGRect(x: 50,
y: 200,
width: view.frame.width - 100,
height: 50))
// This mask for rotation
button.autoresizingMask = [.flexibleLeftMargin,
.flexibleRightMargin,
.flexibleTopMargin,
.flexibleBottomMargin]
button.attrTitleLabel.text = "San Francisco, CA"
button.addTarget(self, action: #selector(chooseCity), for: .touchUpInside)
return button
}()
override func viewDidLoad() {
super.viewDidLoad()
view.backgroundColor = .blue
view.addSubview(customButton)
}
#objc func chooseCity() {
print("Choose city button has pressed")
}
}
class CustomButton: UIButton {
private let arrowImageSize: CGSize = CGSize(width: 20, height: 20)
private let sideOffset: CGFloat = 10
override init(frame: CGRect) {
super.init(frame: frame)
backgroundColor = .white
addSubview(attrTitleLabel)
addSubview(arrowImageView)
}
required init?(coder aDecoder: NSCoder) {
fatalError("init(coder:) has not been implemented")
}
lazy var attrTitleLabel: UILabel = {
let label = UILabel()
label.font = UIFont(name: "NoirPro-SemiBold", size: 20)
label.textColor = .black
return label
}()
lazy var arrowImageView: UIImageView = {
let iv = UIImageView()
iv.image = UIImage(named: "arrow_down")
iv.contentMode = .scaleAspectFit
return iv
}()
override func layoutSubviews() {
super.layoutSubviews()
arrowImageView.frame = CGRect(x: self.frame.width - arrowImageSize.width - sideOffset,
y: self.frame.height/2 - arrowImageSize.height/2,
width: arrowImageSize.width,
height: arrowImageSize.height)
attrTitleLabel.frame = CGRect(x: sideOffset, y: 0, width: self.frame.width - sideOffset*2 - arrowImageSize.width, height: self.frame.height)
}
}
How it looks:
please do not down vote will try my best to explain problem.
i have an InputAccessoryView which was working fine before iphone x, in iphone x my inputAssesoryView is showing at very bottom below the layoutguide. i found following solution
inputAccessoryView Iphone X
after following idea from above link i can place my textfield above the layout guid but it become unresponsive. which is happening because there is no frame size define for view of inputAccessoryView.
class ChatInputContainerView: UIView, UITextFieldDelegate {
override var intrinsicContentSize: CGSize {
return CGSize.zero
}
required init?(coder aDecoder: NSCoder) {
fatalError("init(coder:) has not been implemented")
}
lazy var inputTextField: UITextField = {
let textField = UITextField()
textField.placeholder = "Enter message..."
textField.translatesAutoresizingMaskIntoConstraints = false
textField.delegate = self
return textField
}()
override init(frame: CGRect) {
super.init(frame: frame)
autoresizingMask = .flexibleHeight
self.inputTextField.leftAnchor.constraint(equalTo: rightAnchor, constant: 8).isActive = true
self.inputTextField.bottomAnchor.constraint(equalTo: layoutMarginsGuide.bottomAnchor).isActive = true
self.inputTextField.rightAnchor.constraint(equalTo: leftAnchor).isActive = true
self.inputTextField.heightAnchor.constraint(equalTo: heightAnchor).isActive = true
}
}
following is controller where i am using inputAccessory View
class chatController: UITextFieldDelegate {
override func viewDidLoad() {
super.viewDidLoad()
}
lazy var inputContainerView: ChatInputContainerView = {
// let chatInputContainerView = ChatInputContainerView(frame: CGRect(x: 0, y: 0, width: self.view.frame.width, height: 50))
let chatInputContainerView = ChatInputContainerView()
chatInputContainerView.chatLogController = self
return chatInputContainerView
}()
override var inputAccessoryView: UIView? {
get {
return inputContainerView
}
}
override var canBecomeFirstResponder : Bool {
return true
}
}
previously i was using following code to get size of InputAccessoryView which place the view at the bottom with fix height.
let chatInputContainerView = ChatInputContainerView(frame: CGRect(x: 0, y: 0, width: self.view.frame.width, height: 50))
but now i am using following to set inputAccessoryView which is not working properly, textfield inside view become unresponsive because parent view have no size define.
override var intrinsicContentSize: CGSize {
return CGSize.zero
}
autoresizingMask = .flexibleHeight
in following image you can see all my control are now above the safeAreaLayout but they become unresponsive.
sample image
let me know if you do not understand. please help thank you in advance.
Try adding a top anchor to your 'inputTextField'
self.inputTextField.topAnchor.constraint(equalTo: topAnchor).isActive = true
I might be wrong but without knowing where the top is the 'ChatInputContainerView' will have zero height.
I've added a search bar to my navigation.titleView
self.navigationItem.titleView = searchBar
There's also a BackBarButtonItem with title = ""
self.navigationItem.backBarButtonItem?.title = ""
But then there're gap between Back Button and SearchBar, like this:
I Think that the gap appears here because there's space for title of backBarButtonItem (because my title is null "" but the space still there)
So I want to ask how to omit that gap? I want to make my searchBar nearer my backBarIcon
Thank you so much!
EDIT 1:
I try to change searchBar's frame but it's not working
This is my code
//Change searchBar's frame
let titleViewFrame = (searchController.searchBar.frame)
searchController.searchBar.frame = CGRect(x: titleViewFrame.minX - 20.0, y: titleViewFrame.minY, width: titleViewFrame.width + 20.0, height: titleViewFrame.height)
override func viewDidLoad() {
super.viewDidLoad()
let container = UIView(frame: CGRect(x: 0, y: 0, width: 1000, height: 22))
let searchBar = UISearchBar()
searchBar.translatesAutoresizingMaskIntoConstraints = false
container.addSubview(searchBar)
let leftButtonWidth: CGFloat = 35 // left padding
let rightButtonWidth: CGFloat = 75 // right padding
let width = view.frame.width - leftButtonWidth - rightButtonWidth
let offset = (rightButtonWidth - leftButtonWidth) / 2
NSLayoutConstraint.activate([
searchBar.topAnchor.constraint(equalTo: container.topAnchor),
searchBar.bottomAnchor.constraint(equalTo: container.bottomAnchor),
searchBar.centerXAnchor.constraint(equalTo: container.centerXAnchor, constant: -offset),
searchBar.widthAnchor.constraint(equalToConstant: width)
])
self.navigationItem.titleView = container
}
You can't do that, there is a default space given which we cannot change if we have back button.
self.navigationItem.backBarButtonItem = UIBarButtonItem(title: "", style: .plain, target: nil, action: nil)
self.navigationController?.navigationBar.backIndicatorImage = UIImage(named: "back")
self.navigationController?.navigationBar.backIndicatorTransitionMaskImage = UIImage(named: "back")
self.navigationController?.navigationBar.tintColor = UIColor.lightGray
Below is the screenshot
class SearchBarContainerView: UIView {
let searchBar: UISearchBar
init(customSearchBar: UISearchBar) {
searchBar = customSearchBar
super.init(frame: CGRect.zero)
addSubview(searchBar)
}
override convenience init(frame: CGRect) {
self.init(customSearchBar: UISearchBar())
self.frame = frame
}
required init?(coder aDecoder: NSCoder) {
fatalError("init(coder:) has not been implemented")
}
override func layoutSubviews() {
super.layoutSubviews()
searchBar.frame = bounds
}
}
class MyViewController: UIViewController {
func setupNavigationBar() {
let searchBar = UISearchBar()
let searchBarContainer = SearchBarContainerView(customSearchBar: searchBar)
searchBarContainer.frame = CGRect(x: 0, y: 0, width: view.frame.width, height: 44)
navigationItem.titleView = searchBarContainer
}
}