What is the best way to align right bar button items with left title in UINavigationBar ?
(now I have the icons at the top right corner)
maybe there is a more correct and optimal solution, but it is suitable for me.
Do not be alarmed by the syntax, I use SnapKit
Create button or view
lazy private var settingsButton = UIButton().then {
$0.setImage(Image.settings, for: .normal)
}
override viewDidAppear(_ animated: Bool)
navigationController?.navigationBar.subviews.forEach { subview in
let stringFromClass = NSStringFromClass(subview.classForCoder)
guard stringFromClass.contains("UINavigationBarLargeTitleView") else { return }
subview.subviews.forEach { label in
guard label is UILabel else { return }
subview.addSubview(settingsButton)
settingsButton.snp.makeConstraints{
$0.top.equalTo(label)
$0.right.equalToSuperview().offset(-14)
$0.height.width.equalTo(35)
}
}
}
set UIScrollViewDelegate and in scrollViewDidScroll method get ahead of the navigationBar state and then hide / show the UIBarButtonItem
Result
screenshot
when launching the iOS share extension the textView will by default already be selected / entered. (the keyboard will be visible and the textView will be in edit mode)
I don't want this to happen, how do I programatically exit the textView
override func viewDidLoad() {
self.textView.exit() // obviously doesn't work
}
I see tons of posts about how to exit when user press enter on the keyboard, I do not want to do it "when something delegate" I just want the textview to not be in edit mode when the extension is launched (on viewDidLoad).
I have also tried (as suggested in other post)
self.textView.endEditing(true)
which did not hide the keyboard or exit the textView
You can call textView.resignFirstResponder() in presentationAnimationDidFinish
class ShareViewController: SLComposeServiceViewController {
var textViewTintColor: UIColor?
override func viewDidLoad() {
super.viewDidLoad()
// hide cursor which appears during presentation animation
self.textViewTintColor = self.textView.tintColor
self.textView.tintColor = .clear
}
override func presentationAnimationDidFinish() {
super.presentationAnimationDidFinish()
guard let tintColor = self.textViewTintColor else { return }
self.textView.resignFirstResponder()
// reset cursor
self.textView.tintColor = tintColor
self.textViewTintColor = nil
}
}
I want to change the place where the cancel button appears instead of appearing on the right side as in the image I want it to appear on the left side of the search bar.
You cannot change the position of the default SearchBar and Search Display controller.
For your requirement, you need to create your own custom Search Bar with Cancel as you desire.
Hope it helps..
One way to put the cancel button on the left is to override the effectiveUserInterfaceLayoutDirection of the Search Bar (iOS 10+).
final class CustomSearchController: UISearchController {
private var customSearchBar = CustomSearchBar()
override var searchBar: UISearchBar { customSearchBar }
}
final class CustomSearchBar: UISearchBar {
override var effectiveUserInterfaceLayoutDirection: UIUserInterfaceLayoutDirection {
// Overriding this property swaps the layout at the top level without swapping the layout for the subviews
super.effectiveUserInterfaceLayoutDirection.flipped
}
override func willMove(toSuperview newSuperview: UIView?) {
super.willMove(toSuperview: newSuperview)
// Set and unset the semanticContentAttribute so the effectiveUserInterfaceLayoutDirection is reevaluated.
semanticContentAttribute = .forceLeftToRight
semanticContentAttribute = .unspecified
}
}
extension UIUserInterfaceLayoutDirection {
var flipped: UIUserInterfaceLayoutDirection {
switch self {
case .rightToLeft: return .leftToRight
case .leftToRight: return .rightToLeft
#unknown default: return .rightToLeft
}
}
}
This should put the cancel button on the left for LTR languages, and on the right for RTL languages.
Result in English:
I want to add a button (bar) inside a UISearchbar and another one just outside the UISearchbar as shown in the image. Any help on this appreciated.
Thanks in advance
Naveen
Edit :
As stated by #NicolasMiari in the comments :
This no longer works post-iOS 7, since the bookmarks button is rendered inside the bar's input text field.
For the button inside the search bar, you can use the bookmark button and change its image. You simply go to your storyboard (if you use one), select the search bar, and activate the option "Shows Bookmarks Button". Then, in your code, set the image you want :
[_searchBar setImage:[UIImage imageNamed:#"My-Custom-Image"] forSearchBarIcon:UISearchBarIconBookmark state:UIControlStateNormal];
You can detect a click on this button with the following delegate method :
- (void)searchBarBookmarkButtonClicked:(UISearchBar *)searchBar {
NSLog(#"click");
}
Swift 4
class ViewController: UIViewController {
var searchController = UISearchController(searchResultsController: nil)
override func viewDidLoad() {
searchController.delegate = self
searchController.searchBar.delegate = self
searchController.searchBar.showsBookmarkButton = true
searchController.searchBar.setImage(UIImage(named: "myImage"), for: .bookmark, state: .normal)
}
}
extension ViewController: UISearchBarDelegate {
func searchBarBookmarkButtonClicked(_ searchBar: UISearchBar) {
print("click")
}
}
The fastest way to add a button in UISearchBar is to update the bookmark button like this:
[self.searchDisplayController.searchBar setImage:[UIImage imageNamed:#"customImage.png"] forSearchBarIcon:UISearchBarIconBookmark state:UIControlStateNormal];
If you need to adjust the offset,
[self.searchDisplayController.searchBar setPositionAdjustment:UIOffsetMake(-10, 0) forSearchBarIcon:UISearchBarIconBookmark];
Don't forget to activate the option "Shows Bookmarks Button" in story board.
I would like to know how to hide or not display the UISearchBar cross that appears in the textField fo the UISearchBar
I have tried using this
filterSearchBar.showsCancelButton = NO;
However this is an actual cancel button not the small grey cross, so I would like to know if there is an equivalent for the small grey button that shows in the UISearchBar.
You need to get the textField of the Search Bar:
UITextField *textField = [searchBar valueForKey:#"_searchField"];
textField.clearButtonMode = UITextFieldViewModeNever;
hope this help! =)
There's a better way to do this, and you don't have to use private APIs or traverse subviews to do it, so this solution is App Store safe.
UISearchBar has a built-in API for doing this:
[UISearchBar setImage:forSearchBarIcon:state]
The SearchBar icon key you want is UISearchBarIconClear, and you want the UIControlStateNormal state. Then give it a clear image for the image, and you're done.
So, it should look like this:
[searchBar setImage:clearImage forSearchBarIcon:UISearchBarIconClear state:UIControlStateNormal];
Swift 4
Adding to Alexander's answer and block user interaction on clear button:
To hide button:
searchBar.setImage(UIImage(), for: .clear, state: .normal)
To disable user interaction on the clear button, simply subclass UISearchBar
class CustomSearchBar: UISearchBar {
override func hitTest(_ point: CGPoint, with event: UIEvent?) -> UIView? {
let view = super.hitTest(point, with: event)
if view is UIButton {
return view?.superview // this will pass-through all touches that would've been sent to the button
}
return view
}
}
Based on #Gines answer, here is the Swift version:
func searchBarTextDidBeginEditing(searchBar: UISearchBar) {
guard let firstSubview = searchBar.subviews.first else { return }
firstSubview.subviews.forEach {
($0 as? UITextField)?.clearButtonMode = .never
}
}
Swift 5
Tested on iOS 13
One liner working for me:
searchBar.searchTextField.clearButtonMode = .never
You can also set it to .whileEditing to have it displayed when the user is typing and then removed when the search bar loses focus.
Swift 3, based on #Alexsander answer:
searchBar.setImage(UIImage(), for: .clear, state: .normal)
You can remove the clear text button for all UISearchBar instances:
[UITextField appearanceWhenContainedInInstancesOfClasses:#[[UISearchBar class]]].clearButtonMode = UITextFieldViewModeNever;
Swift 5
Just add a single line below
searchBar.searchTextField.clearButtonMode = .never
Swift 3 solution :
extension UISearchBar{
var textField : UITextField{
return self.value(forKey: "_searchField") as! UITextField
}
}
Usage :
searchBar.textField.clearButtonMode = .never
I tried different solutions about this issue, even the one selected in this post, but they didn't work.
This is the way I found to solve this issue:
UIView *subview = [[searchBar subviews] firstObject]; //SearchBar only have one subview (UIView)
//There are three sub subviews (UISearchBarBackground, UINavigationButton, UISearchBarTextField)
for (UIView *subsubview in subview.subviews)
{
//The UISearchBarTextField class is a UITextField. We can't use UISearchBarTextField directly here.
if ([subsubview isKindOfClass: [UITextField class]])
{
[(UITextField *)subsubview setClearButtonMode:UITextFieldViewModeNever];
}
}
Try this:
- (void)searchBar:(UISearchBar *)searchBar textDidChange:(NSString *)searchText {
UITextField *textField = [searchBar valueForKey:#"_searchField"];
textField.clearButtonMode = UITextFieldViewModeNever;
}
In Case of Swift 2.3 just use :
var searchBar = UISearchBar();
searchBar.frame = CGRectMake(0, 0, 00, 20))
for subview: UIView in (searchBar.subviews.first?.subviews)!
{
if (subview.isKindOfClass(UITextField) )
{
let textFieldObject = (subview as! UITextField)
textFieldObject.clearButtonMode = .Never;
}
}
Swift 2.3, based on #Alexsander answer:
searchBar.setImage(UIImage(named: "SearchClearIcon"), forSearchBarIcon: UISearchBarIcon.Clear, state: UIControlState.Highlighted)
searchBar.setImage(UIImage(named: "SearchClearIcon"), forSearchBarIcon: UISearchBarIcon.Clear, state: UIControlState.Normal)
Converting Soto_iGhost's answer to Swift 4:
func searchBarTextDidBeginEditing(_ searchBar: UISearchBar) {
let textField: UITextField = searchBar.value(forKey: "_searchField") as! UITextField
textField.clearButtonMode = .never
}
If you have an outlet of UISearchBar the you can write above code anywhere in your class.
thijsonline's answer in swift:
(UITextField.appearance(whenContainedInInstancesOf: [UISearchBar.self])).clearButtonMode = .never