Moving UIButton when keyboard pops up - ios

I have below class. I am basically adding NSNotification to check whether keyboard is up. If keyboard is up, I change the frame of button to locate it on top of the keyboard. I think I did this in a correct manner, but the button apparently does not move. What could be the problem?
class vc: UIViewController {
var previousButton: UIButton!
var nextButton: UIButton!
override func viewDidLoad() {
NSNotificationCenter.defaultCenter().addObserver(self, selector: Selector("keyboardWillShow:"), name: UIKeyboardWillShowNotification, object: nil)
NSNotificationCenter.defaultCenter().addObserver(self, selector: Selector("keyboardWillHide:"), name: UIKeyboardWillHideNotification, object: nil)
previousButton = UIButton(frame: CGRectMake(margin + 20, containerView.frame.size.height + 10, 80, 30))
previousButton.setImage(UIImage(named: "previous"), forState: .Normal)
previousButton.addTarget(self, action: "previousButtonPressed2:", forControlEvents: .TouchUpInside)
nextButton = UIButton(frame: CGRectMake(self.view.frame.width - margin - 80 - 20, containerView.frame.size.height + 10 , 80, 30))
nextButton.setImage(UIImage(named: "next"), forState: .Normal)
nextButton.addTarget(self, action: "nextButtonPressed2:", forControlEvents: .TouchUpInside)
self.view.addSubview(previousButton)
self.view.addSubview(nextButton)
}
func keyboardWillShow(notification: NSNotification) {
if let keyboardSize = (notification.userInfo?[UIKeyboardFrameBeginUserInfoKey] as? NSValue)?.CGRectValue() {
previousButton = UIButton(frame: CGRectMake(10 + 20, self.view.frame.size.height - keyboardSize.height - 40, 80, 30))
}
}
func keyboardWillHide(notification: NSNotification) {
if let keyboardSize = (notification.userInfo?[UIKeyboardFrameBeginUserInfoKey] as? NSValue)?.CGRectValue() {
previousButton = UIButton(frame: CGRectMake(10 + 20, self.view.frame.size.height - 40, 80, 30))
}
}
}

You should check for UIKeyboardFrameEndUserInfoKey key in the keyboardWillShow: method instead of UIKeyboardFrameBeginUserInfoKey. The same goes for keyboardWillHide: method:
func keyboardWillShow(notification: NSNotification) {
if let keyboardSize = (notification.userInfo?[UIKeyboardFrameEndUserInfoKey] as? NSValue)?.CGRectValue() {
previousButton = UIButton(frame: CGRectMake(10 + 20, self.view.frame.size.height - keyboardSize.height - 40, 80, 30))
}
}
func keyboardWillHide(notification: NSNotification) {
if let keyboardSize = (notification.userInfo?[UIKeyboardFrameEndUserInfoKey] as? NSValue)?.CGRectValue() {
previousButton = UIButton(frame: CGRectMake(10 + 20, self.view.frame.size.height - 40, 80, 30))
}
}
UIKeyboardFrameBeginUserInfoKey allows you to get the frame of the keyboard from before the keyboard animation starts when you really need a frame of the keyboard when keyboard is fully visible in the screen. This value can be retrieved using UIKeyboardFrameBeginUserInfoKey key.

Related

Get titleLabel during drag and drop

An array of UIButton are generated programmatically. Is it possible to get the titleLabel of the UIButton triggering the drag? Or are there any ways to get info of the UIButton in the drag function?
override func viewDidLoad() {
super.viewDidLoad()
for q in question{
addButton(title:q)
}
}
func addButton(title:String){
var tbutton: UIButton = {
let button = UIButton(frame: CGRect(x: 0, y: 0,
width: buttonWidth,
height: buttonHeight))
button.center = self.view.center
button.layer.cornerRadius = 5
button.layer.masksToBounds = true
button.backgroundColor = UIColor.yellow
button.setTitleColor(.black, for: .normal)
button.setTitle(title, for: .normal)
return button
}()
view.addSubview(tbutton)
tbutton.addTarget(self,
action: #selector(drag(control:event:)),
for: UIControl.Event.touchDragInside)
tbutton.addTarget(self,
action: #selector(drag(control:event:)),
for: [UIControl.Event.touchDragExit,
UIControl.Event.touchDragOutside])
self.buttonArray.append(tbutton)
}
#objc func drag(control: UIControl, event: UIEvent) {
//print(event)
if let center = event.allTouches?.first?.location(in: self.view) {
control.center = center
}
/////////////////////////////////////////
// Get titleLabel of the button here???????????
/////////////////////////////////////////
}
class ViewController: UIViewController {
override func viewDidLoad() {
super.viewDidLoad()
let button = UIButton.init(frame: CGRect.init(x: 0, y: 0, width: 100, height: 100))
button.backgroundColor = .yellow
button.center = CGPoint.init(x: view.bounds.width / 2, y: view.bounds.height / 2)
view.addSubview(button)
let pangesture = UIPanGestureRecognizer.init(target: self, action: #selector(ViewController.panning(_:)))
button.addGestureRecognizer(pangesture)
}
#objc func panning(_ panGesture : UIPanGestureRecognizer){
let button = panGesture.view as! UIButton
switch panGesture.state{
case .changed:
button.center = panGesture.location(in: view)
panGesture.setTranslation(.zero, in: view)
default:
break
}
// here you can get the button's properties too.
}
}

