Created
December 7, 2017 18:36
-
-
Save chunkyguy/77c9ffaa4536adc67caf089669891e56 to your computer and use it in GitHub Desktop.
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
// | |
// ViewController.swift | |
// KeyboardTransitionBug | |
// | |
// Created by Sid on 07/12/2017. | |
// Copyright © 2017 Picnic. All rights reserved. | |
// | |
import UIKit | |
class ViewController: UIViewController { | |
@IBOutlet var imageView: UIImageView! | |
@IBOutlet var searchField: SearchHeaderView! | |
override func viewDidLoad() { | |
super.viewDidLoad() | |
NotificationCenter.default.addObserver(self, selector: #selector(onShowingKeyboard(notif:)), name: Notification.Name.UIKeyboardWillShow, object: nil) | |
} | |
@objc func onShowingKeyboard(notif: Notification) { | |
addAndAnimate(parentView: imageView, info: notif.userInfo) | |
} | |
@IBAction func onTap() { | |
addAndAnimate(parentView: imageView, info: nil) | |
} | |
func addAndAnimate(parentView: UIView, info: [AnyHashable : Any]?) { | |
let (containerView, contentView, frame, constraints) = add(parentView: parentView) | |
DispatchQueue.main.async { [weak self] in | |
self?.animate(containerView: containerView, contentView: contentView, frame: frame, constraints: constraints, info: info) | |
} | |
} | |
func add(parentView: UIView) -> (UIView?, UIView, CGRect, [NSLayoutConstraint]) { | |
let img = UIImageView(image: UIImage(named: "IMG_4389.JPG")) | |
let coordinateSpace = UIScreen.main.fixedCoordinateSpace | |
let frame = view.convert(parentView.frame, to: coordinateSpace) | |
let superView = UIApplication.shared.keyWindow?.rootViewController?.view //UIApplication.shared.keyWindow | |
superView?.addSubview(img) | |
img.translatesAutoresizingMaskIntoConstraints = false | |
let constraints: [NSLayoutConstraint] = [ | |
NSLayoutConstraint(item: img, attribute: .left, relatedBy: .equal, toItem: superView, attribute: .left, multiplier: 1.0, constant: frame.origin.x), | |
NSLayoutConstraint(item: img, attribute: .top, relatedBy: .equal, toItem: superView, attribute: .top, multiplier: 1.0, constant: frame.origin.y), | |
NSLayoutConstraint(item: img, attribute: .width, relatedBy: .equal, toItem: nil, attribute: .notAnAttribute, multiplier: 1.0, constant: frame.size.width), | |
NSLayoutConstraint(item: img, attribute: .height, relatedBy: .equal, toItem: nil, attribute: .notAnAttribute, multiplier: 1.0, constant: frame.size.height) | |
] | |
superView?.addConstraints(constraints) | |
return (superView, img, frame, constraints) | |
} | |
func animate(containerView: UIView?, contentView: UIView, frame: CGRect, constraints: [NSLayoutConstraint], info: [AnyHashable : Any]?) { | |
precondition(containerView != nil) | |
precondition(contentView.superview != nil) | |
precondition(contentView.superview == containerView) | |
precondition(constraints.count == 4) | |
let duration: Double = (info?[UIKeyboardAnimationDurationUserInfoKey] as? NSNumber)?.doubleValue ?? 3.0 | |
let animationCurveRawNSN = info?[UIKeyboardAnimationCurveUserInfoKey] as? NSNumber | |
let animationCurveRaw = Int(animationCurveRawNSN?.uintValue ?? UIViewAnimationOptions.curveEaseInOut.rawValue) | |
let animationCurve = UIViewAnimationCurve(rawValue: animationCurveRaw) ?? UIViewAnimationCurve.easeOut | |
let finalFrame = CGRect(x: frame.origin.x + 100, y: frame.origin.y - 100, width: 100, height: 100) | |
print("\(frame) -> \(finalFrame)") | |
containerView?.layoutIfNeeded() | |
UIView.beginAnimations("animation-007", context: nil) | |
UIView.setAnimationDuration(duration) | |
UIView.setAnimationCurve(animationCurve) | |
UIView.setAnimationBeginsFromCurrentState(true) | |
constraints[0].constant = finalFrame.origin.x | |
constraints[1].constant = finalFrame.origin.y | |
constraints[2].constant = finalFrame.size.width | |
constraints[3].constant = finalFrame.size.height | |
containerView?.layoutIfNeeded() | |
UIView.commitAnimations() | |
// UIView.animate(withDuration: 3.0, delay: 0.0, options: [], animations: { [weak containerView] in | |
// constraints[0].constant = finalFrame.origin.x | |
// constraints[1].constant = finalFrame.origin.y | |
// constraints[2].constant = finalFrame.size.width | |
// constraints[3].constant = finalFrame.size.height | |
// containerView?.layoutIfNeeded() | |
// }, completion: { [weak contentView] complete in | |
// assert(complete) | |
// contentView?.removeFromSuperview() | |
// }) | |
} | |
@IBAction func onDismiss() { | |
searchField.dismissKeyboard() | |
} | |
} | |
final class SearchHeaderView: UIView { | |
/// The title for the toggle button | |
var toggleButtonTitle: String? { | |
get { | |
return toggleButton.title(for: .normal) | |
} | |
set { | |
toggleButton.setTitle(newValue, for: .normal) | |
} | |
} | |
/// The image for the toggle button | |
var toggleButtonImage: UIImage? { | |
get { | |
return toggleButton.image(for: .normal) | |
} | |
set { | |
toggleButton.setImage(newValue, for: .normal) | |
} | |
} | |
// MARK: - UI Elements | |
private let searchBar = UISearchBar() | |
private let toggleButton = UIButton() | |
init(barcodeScannerEnabled: Bool) { | |
super.init(frame: .zero) | |
setUp(displayBarcodeScannerButton: barcodeScannerEnabled) | |
} | |
required init?(coder aDecoder: NSCoder) { | |
super.init(coder: aDecoder) | |
setUp(displayBarcodeScannerButton: false) | |
} | |
override init(frame: CGRect) { | |
super.init(frame: frame) | |
setUp(displayBarcodeScannerButton: false) | |
} | |
private func setUp(displayBarcodeScannerButton: Bool) { | |
/* Set the color of search bar background */ | |
// switch searchBarStyle | |
// case .Prominent: inner view is automatically set to white, with a default 1px black border | |
// case .Minimal: inner view is automatically set to some darker shade of background color | |
let searchBackgroundColor = UIColor.lightGray | |
/* color for elements within search bar like: text, input flashing indicator */ | |
backgroundColor = searchBackgroundColor | |
/* add search bar */ | |
addSubview(searchBar) | |
/* configure search bar */ | |
searchBar.searchBarStyle = .prominent | |
searchBar.isTranslucent = false | |
searchBar.barTintColor = searchBackgroundColor | |
searchBar.tintColor = UIColor.red | |
searchBar.autocapitalizationType = .none | |
searchBar.backgroundImage = UIImage() // get rid of 1px black line | |
/* add button */ | |
if displayBarcodeScannerButton { | |
addSubview(toggleButton) | |
/* configure button */ | |
toggleButton.setTitleColor(UIColor.red, for: .normal) | |
toggleButton.titleLabel?.font = UIFont.preferredFont(forTextStyle: .body) | |
} | |
/* add constraints */ | |
searchBar.translatesAutoresizingMaskIntoConstraints = false | |
addConstraints([ | |
NSLayoutConstraint(item: searchBar, attribute: .leading, relatedBy: .equal, toItem: self, attribute: .leading, multiplier: 1.0, constant: 8.0), | |
NSLayoutConstraint(item: searchBar, attribute: .top, relatedBy: .equal, toItem: self, attribute: .top, multiplier: 1.0, constant: 8.0), | |
NSLayoutConstraint(item: self, attribute: .bottom, relatedBy: .equal, toItem: searchBar, attribute: .bottom, multiplier: 1.0, constant: 8.0), | |
]) | |
if displayBarcodeScannerButton { | |
toggleButton.translatesAutoresizingMaskIntoConstraints = false | |
addConstraints([ | |
NSLayoutConstraint(item: toggleButton, attribute: .trailing, relatedBy: .equal, toItem: self, attribute: .trailing, multiplier: 1.0, constant: -16.0), | |
NSLayoutConstraint(item: toggleButton, attribute: .centerY, relatedBy: .equal, toItem: searchBar, attribute: .centerY, multiplier: 1.0, constant: 0.0), | |
NSLayoutConstraint(item: toggleButton, attribute: .leading, relatedBy: .equal, toItem: searchBar, attribute: .trailing, multiplier: 1.0, constant: 8.0) | |
]) | |
} else { | |
addConstraints([ | |
NSLayoutConstraint(item: self, attribute: .trailing, relatedBy: .equal, toItem: searchBar, attribute: .trailing, multiplier: 1.0, constant: 8.0), | |
]) | |
} | |
isAccessibilityElement = false | |
} | |
func presentKeyboard() { | |
searchBar.becomeFirstResponder() | |
} | |
func dismissKeyboard() { | |
searchBar.resignFirstResponder() | |
} | |
func setQuery(query: String) { | |
searchBar.text = query | |
} | |
} |
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment