TextField底部带有Swift中的iPhone X

时间:2018-03-19 14:44:45

标签: ios swift layout swift3 iphone-x

我是Swift的新手,我的iPhone X存在问题。

我遵循了本教程:https://www.youtube.com/watch?v=FDay6ocBlnE&index=8&list=PL0dzCUj1L5JEfHqwjBV0XFb9qx9cGXwkq以创建聊天应用程序。

我的问题是textField固定在底部,这对iPhone X不利。

enter image description here

我真的不知道如何改变这一点,因为我对故事板更熟悉,而collectionViewController完全是以编程方式。我搜索了很多其他教程,但我找不到任何帮助。

这是我的代码:

底部视图(带文本字段):

class ChatInputContainerView: UIView, UITextFieldDelegate {
   // ...

   override init(frame: CGRect) {
      super.init(frame: frame)
      backgroundColor = .red
      // ...
  }

  required init?(coder aDecoder: NSCoder) {
      fatalError("init(coder:) has not been implemented")
   }

}

CollectionViewController:

class ChatLogController: UICollectionViewController, UICollectionViewDelegateFlowLayout {
   // ...
   lazy var inputContainerView: ChatInputContainerView = {

      // I can't change the y value (it changes nothing)
      let chatInputContainerView = ChatInputContainerView(frame: CGRect(x: 0, y: 0, width: self.view.frame.width, height: 54))
      chatInputContainerView.chatLogController = self

      return chatInputContainerView

   }()

   override var inputAccessoryView: UIView? {
      get {

         return inputContainerView
      }
   }

   override var canBecomeFirstResponder : Bool {
      return true
   }

}

更新

以下是整个代码:

import UIKit
import UserNotifications

class ChatLogController: UICollectionViewController, UITextFieldDelegate, UICollectionViewDelegateFlowLayout, UIImagePickerControllerDelegate, UINavigationControllerDelegate {

   var user: Userm? {
      didSet {
         navigationItem.title = user?.username

         loadMessages()
      }
   }

   var messages = [Message]()


   func loadMessages() {
      guard let toId = user?.id else {
         return
      }

      Api.Message.observeUserDiscussion(toId: toId) { (message) in
         self.messages.append(message)
         DispatchQueue.main.async(execute: {
            self.collectionView?.reloadData()
            //scroll to the last index
            let indexPath = IndexPath(item: self.messages.count - 1, section: 0)
            self.collectionView?.scrollToItem(at: indexPath, at: .bottom, animated: true)
         })
      }
   }

   let cellId = "cellId"

