Sorry I am new to swift and I have an imageView.
I can see my image in imageView.
I want to be able to zoom the image in and out. But I also fail to change my image size. What's wrong with my code? Sorry,I already find many solution to fix my problem. I don't know how to fix it. Should I add some gestureRecognizer or anything else?
Thank for answer.
This is code:
import UIKit
import SnapKit
class ImageViewController: UIViewController, UIScrollViewDelegate {
var url:String = ""
var id:String = ""
var scrollView:UIScrollView = { () -> UIScrollView in
let ui = UIScrollView()
ui.backgroundColor = UIColor.black
ui.minimumZoomScale = 1.0
ui.maximumZoomScale = 6.0
return ui
}()
var toolbar:UIToolbar = { () -> UIToolbar in
let ui = UIToolbar()
ui.barTintColor = defaultNavBackgroundColor
ui.clipsToBounds = true
ui.isTranslucent = false
ui.isUserInteractionEnabled = true
return ui
}()
var photoImageView:UIImageView = { () -> UIImageView in
let ui = UIImageView()
ui.backgroundColor = UIColor.clear
ui.layer.masksToBounds = true
ui.contentMode = .scaleAspectFit
ui.isUserInteractionEnabled = true
return ui
}()
var buttonDownload:UIBarButtonItem = { () -> UIBarButtonItem in
let ui = UIBarButtonItem()
ui.style = .plain
return ui
}()
override func loadView() {
super.loadView()
view.backgroundColor = UIColor.black
}
override func viewWillAppear(_ animated: Bool) {
super.viewWillAppear(animated)
}
override func viewDidLoad() {
super.viewDidLoad()
// navigationItem.title = name
self.automaticallyAdjustsScrollViewInsets = false
imageFromUrl(imageView: photoImageView, url: url, chatroomId: id,isResize: false)
self.buttonDownload.action = #selector(btnDownloadClicked(sender:))
scrollView.delegate = self
scrollView.contentSize = (self.photoImageView.image!.size)
photoImageView.center = scrollView.center
loadContent()
loadVFL()
}
override func didReceiveMemoryWarning() {
super.didReceiveMemoryWarning()
}
func loadContent() {
toolbar.sizeToFit()
let flexSpace = UIBarButtonItem(barButtonSystemItem: .flexibleSpace, target: self, action: nil)
buttonDownload = UIBarButtonItem(barButtonSystemItem: .action, target: self, action: nil)
toolbar.items = [flexSpace,buttonDownload]
view.addSubview(scrollView)
view.addSubview(toolbar)
scrollView.addSubview(photoImageView)
}
func loadVFL() {
scrollView.snp.makeConstraints { (make) -> Void in
make.top.equalToSuperview()
make.bottom.equalTo(toolbar.snp.top)
make.left.equalToSuperview()
make.right.equalToSuperview()
}
photoImageView.snp.makeConstraints { (make) -> Void in
make.top.equalToSuperview()
make.bottom.equalToSuperview()
make.left.equalToSuperview()
make.right.equalToSuperview()
make.centerX.equalToSuperview()
make.centerY.equalToSuperview()
}
toolbar.snp.makeConstraints { (make) -> Void in
make.width.equalToSuperview()
make.bottom.equalToSuperview()
make.height.equalTo(44)
}
}
func btnDownloadClicked(sender:UIBarButtonItem) {
print("press")
}
// MARK: - UIScrollViewDelegate
func viewForZoomingInScrollView(scrollView: UIScrollView) -> UIView? {
return photoImageView
}
}
image like this
Related
Encountered a problem: largeTitle of navigation bar collapsing to small title ~once per 20 attempts after refreshControl.endRefreshing().
tableView is first subview of subviews hierarchy, and top constraint is to superview (not to safeArea)
refreshControl added to tableView.refreshControl, not as subview of tableView
was trying call navigationBar.sizeToFit() after endRefreshing - not success.
Controller code:
override public func viewDidLoad() {
super.viewDidLoad()
definesPresentationContext = true
title = L10n.Trainers.trainers.uppercased()
navigationController?.navigationBar.layoutMargins = .init(top: 0, left: 16, bottom: 0, right: 16)
configureSubviews()
makeConstraints()
configureBindings()
configureActions()
setupTableView()
setupResultsTableView()
}
override public func viewWillAppear(_ animated: Bool) {
super.viewWillAppear(animated)
navigationController?.navigationBar.prefersLargeTitles = true
navigationController?.navigationItem.largeTitleDisplayMode = .always
navigationController?.navigationBar.sizeToFit()
}
override public func viewDidDisappear(_ animated: Bool) {
super.viewDidDisappear(animated)
navigationController?.navigationItem.largeTitleDisplayMode = .automatic
}
override public func viewDidAppear(_ animated: Bool) {
super.viewDidAppear(animated)
vm.onViewDidAppear()
mainView.tableView.refreshControl = mainView.refreshControl
}
override public func loadView() {
view = mainView
}
Refresh-logic code:
vm.isLoading.drive { [weak self] loading in
guard let self = self else { return }
if self.mainView.refreshControl.isRefreshing {
if !loading {
self.mainView.tableView.refreshControl?.endRefreshing()
}
} else {
if loading {
var style = LoaderParameters.blue
style.installConstraints = false
self.mainView.tableView.startLoading(with: style)
self.mainView.tableView.existedLoaderView?.centerX().centerY(-40)
} else {
self.mainView.tableView.stopLoadingProgress()
}
}
}.store(in: &subscriptions)
View code:
final class TrainersView: UIView {
override init(frame: CGRect) {
super.init(frame: frame)
configureSubviews()
makeConstraints()
}
required init?(coder: NSCoder) {
super.init(coder: coder)
}
private(set) lazy var refreshControl = UIRefreshControl().configureWithAutoLayout {
$0.tintColor = Asset.mainGrey.color
}
private(set) lazy var topView: UIView = {
let view = UIView()
view.backgroundColor = .clear
return view
}()
private(set) lazy var tableView = UITableView().configureWithAutoLayout {
$0.register(TrainerCell.self)
$0.tableFooterView = UIView()
$0.showsVerticalScrollIndicator = false
$0.separatorStyle = .none
$0.backgroundColor = Asset.mainWhite.color
}
private func configureSubviews() {
addSubview(tableView)
topView.addSubview(segmentedControl)
tableView.tableHeaderView = topView
tableView.tableHeaderView?.frame.size.height = 60
tableView.tableFooterView?.frame.size.height = 40
tableView.reloadData()
}
private func makeConstraints() {
tableView.pinToSuperview()
segmentedControl.centerX()
segmentedControl.bottomAnchor.constraint(equalTo: topView.bottomAnchor, constant: -8).priority(999).activate()
segmentedControl.widthAnchor ~ widthAnchor - 16 * 2
}
}
I'm creating a ViewPager in Swift using ViewCode.
I need to create the following action: tap on the Next button (method: actionNextPressed() ), and scroll the scrollview to the next page (like a TapGesture scrolling to right or left).
Here is my Swift code, what I've tried until now, and the printscreen from the viewpager (at the moment)
PagerViewController.swift
import UIKit
import SnapKit
open class PagerViewController: UIViewController, UIPageViewControllerDelegate {
private lazy var dimmedView: UIView = {
let view = UIView()
view.backgroundColor = .black
view.alpha = maxDimmedAlpha
return view
}()
private lazy var containerView: UIView = {
let view = UIView()
view.backgroundColor = UIColor(white: 1, alpha: 0)
return view
}()
lazy var scrollView: UIScrollView = {
let scrollView = UIScrollView()
scrollView.showsHorizontalScrollIndicator = false
scrollView.isPagingEnabled = true
scrollView.contentSize = CGSize(width: view.frame.width * CGFloat(pages.count), height: containerView.frame.height)
for i in 0..<pages.count {
var page = pages[i]
let dialog = PageViewController(
icon: page.icon,
titleText: page.title,
descriptionText: page.description,
titleActionButton: page.titleButton,
actionButton: page.actionButton
)!
scrollView.addSubview(dialog.view)
scrollView.subviews[i].frame = CGRect(
x: view.frame.width * CGFloat(i),
y: 0,
width: containerView.frame.width,
height: containerView.frame.height
)
}
scrollView.delegate = self
return scrollView
}()
lazy var pageControl: UIPageControl = {
let pageControl = UIPageControl()
pageControl.currentPage = 0
pageControl.numberOfPages = pages.count
pageControl.addTarget(self, action: #selector(pageControlTapHandler(sender:)), for: .allEvents)
pageControl.isUserInteractionEnabled = false
pageControl.pageIndicatorTintColor = .systemGray
pageControl.currentPageIndicatorTintColor = .systemBlue
pageControl.backgroundColor = .white
return pageControl
}()
private lazy var directionsButtonsStackView: UIStackView = {
let view = UIStackView()
view.axis = .horizontal
view.distribution = .fillEqually
view.backgroundColor = .red
return view
}()
private lazy var buttonJump = UIButton()
private lazy var buttonBefore = UIButton()
private lazy var buttonNext = UIButton()
private var titleJumpButton: String! = ""
private let maxDimmedAlpha: CGFloat = 0.6
open var pages: Array<PageModel>!
private var currentPage: Int = 0
init?(listPages: Array<PageModel>, titleJumpButton: String) {
super.init(nibName: nil, bundle: nil)
self.pages = listPages
self.titleJumpButton = titleJumpButton
}
required public init?(coder: NSCoder) {
fatalError("init(coder:) has not been implemented")
}
#objc func pageControlTapHandler(sender: UIPageControl) {
scrollView.scrollTo(horizontalPage: sender.currentPage)
}
open override func viewDidLoad() {
super.viewDidLoad()
setupView()
addViewComponents()
setupConstraints()
}
private func setupView() {
self.buttonJump = PageButton(frame: .zero).build(
context: self,
title: titleJumpButton!,
selector: #selector(actionJumpPressed)
)
self.buttonBefore = PageButton(frame: .zero).build(
context: self,
title: "Before",
selector: #selector(actionBeforePressed)
)
self.buttonBefore.backgroundColor = .white
self.buttonNext = PageButton(frame: .zero).build(
context: self,
title: "Next",
selector: #selector(actionNextPressed)
)
self.buttonJump.setTitle(titleJumpButton, for: .normal)
}
private func addViewComponents() {
view.addSubview(dimmedView)
containerView.addSubview(scrollView)
containerView.addSubview(pageControl)
directionsButtonsStackView.addArrangedSubview(buttonBefore)
directionsButtonsStackView.addArrangedSubview(buttonNext)
containerView.addSubview(directionsButtonsStackView)
containerView.addSubview(buttonJump)
view.addSubview(containerView)
}
private func setupConstraints() {
dimmedView.snp.makeConstraints { make in
make.top.equalToSuperview()
make.bottom.equalToSuperview()
make.leading.equalToSuperview()
make.trailing.equalToSuperview()
}
containerView.snp.makeConstraints { make in
make.top.equalToSuperview().offset(100)
make.bottom.equalToSuperview().inset(100)
make.leading.equalToSuperview()
make.trailing.equalToSuperview()
make.centerX.equalToSuperview()
make.centerY.equalToSuperview()
make.margins.equalTo(20)
}
scrollView.snp.makeConstraints { make in
make.top.equalToSuperview()
make.bottom.equalTo(pageControl.snp.top)
make.leading.equalTo(containerView.snp.leading)
make.trailing.equalTo(containerView.snp.trailing)
}
pageControl.snp.makeConstraints { make in
make.bottom.equalTo(directionsButtonsStackView.snp.top)
make.leading.equalTo(containerView.snp.leading).offset(20)
make.trailing.equalTo(containerView.snp.trailing).inset(20)
make.height.equalTo(30)
make.centerX.equalToSuperview()
}
directionsButtonsStackView.snp.makeConstraints { make in
make.bottom.equalTo(buttonJump.snp.top)
make.leading.equalTo(containerView.snp.leading).offset(20)
make.trailing.equalTo(containerView.snp.trailing).inset(20)
make.height.equalTo(60)
make.width.greaterThanOrEqualTo(0)
make.centerX.equalToSuperview()
}
buttonJump.snp.makeConstraints { make in
make.bottom.equalToSuperview().inset(10)
make.leading.equalTo(containerView).offset(20)
make.trailing.equalTo(containerView).inset(20)
make.centerX.equalToSuperview()
make.width.greaterThanOrEqualTo(0)
make.height.equalTo(50)
}
}
#objc private func actionJumpPressed() {
self.dismiss(animated: true, completion: nil)
}
#objc private func actionBeforePressed() {
if currentPage == 0 {
return
} else {
currentPage -= 1
pageControl.currentPage = currentPage
}
}
#objc private func actionNextPressed() {
if currentPage == pages.count {
return
} else {
currentPage += 1
pageControl.currentPage = currentPage
}
}
}
extension PagerViewController: UIScrollViewDelegate {
public func scrollViewDidScroll(_ scrollView: UIScrollView) {
let pageIndex = Int(round(scrollView.contentOffset.x / view.frame.width))
pageControl.currentPage = pageIndex
currentPage = pageIndex
}
}
extension UIScrollView {
func scrollTo(horizontalPage: Int? = 0) {
var frame: CGRect = self.frame
frame.origin.x = frame.size.width * CGFloat(horizontalPage ?? 0)
self.scrollRectToVisible(frame, animated: true)
}
}
I had the same issue once with a collectionView. You have to turn off the .isPagingEnabled, scroll the scrollview where you want and turn it back on the paging.
func scrollTo(horizontalPage: Int? = 0) {
scrollView.isPagingEnabled = false
var frame: CGRect = self.frame
frame.origin.x = frame.size.width * CGFloat(horizontalPage ?? 0)
self.scrollRectToVisible(frame, animated: true)
scrollView.isPagingEnabled = true
}
The rightbarbuttonitem is not appearing on the right side of the navigation bar. I want the navigation bar to look similar to the one in the "App Store"
I have tried doing this in the storyboard and in the code, setting the image content mode, clipping to bounds, and giving it a frame.
I have also been looking at solutions online and none of them have worked for me. Any help or suggestions would be appreciated, thanks.
Here are some screenshots:
import UIKit
class KYSearchBarController: UISearchController {
override init(searchResultsController: UIViewController?) {
super.init(searchResultsController: searchResultsController)
}
override init(nibName nibNameOrNil: String?, bundle nibBundleOrNil: Bundle?) {
super.init(nibName: nibNameOrNil, bundle: nibBundleOrNil)
}
required init?(coder aDecoder: NSCoder) {
super.init(coder: aDecoder)
}
// Call in view did appear
func CustomizeSearchBar() {
// Changing color of text in textfield.
let textfieldInsideBar = self.searchBar.value(forKey: "searchField") as? UITextField
textfieldInsideBar?.textColor = .darkGray
// Chaning placeholder
let textfieldLbl = textfieldInsideBar?.value(forKey: "placeholderLabel") as? UILabel
textfieldLbl?.textColor = .darkGray
textfieldLbl?.textAlignment = .center
// Icon customization
let glassIcon = textfieldInsideBar?.leftView as? UIImageView
glassIcon?.image = #imageLiteral(resourceName: "icon")
glassIcon?.image?.withRenderingMode(.alwaysTemplate)
glassIcon?.tintColor = .darkGray
// Centering textfield text
textfieldInsideBar?.textAlignment = .center
let clearButton = textfieldInsideBar?.value(forKey: "clearButton") as! UIButton
clearButton.setImage(UIImage(named: "icon1"), for: .normal)
clearButton.tintColor = .darkGray
}
}
extension UIView {
func MakeRound() {
self.layer.cornerRadius = self.frame.width / 5.0
}
}
class ViewController: UIViewController, UISearchBarDelegate {
let searchController = KYSearchBarController(searchResultsController: nil)
override func viewDidLoad() {
super.viewDidLoad()
navigationItem.searchController = searchController
navigationItem.hidesSearchBarWhenScrolling = false
let userimage = UIImageView(image: UIImage(named: "person1"))
userimage.frame = CGRect(x: 60, y: 0, width: 50, height: 50)
userimage.clipsToBounds = true
userimage.layer.masksToBounds = true
userimage.contentMode = .scaleAspectFit
userimage.MakeRound()
let rightBarButton = UIBarButtonItem(customView: userimage)
navigationItem.rightBarButtonItem = rightBarButton
}
override func viewDidAppear(_ animated: Bool) {
super.viewDidAppear(true)
searchController.CustomizeSearchBar()
}
}
Add the userimage property to make it accessible inside the ViewController.
class ViewController: UIViewController, UISearchBarDelegate {
let searchController = KYSearchBarController(searchResultsController: nil)
let userimage = UIImageView(image: UIImage(named: "person1"))
}
Add the makeRound() function call to viewWillLayoutSubviews().
override func viewWillLayoutSubviews() {
super.viewWillLayoutSubviews()
userimage.makeRound()
}
Update the makeRound() function to make a circle.
extension UIView {
func makeRound() {
self.layer.cornerRadius = self.frame.width / 2.0
}
}
Add a method to add the necessary constraints.
func setupConstraints() {
navigationItem.searchController = searchController
navigationItem.hidesSearchBarWhenScrolling = false
guard let navigationBar = self.navigationController?.navigationBar else { return }
navigationBar.addSubview(userimage)
userimage.clipsToBounds = true
userimage.translatesAutoresizingMaskIntoConstraints = false
NSLayoutConstraint.activate([
userimage.rightAnchor.constraint(equalTo: navigationBar.rightAnchor, constant: -16),
userimage.bottomAnchor.constraint(equalTo: navigationBar.bottomAnchor, constant: -12),
userimage.heightAnchor.constraint(equalToConstant: 40),
userimage.widthAnchor.constraint(equalTo: userimage.heightAnchor)
])
}
Setup a gesture recognizer for the UIImageView and implementation for it.
func setUpGestureRecognizer() {
let tapGestureRecognizer = UITapGestureRecognizer(target: self, action: #selector(profile))
userimage.isUserInteractionEnabled = true
userimage.addGestureRecognizer(tapGestureRecognizer)
}
#objc func profile() {
// Your implementation
}
Update viewDidLoad() with the method call.
override func viewDidLoad() {
super.viewDidLoad()
// Setup constraints
setupConstraints()
setUpGestureRecognizer()
}
I ran into the same issue when I was using a very large image for my UIBarButtonItem.
Once I resized my image to a smaller size, it was appropriately placed at the right hand side of the navigation bar. It looks like you are having the same issue.
Alternatively, since starting from iOS 11 navigation bar uses autolayout, replacing the line
userimage.frame = CGRect(x: 60, y: 0, width: 50, height: 50)
with the below should also do the trick:
userimage.widthAnchor.constraint(equalToConstant: 50).isActive = true
userimage.heightAnchor.constraint(equalToConstant: 50).isActive = true
I am using a WKWebView in my Swift app to present some textfields.
I set some appearance properties to match a specific design, in this case its background has to be blue.
But when the keyboard is triggered by the WKWebView, it does something with the appearance properties and shows the keyboard toolbar in a pale light appearance of my color, do you know why?
The only appearance manipulation on UIToolBar that somewhat worked is this one:
UIToolbar.appearance().backgroundColor = .blue
This is my problem:
This is my goal:
Found a way, ended up to swizzle UIToolbars. Hopefully everything is there, but you would get an idea. Swift 4:
class YourController: UIViewController {
#IBOutlet weak var webView: PWebView!
var toolbar : UIToolbar?
func viewDidLoad() {
webView.addInputAccessoryView(toolbar: self.getToolbar(height: 44))
}
func getToolbar(height: Int) -> UIToolbar? {
let toolBar = UIToolbar()
toolBar.frame = CGRect(x: 0, y: 50, width: 320, height: height)
toolBar.barStyle = .black
toolBar.tintColor = .white
toolBar.barTintColor = UIColor.blue
let doneButton = UIBarButtonItem(title: "Done", style: .plain, target: self, action: #selector(onToolbarDoneClick(sender:)) )
let flexibleSpaceItem = UIBarButtonItem(barButtonSystemItem: .flexibleSpace, target: self, action: nil )
toolBar.setItems([flexibleSpaceItem, doneButton], animated: false)
toolBar.isUserInteractionEnabled = true
toolBar.sizeToFit()
return toolBar
}
#objc func onToolbarDoneClick(sender: UIBarButtonItem) {
webView?.resignFirstResponder()
}
}
var ToolbarHandle: UInt8 = 0
extension WKWebView {
func addInputAccessoryView(toolbar: UIView?) {
guard let toolbar = toolbar else {return}
objc_setAssociatedObject(self, &ToolbarHandle, toolbar, objc_AssociationPolicy.OBJC_ASSOCIATION_RETAIN_NONATOMIC)
var candidateView: UIView? = nil
for view in self.scrollView.subviews {
let description : String = String(describing: type(of: view))
if description.hasPrefix("WKContent") {
candidateView = view
break
}
}
guard let targetView = candidateView else {return}
let newClass: AnyClass? = classWithCustomAccessoryView(targetView: targetView)
guard let targetNewClass = newClass else {return}
object_setClass(targetView, targetNewClass)
}
func classWithCustomAccessoryView(targetView: UIView) -> AnyClass? {
guard let _ = targetView.superclass else {return nil}
let customInputAccesoryViewClassName = "_CustomInputAccessoryView"
var newClass: AnyClass? = NSClassFromString(customInputAccesoryViewClassName)
if newClass == nil {
newClass = objc_allocateClassPair(object_getClass(targetView), customInputAccesoryViewClassName, 0)
} else {
return newClass
}
let newMethod = class_getInstanceMethod(WKWebView.self, #selector(WKWebView.getCustomInputAccessoryView))
class_addMethod(newClass.self, #selector(getter: WKWebView.inputAccessoryView), method_getImplementation(newMethod!), method_getTypeEncoding(newMethod!))
objc_registerClassPair(newClass!)
return newClass
}
#objc func getCustomInputAccessoryView() -> UIView? {
var superWebView: UIView? = self
while (superWebView != nil) && !(superWebView is WKWebView) {
superWebView = superWebView?.superview
}
guard let webView = superWebView else {return nil}
let customInputAccessory = objc_getAssociatedObject(webView, &ToolbarHandle)
return customInputAccessory as? UIView
}
}
private var keyBordView: UIView?
override func viewDidLoad() {
super.viewDidLoad()
let webView = WKWebView.init(frame: view.bounds)
webView.loadHTMLString("<html><body><div contenteditable='true'></div></body></html>", baseURL: nil)
view.addSubview(webView)
for subview in webView.scrollView.subviews {
if subview.classForCoder.description() == "WKContentView" {
keyBordView = subview
}
}
NotificationCenter.default.addObserver(self, selector: #selector(keyboardShow), name: .UIKeyboardDidShow, object: nil)
// Do any additional setup after loading the view.
}
#objc private func keyboardShow() {
let keyboardToolbar = UIToolbar()
keyboardToolbar.backgroundColor = UIColor.blue
keyboardToolbar.sizeToFit()
let flexBarButton = UIBarButtonItem(barButtonSystemItem: .flexibleSpace, target: nil, action: nil)
let doneBarButton = UIBarButtonItem(barButtonSystemItem: .done, target: self, action: #selector(self.dismissKeyBord))
keyboardToolbar.items = [flexBarButton, doneBarButton]
keyBordView = keyboardToolbar
}
I'm creating a Sign Up wizard with multiple UIViewControllers.
I currently have it setup so a user enter's his email, clicks the "Go" button on the keyboard and the next UIViewController slides in from the right where the user will enter his name. The problem though is that when I call presentViewController to bring the next UIViewController in, it dismisses the keyboard.
I'd like the keyboard to stay open the entire time while switching ViewControllers. If you look at Facebook's iOS app, they do what I'm trying to do with their signup page.
Any help or suggestions will be greatly appreciated. I read something about using an overlay window, but am not sure how to go about it since I will have multiple UIViewController's in my Sign Up wizard.
Here's my initial controller in the Sign Up Wizard:
class SignUpEmailViewController: UIViewController {
var titleLabel = UILabel.newAutoLayoutView()
var emailField = SignUpTextField(placeholder: "Enter your email address")
var emailLabel = UILabel.newAutoLayoutView()
var continueButton = SignUpContinueButton.newAutoLayoutView()
var footerView = SignUpFooterView.newAutoLayoutView()
let presentAnimationController = PushInFromLeftAnimationController()
let dismissAnimationController = PushInFromRightAnimationController()
override func viewDidLoad() {
super.viewDidLoad()
setupViews()
setupGestures()
}
override func viewDidAppear(animated: Bool) {
super.viewDidAppear(animated)
emailField.becomeFirstResponder()
}
override func didReceiveMemoryWarning() {
super.didReceiveMemoryWarning()
// Dispose of any resources that can be recreated.
}
func setupViews() {
view.backgroundColor = UIColor.colorFromCode(0xe9eaed)
titleLabel.text = "Get Started"
titleLabel.font = UIFont(name: "AvenirNextLTPro-Demi", size: 18)
titleLabel.textColor = Application.greenColor
emailField.enablesReturnKeyAutomatically = true
emailField.returnKeyType = .Go
emailField.delegate = self
emailLabel.text = "You'll use this email when you log in and if you ever need to reset your password."
emailLabel.font = UIFont(name: "AvenirNextLTPro-Regular", size: 13)
emailLabel.textColor = .colorFromCode(0x4e5665)
emailLabel.numberOfLines = 0
emailLabel.textAlignment = .Center
continueButton.addTarget(self, action: "continueButtonPressed", forControlEvents: .TouchUpInside)
continueButton.hidden = true
view.addSubview(titleLabel)
view.addSubview(emailField)
view.addSubview(emailLabel)
view.addSubview(continueButton)
view.addSubview(footerView)
setupConstraints()
}
func setupGestures() {
let gestureRecognizer = UISwipeGestureRecognizer(target: self, action: "swipeHandler")
gestureRecognizer.direction = .Down
view.addGestureRecognizer(gestureRecognizer)
let tapGesture = UITapGestureRecognizer(target: self, action: "dismissKeyboard")
view.addGestureRecognizer(tapGesture)
}
func setupConstraints() {
titleLabel.autoAlignAxisToSuperviewAxis(.Vertical)
titleLabel.autoPinEdgeToSuperviewEdge(.Top, withInset: screenSize.height * 0.2)
emailField.autoAlignAxisToSuperviewAxis(.Vertical)
emailField.autoPinEdge(.Top, toEdge: .Bottom, ofView: titleLabel, withOffset: 15)
emailField.autoSetDimensionsToSize(CGSize(width: screenSize.width * 0.85, height: 40))
emailLabel.autoAlignAxisToSuperviewAxis(.Vertical)
emailLabel.autoPinEdge(.Top, toEdge: .Bottom, ofView: emailField, withOffset: 10)
emailLabel.autoSetDimension(.Width, toSize: screenSize.width * 0.85)
continueButton.autoAlignAxisToSuperviewAxis(.Vertical)
continueButton.autoPinEdge(.Top, toEdge: .Bottom, ofView: emailField, withOffset: 10)
continueButton.autoSetDimensionsToSize(CGSize(width: screenSize.width * 0.85, height: 30))
footerView.autoSetDimension(.Height, toSize: 44)
footerView.autoPinEdgeToSuperviewEdge(.Bottom)
footerView.autoPinEdgeToSuperviewEdge(.Leading)
footerView.autoPinEdgeToSuperviewEdge(.Trailing)
}
override func prefersStatusBarHidden() -> Bool {
return true
}
func swipeHandler() {
dismissViewControllerAnimated(true, completion: nil)
}
func continueButtonPressed() {
presentNextViewController()
}
func dismissKeyboard() {
view.endEditing(true)
}
func presentNextViewController() {
let toViewController = SignUpNameViewController()
toViewController.transitioningDelegate = self
toViewController.firstNameField.becomeFirstResponder()
presentViewController(toViewController, animated: true, completion: nil)
}
}
extension SignUpEmailViewController: UIViewControllerTransitioningDelegate {
func animationControllerForPresentedController(presented: UIViewController, presentingController presenting: UIViewController, sourceController source: UIViewController) -> UIViewControllerAnimatedTransitioning? {
return presentAnimationController
}
func animationControllerForDismissedController(dismissed: UIViewController) -> UIViewControllerAnimatedTransitioning? {
return dismissAnimationController
}
}
extension SignUpEmailViewController: UITextFieldDelegate {
func textFieldShouldReturn(textField: UITextField) -> Bool {
presentNextViewController()
return true
}
func textFieldShouldBeginEditing(textField: UITextField) -> Bool {
continueButton.hidden = true
emailLabel.hidden = false
return true
}
func textFieldShouldEndEditing(textField: UITextField) -> Bool {
continueButton.hidden = false
emailLabel.hidden = true
return true
}
}
And here's the controller that I'm trying to present:
class SignUpNameViewController: UIViewController, UIViewControllerTransitioningDelegate {
var titleLabel = UILabel.newAutoLayoutView()
var textFieldContainer = UIView.newAutoLayoutView()
var firstNameField = SignUpTextField(placeholder: "First name")
var lastNameField = SignUpTextField(placeholder: "Last name")
var continueButton = SignUpContinueButton.newAutoLayoutView()
var footerView = SignUpFooterView.newAutoLayoutView()
let presentAnimationController = PushInFromLeftAnimationController()
let dismissAnimationController = PushInFromRightAnimationController()
override func viewDidAppear(animated: Bool) {
super.viewDidAppear(animated)
firstNameField.becomeFirstResponder()
}
override func viewDidLoad() {
super.viewDidLoad()
setupViews()
setupGestures()
}
override func didReceiveMemoryWarning() {
super.didReceiveMemoryWarning()
// Dispose of any resources that can be recreated.
}
func setupViews() {
view.backgroundColor = UIColor.colorFromCode(0xe9eaed)
titleLabel.text = "What's your name?"
titleLabel.font = UIFont(name: "AvenirNextLTPro-Demi", size: 18)
titleLabel.textColor = Application.greenColor
firstNameField.returnKeyType = .Next
firstNameField.enablesReturnKeyAutomatically = true
lastNameField.returnKeyType = .Next
lastNameField.enablesReturnKeyAutomatically = true
continueButton.addTarget(self, action: "continueButtonPressed", forControlEvents: .TouchUpInside)
view.addSubview(titleLabel)
view.addSubview(textFieldContainer)
textFieldContainer.addSubview(firstNameField)
textFieldContainer.addSubview(lastNameField)
view.addSubview(continueButton)
view.addSubview(footerView)
setupConstraints()
}
func setupGestures() {
let gestureRecognizer = UISwipeGestureRecognizer(target: self, action: "swipeHandler")
gestureRecognizer.direction = .Right
view.addGestureRecognizer(gestureRecognizer)
let tapGesture = UITapGestureRecognizer(target: self, action: "dismissKeyboard")
view.addGestureRecognizer(tapGesture)
}
func setupConstraints() {
titleLabel.autoAlignAxisToSuperviewAxis(.Vertical)
titleLabel.autoPinEdgeToSuperviewEdge(.Top, withInset: screenSize.height * 0.2)
textFieldContainer.autoPinEdge(.Top, toEdge: .Bottom, ofView: titleLabel, withOffset: 15)
textFieldContainer.autoAlignAxisToSuperviewAxis(.Vertical)
textFieldContainer.autoSetDimensionsToSize(CGSize(width: screenSize.width * 0.8, height: 40))
let spaceBetweenTextFields: CGFloat = 5
let textFieldSize = ((screenSize.width * 0.8) - spaceBetweenTextFields) / 2
let textFields: NSArray = [firstNameField, lastNameField]
textFields.autoDistributeViewsAlongAxis(.Horizontal, alignedTo: .Horizontal, withFixedSize: textFieldSize, insetSpacing: false)
firstNameField.autoPinEdgeToSuperviewEdge(.Top)
firstNameField.autoPinEdgeToSuperviewEdge(.Bottom)
lastNameField.autoPinEdgeToSuperviewEdge(.Top)
lastNameField.autoPinEdgeToSuperviewEdge(.Bottom)
continueButton.autoAlignAxisToSuperviewAxis(.Vertical)
continueButton.autoPinEdge(.Top, toEdge: .Bottom, ofView: textFieldContainer, withOffset: 10)
continueButton.autoSetDimensionsToSize(CGSize(width: screenSize.width * 0.8, height: 30))
footerView.autoSetDimension(.Height, toSize: 44)
footerView.autoPinEdgeToSuperviewEdge(.Bottom)
footerView.autoPinEdgeToSuperviewEdge(.Leading)
footerView.autoPinEdgeToSuperviewEdge(.Trailing)
}
override func prefersStatusBarHidden() -> Bool {
return true
}
func dismissKeyboard() {
view.endEditing(true)
}
func swipeHandler() {
dismissViewControllerAnimated(true, completion: nil)
}
func continueButtonPressed() {
let toViewController = SignUpPasswordViewController()
toViewController.transitioningDelegate = self
presentViewController(toViewController, animated: true, completion: {})
}
func animationControllerForPresentedController(presented: UIViewController, presentingController presenting: UIViewController, sourceController source: UIViewController) -> UIViewControllerAnimatedTransitioning? {
return presentAnimationController
}
func animationControllerForDismissedController(dismissed: UIViewController) -> UIViewControllerAnimatedTransitioning? {
return dismissAnimationController
}
}
And here is my custom transition:
class PushInFromLeftAnimationController: NSObject, UIViewControllerAnimatedTransitioning {
func transitionDuration(transitionContext: UIViewControllerContextTransitioning?) -> NSTimeInterval {
return 0.35
}
func animateTransition(transitionContext: UIViewControllerContextTransitioning) {
let fromViewController = transitionContext.viewControllerForKey(UITransitionContextFromViewControllerKey)!
let toViewController = transitionContext.viewControllerForKey(UITransitionContextToViewControllerKey)!
let finalFrameForVC = transitionContext.finalFrameForViewController(toViewController)
let containerView = transitionContext.containerView()
let bounds = UIScreen.mainScreen().bounds
toViewController.view.frame = CGRectOffset(finalFrameForVC, bounds.size.width, 0)
containerView!.addSubview(toViewController.view)
UIView.animateWithDuration(transitionDuration(transitionContext), delay: 0.0, options: UIViewAnimationOptions.CurveLinear, animations: {
fromViewController.view.frame = CGRectOffset(finalFrameForVC, -bounds.size.width, 0)
toViewController.view.frame = finalFrameForVC
}, completion: {
finished in
transitionContext.completeTransition(true)
})
}
}
I think the keyboard is dismissed because the corresponding UIResponder will resign at the same time the ViewController will disappear.
Have you tried setting the next UITextField (in the next ViewController) as the first responder then? thus the keyboard will be linked to a new UIResponder before the previous one would end editing...