resignFirstResponder is not working as expected.the key board pop's down for every key press rather than for return only - swift

i have 3 UITextField. when i set the resignFirstResponder for the text field, for every key press the key board goes down and key board pops up when we enter. which means for each letter pressed the key board disappears
I tried creating an outlet for the text field as below but the print statement is executed but the key board is not getting disappeared when focus lost or moved to the next text field
#IBAction func done(_ sender: UITextField) {
print("Text field done$$$$$$$$$$$$$$$")
sender.endEditing(true)
sender.resignFirstResponder()
// print("After Resign")
}
tried the below one also:
self.view.addGestureRecognizer(UITapGestureRecognizer(target: self.view, action: #selector(UIView.endEditing(_:))))
override func viewDidLayoutSubviews() {
super.viewDidLayoutSubviews()
//Textfield
let textfield = UITextField()
textfield.setShadowTextField(username, "user-name")
textfield.setShadowTextField(useremail, "email")
textfield.setShadowTextField(userPhone, "phone")
//Hide Keyboard
textName.resignFirstResponder()
textEmail.resignFirstResponder()
userPhone.resignFirstResponder()
//
name = textName.text ?? ""
emailphone = textEmail.text ?? ""
//Button
if isFirstTimeSubView == true {
button?.setSemiButtonLeft(btnFemaleSelector, shadowViewFemale)
button?.setGradientButton(btnFemaleSelector, startColor: "0d5e90", endColor: "8ec67d")
button?.setSemiButtonRight(btnMaleSelector, shadowViewMale)
button?.setGradientButton(btnMaleSelector, startColor: "FFFFFF", endColor: "FFFFFF")
isFirstTimeSubView = false
}
button?.setRoundButton(btnSubmit, shadowView)
button?.setGradientButton(btnSubmit, startColor: "0d5e90", endColor: "8ec67d")
//textNam.sendAction("resignFirstResponder", to:nil, from:nil, forEvent:nil)
// self.userText.delegate = selftextName.resignFirstResponder()
}
extension UITextField {
func setShadowTextField(_ textfield: UITextField?, _ imagename: String?) {
// set color & border
textfield?.borderStyle = .none
textfield?.backgroundColor = UIColor.white
// set corner
textfield?.layer.cornerRadius = (textfield?.frame.size.height ?? 0.0) / 2
//set shadow
textfield?.layer.shadowOpacity = 0.4
textfield?.layer.shadowRadius = 15
textfield?.layer.shadowOffset = CGSize(width: 5, height: 10)
textfield?.layer.shadowColor = UIColor.gray.cgColor
// set icon & Placeholder position
let UIViewController = UIView(frame: CGRect(x: 0, y: 0, width: 60, height: textfield?.frame.size.height ?? 0.0))
let icon = UIImageView(image: UIImage(named: imagename ?? ""))
icon.frame = CGRect(x: 0, y: 0, width: UIViewController.frame.size.width / 4, height: UIViewController.frame.size.height / 4)
icon.center = UIViewController.center
UIViewController.addSubview(icon)
textfield?.leftView = UIViewController
textfield?.leftViewMode = .always
}
}

The question is a little unclear but if you want the keyboard to go down when you've pressed the done button, you should implement the UITextFieldDelegate on your view controller and during the textFieldShouldReturn(_:) method call resignFirstResponder from there:
class myVC: UIViewController, UITextFieldDelegate{
func textFieldShouldReturn(_ textField: UITextField) -> Bool{
return true
}
}
and don't forget to set the delegate in the viewDidLoad for your VC:
override func viewDidLoad() {
super.viewDidLoad()
/// Text field delegate handling
textFieldFirstName.delegate = self
}
https://developer.apple.com/documentation/uikit/uitextfielddelegate/1619603-textfieldshouldreturn?language=objc
By calling resignFirstResponder in viewDidLayoutSubviews, you are resigning the responder every time the viewDidLayoutSubviews is called, i.e. When the bounds change for a view controller's view, the view adjusts the positions of its subviews and then the system calls this method. So I presume the keyboard will be changing the bounds, causing viewDidLayoutSubviews to fire after each keypress and creating the behaviour you are seeing

Related

Why does my function to adjust view according to keyboard height behave erratically?

I am trying to re-create a Facebook sign up page for practice; the set up of my viewController is as follows:
1)A profile image container at the top,
2)Email textfield
3)Password Textfield
4)Confirm Password textfield
To solve the issue of the keyboard blocking the "Confirm Password" field, I have used listeners as below.
The issue is that the very first time a user clicks on a textfield to type (no matter which one), the screen moves way too far up, such that the email textfield at the top ends up going beyond the screen size on top. However, when I dismiss the keyboard and re-click on any textfield, it goes up as intended: Only until the top textfield reaches the top of the screen.
I can find no other reason for this behaviour, it persisted even after I re-wrote some of my code.
My ViewController set up:
class ViewController: UIViewController {
#objc func dismissKeyboard() {
view.endEditing(true)
}
let imageContainer: UIView = {
let v = UIView()
v.translatesAutoresizingMaskIntoConstraints = false
v.backgroundColor = .red
return v
}()
let emailTF: UITextField = {
let tf = UITextField()
tf.translatesAutoresizingMaskIntoConstraints = false
tf.placeholder = "EMAIL"
return tf
}()
let passwordTF: UITextField = {
let tf = UITextField()
tf.translatesAutoresizingMaskIntoConstraints = false
tf.placeholder = "Password"
return tf
}()
let confirmPasswordTF: UITextField = {
let tf = UITextField()
tf.translatesAutoresizingMaskIntoConstraints = false
tf.placeholder = "Confirm password"
return tf
}()
#objc func keyboardWillShow(notification: NSNotification) {
if let keyboardSize = (notification.userInfo?[UIResponder.keyboardFrameBeginUserInfoKey] as? NSValue)?.cgRectValue {
if self.view.frame.origin.y == 0 {
self.view.frame.origin.y -= keyboardSize.height
}
}
}
#objc func keyboardWillHide(notification: NSNotification) {
if self.view.frame.origin.y != 0 {
self.view.frame.origin.y = 0
}
}
override func viewDidLoad() {
super.viewDidLoad()
view.backgroundColor = .lightGray
NotificationCenter.default.addObserver(self, selector: #selector(keyboardWillShow), name: UIResponder.keyboardWillShowNotification, object: nil)
NotificationCenter.default.addObserver(self, selector: #selector(keyboardWillHide), name: UIResponder.keyboardWillHideNotification, object: nil)
view.addSubview(imageContainer)
view.addSubview(emailTF)
view.addSubview(passwordTF)
view.addSubview(confirmPasswordTF)
NSLayoutConstraint.activate([
imageContainer.centerXAnchor.constraint(equalTo: view.centerXAnchor),
imageContainer.heightAnchor.constraint(equalTo: view.heightAnchor, multiplier: 0.275),
imageContainer.widthAnchor.constraint(equalTo: view.heightAnchor),
imageContainer.topAnchor.constraint(equalTo: view.safeAreaLayoutGuide.topAnchor),
emailTF.topAnchor.constraint(equalTo: imageContainer.bottomAnchor),
emailTF.heightAnchor.constraint(equalToConstant: 100),
emailTF.widthAnchor.constraint(equalToConstant: 200),
emailTF.centerXAnchor.constraint(equalTo: view.centerXAnchor),
passwordTF.topAnchor.constraint(equalTo: emailTF.bottomAnchor, constant: 20),
passwordTF.heightAnchor.constraint(equalToConstant: 100),
passwordTF.widthAnchor.constraint(equalToConstant: 200),
passwordTF.centerXAnchor.constraint(equalTo: view.centerXAnchor),
confirmPasswordTF.topAnchor.constraint(equalTo: passwordTF.bottomAnchor, constant: 20),
confirmPasswordTF.heightAnchor.constraint(equalToConstant: 100),
confirmPasswordTF.widthAnchor.constraint(equalToConstant: 200),
confirmPasswordTF.centerXAnchor.constraint(equalTo: view.centerXAnchor),
])
let tapToDismissKeyboard: UITapGestureRecognizer = UITapGestureRecognizer(target: self, action: #selector(self.dismissKeyboard))
view.addGestureRecognizer(tapToDismissKeyboard)
}
}
I'd really appreciate some help as to what I can do to correct this issue.
Seems like this is a known issue raised here and other SO questions too..
Two points to make:-
1) Use UIResponder.keyboardFrameEndUserInfoKey instead of UIResponder.keyboardFrameBeginUserInfoKey at:
if let keyboardSize = (notification.userInfo?[UIResponder.keyboardFrameBeginUserInfoKey] as? NSValue)?.cgRectValue {
in keyboardWillShow()
2) Doing so, you will get the total height of the keyboard including the toolbar. Which means:
However, when I dismiss the keyboard and re-click on any textfield, it
goes up as intended: Only until the top textfield reaches the top of
the screen.
This is the buggy behaviour where you get an incorrect height excluding the toolbar and:
The issue is that the very first time a user clicks on a textfield to
type (no matter which one), the screen moves way too far up, such that
the email textfield at the top ends up going beyond the screen size on
top.
This is actually the intended behaviour with actual height. You could calculate the height of the toolbar and reduce it from this height to achieve your goal! If your VC is embedded in a navigation controller, you could use this
Hope this helps.

How to hide keyboard on return key in Sprite kit?

I'm using UITextField for user to enter his name. And this is how I add UITextField to the game.
let firstPlayer:UITextField = UITextField()
firstPlayer.frame = CGRect(origin: CGPoint(x: (self.scene?.size.width)! * 0.21, y: (self.scene?.size.height)! * 0.2), size: CGSize(width: 200, height: 30))
firstPlayer.placeholder = "First Player Name"
firstPlayer.backgroundColor = UIColor.lightGray
firstPlayer.autocorrectionType = UITextAutocorrectionType.no
firstPlayer.keyboardType = UIKeyboardType.default
firstPlayer.keyboardAppearance = UIKeyboardAppearance.default
firstPlayer.delegate = self as? UITextFieldDelegate
firstPlayer.isHidden = true
view.addSubview(firstPlayer)
later i unhide the textfield before it's needed. when I press on textfield in simulator the keyboard pops up. But when I press Return nothing happens.
I searched about this for sprite kit but found everything about uikit. I tried adding
func textFieldShouldReturn(_textField: UITextField) -> Bool {
self.view.endEditing(true); // or resignFirstResponder
return false;
}
to the GameViewController or in it's viewDidLoad or willLayoutSubviews but nothing worked.
I can't understand how it would be done in sprite kit.
Any Help will be really Appreciated Thanks.
The line:
firstPlayer.delegate = self as? UITextFieldDelegate
should just be:
firstPlayer.delegate = self
The fact that you added the as? UITextFieldDelegate probably means that you forgot to indicate that your class conforms to UITextFieldDelegate.
Update your class declaration from something like:
class MyViewController: UIViewController {
to something like:
class MyViewController: UIViewController, UITextFieldDelegate {
Just add the , UITextFieldDelegate to whatever your current declaration is.
You also have a typo on:
func textFieldShouldReturn(_textField: UITextField) -> Bool {
That needs to be:
func textFieldShouldReturn(_ textField: UITextField) -> Bool {
Note the space after the _.

How to make Swift delegation work in React Native iOS App

I am trying to make a custom keyboard to replace the native iOS keyboard in my React Native app. However, I am having trouble making the Swift delegation pattern work when I connect it to React Native. Does anyone know what I can do?
I made a test app entirely in Swift (programmatically) to make sure that the custom keyboard works and the button actions register (they do). However, when I connect this working Swift keyboard to React Native, the buttons stop working. The keyboard appears normally when I click on the text input (for now, this is also made in Swift but this will change soon), but the buttons won't register at all (a print statement doesn't work).
I also tried switching from the delegate pattern to just using callbacks/functions. This time, the buttons register (print statement works), but the text input is never updated and any variable I use to hold the button values is reset.
KeyboardViewManager.swift- In the test app, this was the viewcontroller.
class KeyboardViewManager: RCTViewManager {
let textField: UITextField = UITextField(frame: CGRect(x: 80, y: 134, width: 255.00, height: 78.00));
override func view() -> UIView! {
// initialize custom keyboard
let keyboardView = Keyboard(frame: CGRect(x: 0, y: 0, width: 375, height: 440))
// the view controller will be notified by the keyboard whenever a key is tapped
keyboardView.delegate = self as? KeyboardDelegate
textField.inputView = keyboardView
return textField
}
func keyWasTapped(character: String) {
if (character == "<") {
textField.deleteBackward()
} else {
textField.insertText(character)
}
}
func closeIOSKeyboard() {
textField.endEditing(true)
}
}
The class for the custom Keyboard
protocol KeyboardDelegate: class {
func keyWasTapped(character: String)
func closeIOSKeyboard()
}
class Keyboard: UIView {
weak var delegate: KeyboardDelegate?
// MARK:- keyboard initialization
required init?(coder aDecoder: NSCoder) {
super.init(coder: aDecoder)
initializeSubviews()
}
override init(frame: CGRect) {
super.init(frame: frame)
initializeSubviews()
}
func makeButtonWithText(text:String, x:Int, y:Int, width:Int, height:Int, fontSize:CGFloat = 24, bgColor:UIColor = UIColor.clear) -> UIButton {
let myButton = UIButton(type: UIButton.ButtonType.system)
myButton.frame = CGRect(x: x, y: y, width: width, height: height)
myButton.setTitle(text, for: UIControl.State.normal)
myButton.setTitleColor(UIColor.white, for: UIControl.State.normal)
myButton.titleLabel?.font = .systemFont(ofSize: fontSize)
myButton.backgroundColor = bgColor
myButton.addTarget(self,
action: #selector(keyTapped),
for: .allEvents
)
return myButton
}
func initializeSubviews() {
let view = UIView()
view.backgroundColor = UIColor(red: 42/255, green: 41/255, blue: 39/255, alpha: 1)
view.addSubview(makeButtonWithText(text: "1",x: 40,y: 40,width: 85,height: 37))
// similar code for other buttons here
view.addSubview(makeButtonWithText(text: "OK",x: 0,y: 340,width: 375,height: 50,
fontSize: 15, bgColor: UIColor(red: 15/255, green: 154/255, blue: 142/255, alpha: 1)
))
self.addSubview(view)
view.frame = self.bounds
}
#objc
#IBAction func keyTapped(sender: UIButton) {
KeyboardViewManager().keyTapped(sender: sender, character: sender.titleLabel!.text!)
// When a button is tapped, send that information to the
// delegate (ie, the view controller)
self.delegate?.keyWasTapped(character: sender.titleLabel!.text!)
}
#objc
#IBAction func closeKeyboard(sender: UIButton) {
// When a ok is tapped, close the keyboard
self.delegate?.closeIOSKeyboard()
}
}
Note: I feel like the issue may have something to do with using RCTViewManager instead of viewController to manipulate a UIView. Unfortunately, I'm new to Swift and React Native, and I'm not quite sure how RCTViewManager works!
I expect the text input to be updated each time a button is clicked on the keyboard. Instead, when the buttons are clicked, nothing happens. Fortunately, the keyboard does appear with the correct stylings.
Edit: Here is sample code for my React-Native App (not my actual app, but it's an example of how I'm connecting between Swift and React Native)
import React, {Fragment} from 'react';
import {
View,
requireNativeComponent,
} from 'react-native';
const CustomKeyboard = requireNativeComponent("KeyboardView");
import {
Header,
LearnMoreLinks,
Colors,
DebugInstructions,
ReloadInstructions,
} from 'react-native/Libraries/NewAppScreen';
const App = () => {
return (
<View style={{flex: 1, alignItems: "stretch"}}>
<CustomKeyboard style={{flex: 1, alignItems: "center", justifyContent: "center", position: 'relative', top: -100}}/>
</View>
);

UISlider not updating values

apologies if this is a stupid question. I can't seem to get my slider to update its value as its being interacted with. (I'm going to point everyone to the very last method in this long code)
class CustomSlider: UISlider {
override func trackRect(forBounds bounds: CGRect) -> CGRect {
var rect = super.trackRect(forBounds: bounds)
rect.size.height = 7
return rect
}
}
class FactionButton: CustomSlider {
var factionSlider = CustomSlider(frame: CGRect(x: 15, y: 542, width: 386, height: 57))
func factionBalanceSlider(){
factionSlider.minimumValueImage = #imageLiteral(resourceName: "Alliance Slider")
factionSlider.maximumValueImage = #imageLiteral(resourceName: "Horde Slider")
factionSlider.setThumbImage(#imageLiteral(resourceName: "Thumb Image"), for: .normal)
factionSlider.minimumTrackTintColor = UIColor(red:0.08, green:0.33, blue:0.69, alpha:0.8)
factionSlider.maximumTrackTintColor = UIColor(red:1.00, green:0.00, blue:0.00, alpha:0.59)
factionSlider.setValue(0.5, animated: true)
factionSlider.isContinuous = false
factionSlider.addTarget(self, action: #selector(recordFactionBalance(sender:)), for: .valueChanged)
}
func getSlider() -> CustomSlider {
return factionSlider
}
override func trackRect(forBounds bounds: CGRect) -> CGRect {
var customBounds = super.trackRect(forBounds: bounds)
customBounds.size.height = 10
return customBounds
}
#objc func recordFactionBalance(sender: CustomSlider){
//also calculates balance and adds it into the quiz data
print("hi")
print(sender.value) //It's this part that doesn't work
}
}
It's this bit nearest to the bottom that has the issue. (Everything else is fine) The action function doesn't seem to be triggered at all, even when I'm interacting with it. Neither print statements are being executed. Any ideas why?
Cheers
From the getSlider(), i can guess you are using this class as a utility to get the CustomSlider. So, i suspect you are adding the slider to the view as below,
let container = FactionButton()
container.factionBalanceSlider()
let slider = container.getSlider()
self.view.addSubview(slider)
If you will not add the container to the view which is set as the receiver for .valueChange event so it will not get any event. To receive events you also need to add the container in the view as below,
self.view.addSubview(container)

How to automatically scroll through messages in swift

Im trying to implement a String list of messages to display on the screen for my login page. I need these messages to be able to scrolled through if the user decides to. I am using a label for my text. If the user does not scroll, then the messages will automatically scroll through. I tried using iCarousel but it does not achieve the effect I want.
You can use Libray https://github.com/cbpowell/MarqueeLabel
or easily you can also make auto scrollable label your own self like
func startAnimation()
{
//Animating the label automatically change as per your requirement
DispatchQueue.main.async(execute: {
UIView.animate(withDuration: 10.0, delay: 1, options: ([.curveLinear, .repeat]), animations: {
() -> Void in
self.demoLabel.center = CGPoint(x: 0 - self.demoLabel.bounds.size.width / 2, y: self.demoLabel.center.y)
}, completion: nil)
})
}
Usage
class ViewController: UIViewController {
let demoLabel: UILabel = {
let label = UILabel()
label.translatesAutoresizingMaskIntoConstraints = false
label.font = .systemFont(ofSize: 14)
label.textColor = .green
label.text = "This is the demo label for testing automatically scrolling of uilabel when user not clicked on label if user click on label the scrolling is stoped."
return label
}()
override func viewDidLoad() {
super.viewDidLoad()
view.addSubview(demoLabel)
startAnimation()
}