How to set the custom inputview of the textview as same height as that of the default keyboard in iOS?

I want the height of custom inputView of the textView to be same height as that of default keyboard. I tried a lot, including:
self.textView.inputView?.autoresizingMask = .flexibleHeight
I couldn't find a solution. It's always coming less than that of default keyboard. (EDIT: This issue exists only for iPhone X)
My code:
class ViewController: UIViewController {
let textView = UITextView()
let button = UIButton()
var keyboardView = UIView()
override func viewDidLoad() {
super.viewDidLoad()
button.addTarget(self, action: #selector(buttonAction), for: .touchUpInside)
textView.backgroundColor = .lightGray
button.backgroundColor = .red
self.view.addSubview(textView)
self.view.addSubview(button)
}
#objc func buttonAction() {
if self.textView.inputView == nil {
self.textView.inputView = keyboardView
self.textView.inputView?.autoresizingMask = .flexibleHeight
self.textView.reloadInputViews()
} else {
self.textView.inputView = nil
self.textView.reloadInputViews()
}
}
override func viewWillLayoutSubviews() {
super.viewWillLayoutSubviews()
textView.frame = CGRect(x: 0, y: 50, width: self.view.frame.size.width - 50, height: 50)
button.frame = CGRect(x: self.view.frame.size.width - 50, y: 50, width: 50, height: 50)
}
}

Label is attached to the keyboard

How to add a block with the send button so that it moves with the keyboard. And also that would be textview behaved the same.
preview
Add this code in your controller
func createInputAccessoryView () -> UIToolbar {
let toolbarAccessoryView = UIToolbar(frame: CGRect(x: 0, y: 0, width: self.view.bounds.size.width, height: 44))
toolbarAccessoryView.barStyle = .default
toolbarAccessoryView.tintColor = UIColor.blue
let flexSpace = UIBarButtonItem(barButtonSystemItem:.flexibleSpace, target:nil, action:nil)
let doneButton = UIBarButtonItem(barButtonSystemItem:.done, target:self, action:Selector(("doneTouched")))
toolbarAccessoryView.setItems([flexSpace, doneButton], animated: false)
return toolbarAccessoryView
}
#objc func doneTouched() {
/* Your action goes here */
}
Now add this in your viewDidLoad or anywhere
yourTextView.inputAccessoryView = createInputAccessoryView ()
Design the block view and then attach it's bottom constraint as IBOutlet and do this
override func viewDidLoad() {
super.viewDidLoad()
NotificationCenter.default.addObserver(self, selector: #selector(ViewController.keyboardWillShow), name: NSNotification.Name.UIKeyboardWillShow, object: nil)
NotificationCenter.default.addObserver(self, selector: #selector(ViewController.keyboardWillHide), name: NSNotification.Name.UIKeyboardWillHide, object: nil)
}
#objc func keyboardWillShow(notification: NSNotification) {
if let keyboardSize = (notification.userInfo?[UIKeyboardFrameBeginUserInfoKey] as? NSValue)?.cgRectValue {
self.viewBotCon.constant = -1 * keyboardSize.height
self.view.layoutIfNeeded()
}
}
#objc func keyboardWillHide(notification: NSNotification) {
self.viewBotCon.constant = 0
self.view.layoutIfNeeded()
}

How to I add preview text on top of keyboard layout in iOS

