iOS Keyboard - Capitalise 'done' button - ios

I am using 'UIKeyboardTypeDefault' keyboard type for my UITextfields.
The done button for the keyboard appears in lowercase as 'done'.
Is there anyway to make this a capitalised as 'Done' ?

You can try using the POD - > IQKeyboardManagerSwift
LINK -->
pod 'IQKeyboardManagerSwift', :git =>
'https://github.com/hackiftekhar/IQKeyboardManager.git'
This is very useful pod for handling stuff for keyboard

We cannot set a custom text for the return key, we can only select from the available options (refer attached screenshot).
In order to set a custom text, for e.g capitalised 'done' button, you will have to create a custom keyboard. attached screenshot

I've been struggling with the same question for tvOS for the last day or so, and figured out the solution is to get the 'to' viewController of the presented keyboard, iterate over its view hierarchy to find the button, then grab its text, capitalise it, and set it back.
Ended up with the following function:
fileprivate func CapitaliseReturnKey() {
let scene = UIApplication.shared.connectedScenes.first
guard
let windowSceneDelegate = scene?.delegate as? UIWindowSceneDelegate,
let window = windowSceneDelegate.window,
// This gets the presented keyboard view, which is the 'to' view for the presentation transition.
let keyboardView = window?.rootViewController?.transitionCoordinator?.view(forKey: .to)
else {
return
}
capitaliseReturnKey(in: keyboardView)
/// Traverses the view heirarchy of the passed-in view looking for a UIButton and capitalises its title.
/// - Parameter view: the view to iterate over
func capitaliseReturnKey(in view: UIView) {
for subView in view.subviews {
if subView.subviews.count > 0 {
capitaliseReturnKey(in: subView)
}
if subView.isKind(of: UIButton.self) {
if let buttonView = subView as? UIButton {
buttonView.setTitle(buttonView.currentTitle?.localizedCapitalized, for: .normal)
}
}
}
}

Related

macOS - Is there a way to know which textfield triggered performKeyEquivalent?

I have created a subclass of NSView and assigned that to the main ViewController's view.
I have two NSTableViews on that view. These subviews have NSTextFields.
I start editing one of these text fields and press Cmd C.
performKeyEquivalent is triggered.
How do I know which text field triggered it?
I haved added this line
override func performKeyEquivalent(with event: NSEvent) -> Bool {
super.performKeyEquivalent(with:event)
let firstResponder = self.window?.firstResponder
but as expected it does not helper.
macOS tells me that firstResponder is a NSTextView, but I have no text view on the project.
tag does not helper either. I have the cells of my tableViews with tags equal to 100, 200, and 300 but
let tag = (firstResponder! as! NSTextView).tag
gives me -1 (?)
any ideas?
NSTextField is a delegate of own editor, which is NSTextView, so here how it should go
override func performKeyEquivalent(with event: NSEvent) -> Bool {
if let editor = self.window?.firstResponder as? NSTextView,
let textField = editor.delegate as? NSTextField {
print("Identified by: \(textField.tag)")
}
return super.performKeyEquivalent(with:event)
}

Increase the height of UINavigationBarLargeTitleView

I want to add a banner to the navigation bar, but by increasing the height of it. I want to copy the design and behaviour of an artist page in the Apple Music app:
It behaves just like a normal Large Title would, except for that it has been moved down, it has a sticky UIImageView behind it and it returns its background when the user scrolls down far enough. You can fire up Apple Music, search for an artist and go to their page to try it out yourself.
I've tried a bunch of things like setting the frame on the UINavigationBarLargeTitleView, and the code from this answer: https://stackoverflow.com/a/49326161/5544222
I already got a hold of the UINavigationBarLargeTitleView and its UILabel using the following code:
func setLargeTitleHeight() {
if let largeTitleView = self.getLargeTitleView() {
if let largeTitleLabel = self.getLargeTitleLabel(largeTitleView: largeTitleView) {
// Set largeTitleView height.
}
}
}
func getLargeTitleView() -> UIView? {
for subview in self.navigationBar.subviews {
if NSStringFromClass(subview.classForCoder).contains("UINavigationBarLargeTitleView") {
return subview
}
}
return nil
}
func getLargeTitleLabel(largeTitleView: UIView) -> UILabel? {
for subview in largeTitleView.subviews {
if subview.isMember(of: UILabel.self) {
return (subview as! UILabel)
}
}
return nil
}
Initially put a view with image and label and play button. Then clear the navigation bar it will show the image below it by
self.navigationController!.navigationBar.setBackgroundImage(UIImage(), for: .default)
self.navigationController!.navigationBar.shadowImage = UIImage()
self.navigationController!.navigationBar.isTranslucent = true
later when you scroll up you have to handle it manually and again show the
navigation with title.

customize swipe delete button in swift4

I have customize Swipe delete button till swift3 [ios 9].
I have tried this code for ios 9 in swift3
func setSwipeDeletebutton(cell : UITableViewCell, BackView : UIView) {
//Customize Delete button
for subview in cell.subviews {
subview.backgroundColor = UIColor.clear
for sub in subview.subviews {
if String(describing: sub).range(of: "UITableViewCellActionButton") != nil {
sub.backgroundColor = UIColor.white
var newframe = sub.frame
newframe.size.height = BackView.frame.size.height
sub.frame = newframe
sub.SetUpView()
for view in sub.subviews {
if String(describing: view).range(of: "UIButtonLabel") != nil {
if let label = view as? UILabel {
label.textColor = SharedInstance.hexStringToUIColor(hex: Color.TodayActivityColor.Type_LEAVE)
}
}
}
}
}
}
}
Now, as a change in ios 11, I can not customize swipe delete button using this code.
I have tried to set image as swipe delete button, but it's not set properly because I also want shadow to that delete button.
Can anyone suggest that how can I customize the swipe delete button using swift4?
You are accessing subviews by using:
String(describing: sub).range(of: "UITableViewCellActionButton")
And
String(describing: view).range(of: "UIButtonLabel")
This is not advisable by apple.
However, to debug this issue open your view hierarchy while the table view row action / drawer is open.
You should see the view you wish to alter, in the hierarchy.
Then change your Strings as required:
String(describing: sub).range(of: "UISwipeActionPullView")
UISwipeActionPullView may not be what you need but the concept is the same.

Slide UIInputView with UIViewController like Slack

I'd like to use the UIViewController's input accessory view like this:
override func canBecomeFirstResponder() -> Bool {
return true
}
override var inputAccessoryView: UIView! {
return self.bar
}
but the issue is that I have a drawer like view and when I slide the view open, the input view stays on the window. How can I keep the input view on the center view like Slack does it.
Where my input view stays at the bottom, taking up the full screen (the red is the input view in the image below):
There are two ways to do this exactly like Slack doing it, Meiwin has a medium post here A Stickler for Details: Implementing Sticky Input Field in iOS to show how he managed to do this which he actually puts an empty UIView as an inputAccessoryView then track it’s coordinates on screen to know where to put his custom view in relation with the empty view, this way can be helpful if you are going to support SplitViewController on iPad, but if you are not interested in this way, you can see how I managed to do this like this image
Here is before swiping
Here is after
All I did was actually taking a snapshot from the inputAccessoryView window and putting it on the NavigationController of the TableViewController
I am using SideMenu from Jon Kent and it’s pretty easy to do it with the UISideMenuNavigationControllerDelegate
var isInputAccessoryViewEnabled = true {
didSet {
self.inputAccessoryView?.isHidden = !self.isInputAccessoryViewEnabled
if self.isInputAccessoryViewEnabled {self.becomeFirstResponder()}
}
}
func sideMenuWillAppear(menu: UISideMenuNavigationController, animated: Bool) {
let inputWindow = UIApplication.shared.windows.filter({$0.className == "UITextEffectsWindow"}).first
self.inputAccessoryViewSnapShot = inputWindow?.snapshotView(afterScreenUpdates: false)
if let snapShotView = self.inputAccessoryViewSnapShot, let navView = self.navigationController?.view {
navView.addSubview(snapShotView)
}
self.isInputAccessoryViewEnabled = false
}
func sideMenuDidDisappear(menu: UISideMenuNavigationController, animated: Bool) {
self.inputAccessoryViewSnapShot?.removeFromSuperview()
self.isInputAccessoryViewEnabled = true
}
I hope that helps :)

How to loop through all UIButtons in my Swift view?

How would I loop through all UIButtons in my view in Swift? I would want to set all the titles to "", but my for-loop in Swift is giving an error.
for btns in self.view as [UIButton] {
// set the title to ""
}
This code should work:
for view in self.view.subviews as [UIView] {
if let btn = view as? UIButton {
btn.setTitleForAllStates("")
}
}
You need to iterate through the subViews array.
Shortened and updated for Swift 3 & 4
for case let button as UIButton in self.view.subviews {
button.setTitleForAllStates("")
}
Looping over subview works, but it's sometimes a little ugly, and has other issues.
If you need to loop over some specific buttons, for example to add corner radius or change tint or background color, you can use an array of IBOutlets and then loop over that.
var buttons = [SkipBtn, AllowBtn]
for button in buttons as! [UIButton] {
button.layer.cornerRadius = 5
}
Swift 4:
let subviewButtons = self.view.subviews.filter({$0.isKind(of: UIButton.self)})
for button in subviewButtons {
//do something
}
To add some context for a common use case, suppose the buttons were in a scroll view and you wanted to highlight the tapped button and de-highlight the other buttons. In this situation, you would direct all buttons to one action method:
#objc private func buttonAction(_ button: UIButton) {
for case let b as UIButton in view.scrollView.subviews {
if b == button {
b.setTitleColor(UIColor.green, for: []) // highlight
} else {
b.setTitleColor(UIColor.black, for: []) // de-highlight
}
}
}
This code seems to be quite useful for iterating over any object within a view, just change UIButton for any other subview type such as UIView or UIImageView, etc.
let filteredSubviews = self.view.subviews.filter({
$0.isKindOfClass(UIButton)})
for view in filteredSubviews {
//Do something
}
Used some of the offered questions out there and created my own. I believe is the most efficient when you want to programmatically set up the title of various UIButtons(in my case I am building a quiz)
By randomising my array list and with just a for loop I printing the item at index to the button title
for view in self.viewForButtons.subviews{
if view.isKindOfClass(UIButton)
{
let button : UIButton = view as! UIButton
button.setTitle("item[i]", forState: .Normal)
}
}
If you have UIView's within self.view then you need to loop through the subviews while searching for UIButton. Using the accepted answer, I made this little function to do so:
Swift 4 + :
func findButton(`in` view: UIView){
for view in view.subviews as [UIView] {
if let button = view as? UIButton {
// Do something with 'button'
}else{
// Loop through subview looking for buttons
findButton(in: view)
}
}
}
Usage:
override func viewDidLoad() {
findButton(in: self.view)
}
Hope this helps!
Here's a short way in Swift if you know the subview only has buttons:
myView.subviews.map {
($0 as? UIButton)!.enabled = false
}

Resources