gpt4 book ai didi

ios - Swift 中带有 iPhone X 的 TextField 底部

转载 作者:行者123 更新时间:2023-11-28 07:52:07 26 4
gpt4 key购买 nike

我是 Swift 的新手,我遇到了 iPhone X 的问题。

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

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

enter image description here

我真的不知道如何更改它,因为我对 Storyboard更熟悉,而且这里的 collectionViewController 完全以编程方式进行。我搜索了很多其他教程,但没有找到任何帮助。

这是我的代码:

底部 View (带有文本字段):

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")
}

}

Collection View Controller :

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
})
}
}

}

View :

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")
}

}

最佳答案

如果你只想锚定到底部安全区域,你可以在你的 View Controller 中的任何地方这样做:

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 之前的设备。

我还刚刚注意到您已经在 View 的初始化器中明确设置了 View 的框架。如果您使用自动布局(约束),您通常不想像那样设置 View 的框架。因此,我建议不要像您那样设置 View 的框架,而是使用约束来设置。

关于ios - Swift 中带有 iPhone X 的 TextField 底部,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/49365673/

26 4 0
Copyright 2021 - 2024 cfsdn All Rights Reserved 蜀ICP备2022000587号
广告合作:1813099741@qq.com 6ren.com