I want to show preview text on top of keyboard like this:
How do I solve with this problem?
I think this is what you want :
Code :
override func viewDidAppear(_ animated: Bool) {
let viewAcc = UIView()
viewAcc.frame = CGRect(x: 0, y: 0, width: self.view.frame.size.width, height: 50)
viewAcc.backgroundColor = UIColor.gray
let newTF = UITextField(frame: CGRect(x: 2, y: 10, width: self.view.frame.size.width - 75 , height: 30))
newTF.backgroundColor = UIColor.white
newTF.borderStyle = UITextBorderStyle.none
let btnDone = UIButton(frame: CGRect(x: newTF.frame.size.width + 10, y: 5, width: 45, height: 30 ))
btnDone.backgroundColor = UIColor.blue
btnDone.setTitle("Done", for: .normal)
viewAcc.addSubview(newTF)
viewAcc.addSubview(btnDone)
self.mytextField.inputAccessoryView = viewAcc
}
Reference:
Apple Doc Reference
#dahiya_boy's method is much better i guess. but if you need alternative way...
you can observe on this notifications and show or hide a label that show a preview of text.
// this one trigger keyboardWillShow when keyboard is shown to user
NotificationCenter.default.addObserver(self, selector: #selector(keyboardWillShow), name: .UIKeyboardWillShow, object: nil)
// this one trigger keyboardWillHide when keyboard is dismissing
NotificationCenter.default.addObserver(self, selector: #selector(keyboardWillHide), name: .UIKeyboardWillHide, object: nil)
and in function keyboardWillShow you can display a label for preview on top of the keyboard.
func keyboardWillShow(sender: NSNotification) {
if let userInfo = sender.userInfo {
if let keyboardHeight = userInfo[UIKeyboardFrameEndUserInfoKey]?.CGRectValue().size.height {
// keyboard height is available you can use it to put image in view
}
}
}
func keyboardWillHide(sender: NSNotification) {
// you can hide the label here
}

How can I get events to my (sub) UIView?

I'm new to Swift and have a hard time understand the event flow. The code below can be run directly in an xcode playground. I have a white UIView in the background. This view has a brown button and a red view as sub-views. Click on them and the events are logged in the controller, just as expected.
But the controller of this white view also adds another view, that has it's own controller class (SubviewController). SubviewController is green and has a blue subview with a black button. Question is... why don't I get any logs from the green, blue and black views/buttons?
import Foundation
import UIKit
import PlaygroundSupport
class TestViewController : UIViewController {
let playButton: UIButton = {
let playButton = UIButton(frame: CGRect(x: 155, y: 135, width: 160, height: 40))
playButton.setTitle("BROWN BUTTON", for: .normal)
playButton.backgroundColor = UIColor.brown
return playButton
}()
override func loadView() {
let viewWhite = UIView()
viewWhite.backgroundColor = UIColor.white
let viewRed = UIView()
viewRed.backgroundColor = UIColor.red
viewRed.frame = CGRect(x: 20, y: 20, width: 40, height: 10)
viewRed.clipsToBounds = true
let recognizer2 = UITapGestureRecognizer(target: self, action: #selector (self.handleTapRed(_:)))
viewRed.addGestureRecognizer(recognizer2)
let recognizer = UITapGestureRecognizer(target: self, action: #selector (self.handleTap(_:)))
viewWhite.addGestureRecognizer(recognizer)
playButton.addTarget(self, action: #selector (self.action) , for: .touchUpInside)
let catList = SubviewController()
viewWhite.addSubview(catList.view)
viewWhite.addSubview(playButton)
viewWhite.addSubview(viewRed)
self.view = viewWhite
}
func action() {
print("Brown button tapped")
}
func handleTap(_ sender:UITapGestureRecognizer){
print("WHITE VIEW (background view) TAPPED")
}
func handleTapRed(_ sender:UITapGestureRecognizer){
print("RED VIEW TAPPED")
}
}
class SubviewController: UIViewController {
let buttonBlack: UIButton = {
let button = UIButton(frame: CGRect(x: 40, y: 10, width: 170, height: 20))
button.backgroundColor = UIColor.black
button.setTitle("BLACK BUTTON", for: .normal)
return button
}()
let viewBlue: UIView = {
let v = UIView()
v.backgroundColor = UIColor.blue
v.frame = CGRect(x: 20, y: 40, width: 240, height: 60)
v.clipsToBounds = true
return v
}()
override func loadView() {
super.loadView()
self.view.backgroundColor = UIColor.green
buttonBlack.addTarget(self, action: #selector (self.blackKlick) , for: .touchUpInside)
self.view.addSubview(viewBlue)
self.view.frame = CGRect(x: 0, y: 40, width: 240, height: 60)
self.view.clipsToBounds = true
self.view.addGestureRecognizer(UITapGestureRecognizer(target: self, action: #selector (self.handleTapGreen(_:))))
viewBlue.addGestureRecognizer(UITapGestureRecognizer(target: self, action: #selector (self.handleTapBlue(_:))))
viewBlue.addSubview(buttonBlack)
}
func blackKlick() {
print("Black button tapped")
}
func handleTapBlue(_ sender:UITapGestureRecognizer){
print("BLUE VIEW TAPPED")
}
func handleTapGreen(_ sender:UITapGestureRecognizer){
print("GREEN VIEW TAPPED")
}
}
PlaygroundPage.current.liveView = TestViewController()
Thanks for any help!
This line in your current code:
let catList = SubviewController()
creates a local instance of SubvieController. As soon as you exit the loadView() func, that instance is gone.
So, you need a class-level variable to keep that instance around. Add this line:
class TestViewController : UIViewController {
var catList: SubviewController!
and then remove the let from the instantiation line in loadView():
catList = SubviewController()

Resources