   override func viewDidLoad() {
      super.viewDidLoad()

      UNUserNotificationCenter.current().getNotificationSettings { (settings) in
         print("Notification settings: \(settings)")
         guard settings.authorizationStatus == .authorized else { return }

         //Not authorised
         UIApplication.shared.registerForRemoteNotifications()
      }


      navigationItem.backBarButtonItem = UIBarButtonItem(title: " ", style: .plain, target: nil, action: nil)
      collectionView?.contentInset = UIEdgeInsets(top: 8, left: 0, bottom: 20, right: 0)
      // collectionView?.scrollIndicatorInsets = UIEdgeInsets(top: 0, left: 0, bottom: 50, right: 0)
      collectionView?.alwaysBounceVertical = true
      collectionView?.backgroundColor = UIColor.white
      collectionView?.register(ChatMessageCell.self, forCellWithReuseIdentifier: cellId)
      collectionView?.keyboardDismissMode = .interactive

      arrowBackButton(greyBack)

      let image = UIImage(named: "iconProfilCog")
      navigationItem.rightBarButtonItem = UIBarButtonItem(image: image, style: .plain, target: self, action: #selector(handleParamsMessage))
      navigationItem.rightBarButtonItem?.tintColor = UIColor(red: 203/255, green: 203/255, blue: 203/255, alpha: 1)

      setupKeyboardObservers()

      emptyTextField()
   }

   func emptyTextField() {
      self.inputContainerView.inputTextField.text = ""
      self.inputContainerView.sendButton.isEnabled = false
      self.inputContainerView.sendButton.alpha = 0.8
   }

   override func viewDidLayoutSubviews() {
      inputContainerView.inputTextField.roundCorners([.topLeft,.bottomLeft], radius: 10)
      inputContainerView.backgroundSendButtonView.roundCorners([.topRight,.bottomRight], radius: 22)
   }


   lazy var inputContainerView: ChatInputContainerView = {


      let chatInputContainerView = ChatInputContainerView(frame: CGRect(x: 0, y: 0, width: self.view.frame.width, height: 54))
      chatInputContainerView.chatLogController = self

      return chatInputContainerView

   }()

   func handleParamsMessage() {
      print("params")
      let storyboard: UIStoryboard = UIStoryboard(name: "Main", bundle: nil)
      let detailMessage = storyboard.instantiateViewController(withIdentifier: "MessageDetailTableViewController") as! MessageDetailTableViewController
      if let user = user {
         detailMessage.userId = user.id!
         self.navigationController?.pushViewController(detailMessage, animated: true)
      }

   }

   func handleUploadTap() {
      let imagePickerController = UIImagePickerController()

      imagePickerController.allowsEditing = true
      imagePickerController.delegate = self
      //imagePickerController.mediaTypes = [kUTTypeImage as String, kUTTypeMovie as String]

      present(imagePickerController, animated: true, completion: nil)
   }

   func imagePickerController(_ picker: UIImagePickerController, didFinishPickingMediaWithInfo info: [String : Any]) {

//      if let videoUrl = info[UIImagePickerControllerMediaURL] as? URL {
//         //we selected a video
//         handleVideoSelectedForUrl(videoUrl)
//      } else {
//         //we selected an image
         handleImageSelectedForInfo(info as [String : AnyObject])
//      }

      dismiss(animated: true, completion: nil)
   }

   fileprivate func handleImageSelectedForInfo(_ info: [String: AnyObject]) {
      var selectedImageFromPicker: UIImage?

      if let editedImage = info["UIImagePickerControllerEditedImage"] as? UIImage {
         selectedImageFromPicker = editedImage
      } else if let originalImage = info["UIImagePickerControllerOriginalImage"] as? UIImage {

         selectedImageFromPicker = originalImage
      }

      if let selectedImage = selectedImageFromPicker {
         HelperService.uploadMessagePictureToDatabase(selectedImage, completion: { (imageUrl) in
            self.sendMessageWithImageUrl(imageUrl, image: selectedImage)
         })
      }
   }

   override var inputAccessoryView: UIView? {
      get {

         return inputContainerView
      }
   }

   override var canBecomeFirstResponder : Bool {
      return true
   }

   func setupKeyboardObservers() {
      NotificationCenter.default.addObserver(self, selector: #selector(handleKeyboardDidShow), name: NSNotification.Name.UIKeyboardDidShow, object: nil)
   }

   override func viewDidDisappear(_ animated: Bool) {
      super.viewDidDisappear(animated)

      NotificationCenter.default.removeObserver(self)
   }

   func handleKeyboardDidShow() {

      if messages.count > 0 {
         let indexPath = IndexPath(item: messages.count - 1, section: 0)
         collectionView?.scrollToItem(at: indexPath, at: .top, animated: true)
      }
   }


   override func collectionView(_ collectionView: UICollectionView, numberOfItemsInSection section: Int) -> Int {
      return messages.count
   }

   override func collectionView(_ collectionView: UICollectionView, cellForItemAt indexPath: IndexPath) -> UICollectionViewCell {
      let cell = collectionView.dequeueReusableCell(withReuseIdentifier: cellId, for: indexPath) as! ChatMessageCell

      cell.chatLogController = self

      let message = messages[indexPath.item]
      cell.textView.text = message.text

      setupCell(cell, message: message)

      //lets modify the bubbleView's width somehow???



      // cell.bubbleWidthAnchor?.constant = estimateFrameForText(message.text!).width + 25
      if let text = message.text {
         //a text message
         cell.bubbleWidthAnchor?.constant = estimateFrameForText(text).width + 25
         cell.textView.isHidden = false
      } else if message.imageUrl != nil {
         //fall in here if its an image message
         cell.bubbleWidthAnchor?.constant = 200
         cell.textView.isHidden = true
      }

      return cell
   }



   fileprivate func setupCell(_ cell: ChatMessageCell, message: Message) {
      if let profileImageUrl = self.user?.profileImageUrl {
         let photoUrl = URL(string: profileImageUrl)
         cell.profileImageView.sd_setImage(with: photoUrl)
      }



      if message.fromId == Api.User.CURRENT_USER?.uid {
         //outgoing blue
         cell.bubbleView.backgroundColor = ChatMessageCell.blueColor
         cell.textView.textColor = UIColor.white
         cell.profileImageView.isHidden = true
         cell.tailImageView.isHidden = true

         cell.bubbleViewRightAnchor?.isActive = true
         cell.bubbleViewLeftAnchor?.isActive = false

      } else {
         //incoming gray
         cell.bubbleView.backgroundColor = UIColor(red: 243/255, green: 243/255, blue: 243/255, alpha: 1)
         cell.textView.textColor = UIColor(red: 70/255, green: 70/255, blue: 70/255, alpha: 1)
         cell.profileImageView.isHidden = false
         cell.tailImageView.isHidden = false

         cell.bubbleViewRightAnchor?.isActive = false
         cell.bubbleViewLeftAnchor?.isActive = true
      }

      if let messageImageUrl = message.imageUrl {
         let photoUrl = URL(string: messageImageUrl)
         cell.messageImageView.sd_setImage(with: photoUrl)
         cell.messageImageView.isHidden = false
         // cell.bubbleView.backgroundColor = UIColor(red: 243/255, green: 243/255, blue: 243/255, alpha: 1)
      } else {
         cell.messageImageView.isHidden = true
      }
   }

   override func viewWillTransition(to size: CGSize, with coordinator: UIViewControllerTransitionCoordinator) {
      collectionView?.collectionViewLayout.invalidateLayout()
   }

   func collectionView(_ collectionView: UICollectionView, layout collectionViewLayout: UICollectionViewLayout, sizeForItemAt indexPath: IndexPath) -> CGSize {

      var height: CGFloat = 80

      let message = messages[indexPath.item]
      if let text = message.text {
         height = estimateFrameForText(text).height + 18
      } else if let imageWidth = message.imageWidth?.floatValue, let imageHeight = message.imageHeight?.floatValue {

         // h1 / w1 = h2 / w2
         // solve for h1
         // h1 = h2 / w2 * w1

         height = CGFloat(imageHeight / imageWidth * 200)

      }

      let width = UIScreen.main.bounds.width
      return CGSize(width: width, height: height)
   }

   fileprivate func estimateFrameForText(_ text: String) -> CGRect {
      let size = CGSize(width: 200, height: 1000)
      let options = NSStringDrawingOptions.usesFontLeading.union(.usesLineFragmentOrigin)
      return NSString(string: text).boundingRect(with: size, options: options, attributes: [NSAttributedStringKey.font: UIFont.systemFont(ofSize: 15, weight: .medium)], context: nil)
   }

   var containerViewBottomAnchor: NSLayoutConstraint?

   func handleSend() {
      self.inputContainerView.sendButton.isEnabled = false
      let properties = ["text": inputContainerView.inputTextField.text!]
      sendMessageWithPropertiesFIR(properties as [String : AnyObject])
   }

   fileprivate func sendMessageWithImageUrl(_ imageUrl: String, image: UIImage) {
      let properties: [String: AnyObject] = ["imageUrl": imageUrl as AnyObject, "imageWidth": image.size.width as AnyObject, "imageHeight": image.size.height as AnyObject]
      sendMessageWithPropertiesFIR(properties)
   }

   func sendMessageWithPropertiesFIR(_ properties: [String: AnyObject]) {
      print(properties["text"])

      var messageText = ""
      if properties["text"] != nil {
         messageText = properties["text"] as! String
      } else {
         messageText = "A envoyé une photo"
      }

      Api.Message.sendMessageWithProperties(toId: user!.id!, properties: properties) {

         Api.Message.isUserMuted(userId: self.user!.id!, completion: { (isMuted) in
            if !isMuted {
               Api.UserToken.observeUserToken(withUser: self.user!.id!, completion: { (token) in
                  if let token = token {
                     Api.User.observeCurrentUser(completion: { (user) in

                        Api.Notification.sendNotifPush(token: token, message: "\(user.username!): \(messageText)")
                     })
                  }
               })
            }
         })
         self.emptyTextField()
      }
   }

   func textFieldShouldReturn(_ textField: UITextField) -> Bool {
      handleSend()
      return true
   }

   var startingFrame: CGRect?
   var blackBackgroundView: UIView?
   var startingImageView: UIImageView?

   //my custom zooming logic
   func performZoomInForStartingImageView(_ startingImageView: UIImageView) {

      self.startingImageView = startingImageView
      self.startingImageView?.isHidden = true

      self.inputContainerView.inputTextField.resignFirstResponder()
      startingFrame = startingImageView.superview?.convert(startingImageView.frame, to: nil)

      let zoomingImageView = UIImageView(frame: startingFrame!)
      zoomingImageView.backgroundColor = UIColor.red
      zoomingImageView.image = startingImageView.image
      zoomingImageView.isUserInteractionEnabled = true
      zoomingImageView.addGestureRecognizer(UITapGestureRecognizer(target: self, action: #selector(handleZoomOut)))

      if let keyWindow = UIApplication.shared.keyWindow {
         blackBackgroundView = UIView(frame: keyWindow.frame)
         blackBackgroundView?.backgroundColor = UIColor.black
         blackBackgroundView?.alpha = 0

         keyWindow.addSubview(blackBackgroundView!)

         keyWindow.addSubview(zoomingImageView)

         UIView.animate(withDuration: 0.5, delay: 0, usingSpringWithDamping: 1, initialSpringVelocity: 1, options: .curveEaseOut, animations: {
            // self.inputContainerView.inputTextField.resignFirstResponder()
            self.blackBackgroundView?.alpha = 1
            self.inputContainerView.alpha = 0

            // math?
            // h2 / w1 = h1 / w1
            // h2 = h1 / w1 * w1
            let height = self.startingFrame!.height / self.startingFrame!.width * keyWindow.frame.width

            zoomingImageView.frame = CGRect(x: 0, y: 0, width: keyWindow.frame.width, height: height)

            zoomingImageView.center = keyWindow.center

         }, completion: { (completed) in
            //                    do nothing
         })

      }
   }

   func handleZoomOut(_ tapGesture: UITapGestureRecognizer) {
      if let zoomOutImageView = tapGesture.view {
         //need to animate back out to controller
         zoomOutImageView.layer.cornerRadius = 8
         zoomOutImageView.clipsToBounds = true

         UIView.animate(withDuration: 0.5, delay: 0, usingSpringWithDamping: 1, initialSpringVelocity: 1, options: .curveEaseOut, animations: {

            self.startingFrame = self.startingImageView?.superview?.convert((self.startingImageView?.frame)!, to: nil)
            zoomOutImageView.frame = self.startingFrame!
            self.blackBackgroundView?.alpha = 0
            self.inputContainerView.alpha = 1

         }, completion: { (completed) in
            zoomOutImageView.removeFromSuperview()
            self.startingImageView?.isHidden = false
         })
      }
   }

}

观点:

import UIKit

class ChatInputContainerView: UIView, UITextFieldDelegate {

   weak var chatLogController: ChatLogController? {
      didSet {
         sendButton.addTarget(chatLogController, action: #selector(ChatLogController.handleSend), for: .touchUpInside)
         uploadImageView.addGestureRecognizer(UITapGestureRecognizer(target: chatLogController, action: #selector(ChatLogController.handleUploadTap)))
         inputTextField.addTarget(self, action: #selector(textFieldDidChange(_:)), for: .editingChanged)
      }
   }

   let inputColor = UIColor(red: 243/255, green: 243/255, blue: 243/255, alpha: 1)

   lazy var inputTextField: UITextField = {
      let textField = UITextField()
      textField.placeholder = "Entrer un message..."
      textField.translatesAutoresizingMaskIntoConstraints = false
      textField.delegate = self

      textField.backgroundColor = inputColor
      // textField.roundCorners([.topLeft,.bottomLeft], radius: 10)
      textField.clipsToBounds = true

      return textField
   }()

   let uploadImageView: UIImageView = {
      let uploadImageView = UIImageView()
      uploadImageView.isUserInteractionEnabled = true
      uploadImageView.image = UIImage(named: "pinImage")
      uploadImageView.translatesAutoresizingMaskIntoConstraints = false
      return uploadImageView
   }()

   lazy var backgroundSendButtonView: UIView = {
      let backgroundSendButtonView = UIView()
      backgroundSendButtonView.backgroundColor = inputColor
      backgroundSendButtonView.translatesAutoresizingMaskIntoConstraints = false
      return backgroundSendButtonView
   }()

   let sendButton = UIButton(type: .system)

   override init(frame: CGRect) {
      super.init(frame: frame)

      backgroundColor = .red

      addSubview(uploadImageView)



      // sendButton.setTitle("Send", for: UIControlState())
      sendButton.setImage(UIImage(named: "planeChat"), for: .normal)
      sendButton.backgroundColor = UIColor.white
      sendButton.tintColor = UIColor(red: 82/255, green: 121/255, blue: 179/255, alpha: 1)
      sendButton.layer.cornerRadius = 20
      sendButton.clipsToBounds = true
      sendButton.translatesAutoresizingMaskIntoConstraints = false

      //what is handleSend?

      addSubview(sendButton)


      addSubview(self.inputTextField)
      //x,y,w,h

      // A enlever après
      self.inputTextField.leftAnchor.constraint(equalTo: uploadImageView.rightAnchor, constant: 12).isActive = true
      //self.inputTextField.leftAnchor.constraint(equalTo: leftAnchor, constant: 8).isActive = true

      //self.inputTextField.centerYAnchor.constraint(equalTo: centerYAnchor).isActive = true
      self.inputTextField.topAnchor.constraint(equalTo: topAnchor, constant: 4).isActive = true
      self.inputTextField.rightAnchor.constraint(equalTo: sendButton.leftAnchor, constant: -4).isActive = true
      self.inputTextField.heightAnchor.constraint(equalToConstant: 48).isActive = true

      //x,y,w,h
      sendButton.rightAnchor.constraint(equalTo: rightAnchor, constant: -8).isActive = true
      sendButton.centerYAnchor.constraint(equalTo: inputTextField.centerYAnchor).isActive = true
      sendButton.widthAnchor.constraint(equalToConstant: 38).isActive = true
      sendButton.heightAnchor.constraint(equalToConstant: 38).isActive = true

      //x,y,w,h
      uploadImageView.leftAnchor.constraint(equalTo: leftAnchor, constant: 18).isActive = true
      uploadImageView.centerYAnchor.constraint(equalTo: inputTextField.centerYAnchor).isActive = true
      uploadImageView.widthAnchor.constraint(equalToConstant: 18).isActive = true
      uploadImageView.heightAnchor.constraint(equalToConstant: 20).isActive = true
      //l//et backgroundSendButtonView = UIView()

       //addSubview(backgroundSendButtonView)

      // backgroundSendButtonView.roundCorners([.topRight,.bottomRight], radius: 24)

      insertSubview(backgroundSendButtonView, belowSubview: sendButton)
      backgroundSendButtonView.rightAnchor.constraint(equalTo: rightAnchor, constant: -4).isActive = true
       backgroundSendButtonView.centerYAnchor.constraint(equalTo: inputTextField.centerYAnchor).isActive = true
       //backgroundSendButtonView.widthAnchor.constraint(equalToConstant: 30).isActive = true
       backgroundSendButtonView.leftAnchor.constraint(equalTo: inputTextField.rightAnchor).isActive = true
       backgroundSendButtonView.heightAnchor.constraint(equalTo: inputTextField.heightAnchor).isActive = true

      //x,y,w,h

//      let separatorLineView = UIView()
//      separatorLineView.backgroundColor = UIColor(red: 220/255, green: 220/255, blue: 220/255, alpha: 1)
//      separatorLineView.translatesAutoresizingMaskIntoConstraints = false
//      addSubview(separatorLineView)
//      //x,y,w,h
//      separatorLineView.leftAnchor.constraint(equalTo: leftAnchor).isActive = true
//      separatorLineView.topAnchor.constraint(equalTo: topAnchor).isActive = true
//      separatorLineView.widthAnchor.constraint(equalTo: widthAnchor).isActive = true
//      separatorLineView.heightAnchor.constraint(equalToConstant: 1).isActive = true

      let gradientView = UIView()
      let colorTop = UIColor.clear.cgColor
      let colorBottom = UIColor(red: 0, green: 0, blue: 0, alpha: 0.05).cgColor

      gradientView.translatesAutoresizingMaskIntoConstraints = false
      addSubview(gradientView)

      //x,y,w,h
      gradientView.leftAnchor.constraint(equalTo: leftAnchor).isActive = true
      gradientView.topAnchor.constraint(equalTo: topAnchor, constant: -25).isActive = true
      gradientView.widthAnchor.constraint(equalTo: widthAnchor).isActive = true
      gradientView.heightAnchor.constraint(equalToConstant: 25).isActive = true

      gradientView.backgroundColor = UIColor.clear
      let gradientBackground = CAGradientLayer()

      gradientBackground.colors = [ colorTop, colorBottom]
      gradientBackground.locations = [0.0, 1.0]
      var backgroundLayer = CALayer()
      backgroundLayer = gradientBackground

      let width = UIScreen.main.bounds.size.width
      backgroundLayer.frame = CGRect(x: 0, y: 0, width: width, height: 25)
      print(backgroundLayer.frame)
      print(gradientView.bounds)
      gradientView.layer.insertSublayer(backgroundLayer, at: 0)


   }

   func setGradient(_ view: UIView, colorTop: CGColor, colorBottom: CGColor) {

   }

   func textFieldShouldReturn(_ textField: UITextField) -> Bool {
      chatLogController?.handleSend()
      return true
   }

   @objc func textFieldDidChange(_ textField: UITextField) {
      if textField == self.inputTextField {
         if self.inputTextField.text!.isEmpty {
           disableButton()
        } else {
           // sendButton.setTitleColor(typoGreyButton, for: .normal)
           self.sendButton.isEnabled = true
            self.sendButton.alpha = 1
        }
     }
   }

   func disableButton(){
      //sendButton.setTitleColor(smoothGray, for: .normal)
      sendButton.isEnabled = false
      self.sendButton.alpha = 0.8
   }

   func emptyTextField() {
      self.inputTextField.text = ""
      disableButton()
   }

//   func textViewDidChange(_ textView: UITextView) {
//      print(textView)
//      if textView == self.inputContainerView.inputTextField {
//         if (self.inputContainerView.inputTextField.text?.isEmpty)! {
//            disableButton()
//         } else {
//            // sendButton.setTitleColor(typoGreyButton, for: .normal)
//            self.inputContainerView.sendButton.isEnabled = true
//         }
//      }
//
//   }


   required init?(coder aDecoder: NSCoder) {
      fatalError("init(coder:) has not been implemented")
   }

}

1 个答案:

答案 0 :(得分:0)

如果您只想锚定到底部安全区域,可以在视图控制器的任何位置执行此操作:

if #available(iOS 11.0, *) {
    someView.bottomAnchor.constraint(equalTo: view.safeAreaLayoutGuide.bottomAnchor).isActive = true
} else {
    someView.bottomAnchor.constraint(equalTo: bottomLayoutGuide.topAnchor).isActive = true
}

但是,如果要将其用作常量(即从值中减去底部安全区域的长度),则需要在稍后的生命周期方法中执行此操作,如viewDidLayoutSubviews()

if #available(iOS 11.0, *) {
    someView.bottomAnchor.constraint(equalTo: anotherView.bottomAnchor, constant: -view.safeAreaInsets.bottom).isActive = true
} else {
    someView.bottomAnchor.constraint(equalTo: anotherView.bottomAnchor, constant: -bottomLayoutGuide.length).isActive = true
}

iOS 11修改了他们的安全区域API,因此请确保您支持iOS-11之前的设备,就像我在这些示例中所做的那样。

我还注意到您已在其初始化程序中明确设置了视图框架。如果您使用自动布局(约束),通常不想设置视图框架。因此,我建议不要像你那样设置视图框架,而是使用约束来完成它。