我正在尝试实现自定义文本输入视图,类似于以下大多数消息传递应用程序中使用的视图:
在整个视图最初显示在屏幕底部然后在键盘上方的位置处,选中时,文本框将根据内容调整大小,并包含一个用于上载文本的按钮。
我假设我需要创建一个包含所有这些元素的自定义UIView,但是不确定如何更改文本框大小以及如何在按下时将视图移动到键盘上方。
有人可以指出我正确的方向
答案 0 :(得分:3)
看看MessageInputBar
https://github.com/MessageKit/MessageInputBar
这将使您轻松自如,并阻止您重新发明轮子及其高度可定制的功能,您可以运行示例以查看其工作方式。
修改
只是给您一个主意
import UIKit
import MessageInputBar
class CustomInputBar: MessageInputBar {
override init(frame: CGRect) {
super.init(frame: frame)
configure()
}
required init?(coder aDecoder: NSCoder) {
fatalError("init(coder:) has not been implemented")
}
func configure() {
backgroundView.backgroundColor = UIColor(red: 245/255, green: 245/255, blue: 245/255, alpha: 1)
let button = InputBarButtonItem()
button.setSize(CGSize(width: 36, height: 36), animated: false)
button.setImage(#imageLiteral(resourceName: "ic_up").withRenderingMode(.alwaysTemplate), for: .normal)
button.imageView?.contentMode = .scaleAspectFit
button.tintColor = UIColor(red: 0, green: 122/255, blue: 1, alpha: 1)
inputTextView.backgroundColor = .white
inputTextView.placeholderTextColor = UIColor(red: 0.6, green: 0.6, blue: 0.6, alpha: 1)
inputTextView.textContainerInset = UIEdgeInsets(top: 8, left: 16, bottom: 8, right: 16)
inputTextView.placeholderLabelInsets = UIEdgeInsets(top: 8, left: 20, bottom: 8, right: 20)
inputTextView.layer.borderColor = UIColor(red: 200/255, green: 200/255, blue: 200/255, alpha: 1).cgColor
inputTextView.layer.borderWidth = 1.0
inputTextView.layer.cornerRadius = 4.0
inputTextView.layer.masksToBounds = true
inputTextView.scrollIndicatorInsets = UIEdgeInsets(top: 8, left: 0, bottom: 8, right: 0)
setLeftStackViewWidthConstant(to: 36, animated: false)
setStackViewItems([button], forStack: .left, animated: false)
sendButton.setSize(CGSize(width: 52, height: 36), animated: false)
}
}
如下所示:
具有您想要的所有功能以及更多功能。
我对示例项目中的代码进行了一些编辑,以使其看起来与问题中添加的代码完全一样。
然后您ViewController
将会
import UIKit
import MessageInputBar
final class ExampleViewController: UITableViewController {
// MARK: - Properties
override var inputAccessoryView: UIView? {
return messageInputBar
}
override var canBecomeFirstResponder: Bool {
return true
}
// MARK: - MessageInputBar
private let messageInputBar = CustomInputBar()
// MARK: - View Life Cycle
override func viewDidLoad() {
super.viewDidLoad()
view.backgroundColor = .white
tableView.keyboardDismissMode = .interactive
messageInputBar.delegate = self
}
}
要收听MessageInputBarDelegate
,只需添加
extension ExampleViewController: MessageInputBarDelegate {
func messageInputBar(_ inputBar: MessageInputBar, didPressSendButtonWith text: String) {
// Use to send the message
messageInputBar.inputTextView.text = String()
messageInputBar.invalidatePlugins()
}
func messageInputBar(_ inputBar: MessageInputBar, textViewTextDidChangeTo text: String) {
// Use to send a typing indicator
}
func messageInputBar(_ inputBar: MessageInputBar, didChangeIntrinsicContentTo size: CGSize) {
// Use to change any other subview insets
}
}
就这么简单:)
答案 1 :(得分:2)
如果您想自己以编程方式进行操作,可以尝试一下。
自定义文本输入视图,其中将包含文本输入和发送按钮
import UIKit
class TextEntryView: UIView {
let tvMessage: UITextView = {
let textView = UITextView()
textView.translatesAutoresizingMaskIntoConstraints = false
textView.textColor = Constants.charlie
textView.font = UIFont.systemFont(ofSize: 17)
textView.isScrollEnabled = false
return textView
}()
let btnSend: UIButton = {
let image: UIImage = UIImage(named: "send_icon")!
let button = UIButton(type: .custom)
button.translatesAutoresizingMaskIntoConstraints = false
button.setImage(image, for: .normal)
button.setContentHuggingPriority(UILayoutPriority(rawValue: 250), for: .horizontal)
return button
}()
override init(frame: CGRect) {
super.init(frame: frame)
self.backgroundColor = .white
self.addBorders(edges: .top, color: UIColor(red: 220/250, green: 220/250, blue: 220/250, alpha: 1))
setupLayout()
}
required init?(coder aDecoder: NSCoder) {
fatalError("init(coder:) has not been implemented")
}
override class var requiresConstraintBasedLayout: Bool {
return true
}
private func setupLayout() {
self.addSubview(tvMessage)
self.addSubview(btnSend)
tvMessage.topAnchor.constraint(equalTo: self.topAnchor, constant: 6).isActive = true
tvMessage.leadingAnchor.constraint(equalTo: self.leadingAnchor, constant: 12).isActive = true
tvMessage.trailingAnchor.constraint(equalTo: btnSend.leadingAnchor, constant: -12).isActive = true
tvMessage.bottomAnchor.constraint(equalTo: self.bottomAnchor, constant: -6).isActive = true
btnSend.topAnchor.constraint(equalTo: self.topAnchor, constant: 6).isActive = true
btnSend.trailingAnchor.constraint(equalTo: self.trailingAnchor, constant: -12).isActive = true
btnSend.bottomAnchor.constraint(equalTo: self.bottomAnchor, constant: -6).isActive = true
btnSend.widthAnchor.constraint(equalToConstant: 40).isActive = true
}
}
在控制器中添加自定义视图
import UIKit
class ChatController: UIViewController, UITextViewDelegate {
let textEntry = TextEntryView()
var bottomConstraint: NSLayoutConstraint?
var textEntryHeightConstraint: NSLayoutConstraint?
override func viewWillAppear(_ animated: Bool) {
initViews()
setupLayout()
NotificationCenter.default.addObserver(self,
selector: #selector(self.keyboardNotification(notification:)),
name: NSNotification.Name.UIKeyboardWillChangeFrame,
object: nil)
let tapGesture = UITapGestureRecognizer(target: self, action: #selector(hideKeyboard))
tapGesture.cancelsTouchesInView = true
tableView.addGestureRecognizer(tapGesture)
}
@objc func hideKeyboard() {
self.endEditing(true)
}
deinit {
NotificationCenter.default.removeObserver(self)
}
@objc func keyboardNotification(notification: NSNotification) {
if let userInfo = notification.userInfo {
let keyboardFrame = (userInfo[UIKeyboardFrameEndUserInfoKey] as? NSValue)?.cgRectValue
let endFrameY = keyboardFrame?.origin.y ?? 0
let duration:TimeInterval = (userInfo[UIKeyboardAnimationDurationUserInfoKey] as? NSNumber)?.doubleValue ?? 0
let animationCurveRawNSN = userInfo[UIKeyboardAnimationCurveUserInfoKey] as? NSNumber
let animationCurveRaw = animationCurveRawNSN?.uintValue ?? UIViewAnimationOptions.curveEaseInOut.rawValue
let animationCurve:UIViewAnimationOptions = UIViewAnimationOptions(rawValue: animationCurveRaw)
if endFrameY >= UIScreen.main.bounds.size.height {
bottomConstraint?.constant = 0
} else {
bottomConstraint?.constant = -(keyboardFrame?.size.height)!
}
UIView.animate(withDuration: duration,
delay: TimeInterval(0),
options: animationCurve,
animations: { self.layoutIfNeeded() },
completion: nil)
}
}
func textView(_ textView: UITextView, shouldChangeTextIn range: NSRange, replacementText text: String) -> Bool {
if (textEntry.tvMessage.contentSize.height + 12 < (textEntryHeightConstraint?.constant)!) {
self.textEntry.tvMessage.isScrollEnabled = false
} else {
self.textEntry.tvMessage.isScrollEnabled = true
}
return true
}
func textViewDidBeginEditing(_ textView: UITextView) {
if textEntry.tvMessage.textColor == .lightGray {
textEntry.tvMessage.text = nil
textEntry.tvMessage.textColor = Constants.tertiaryColor
}
}
func textViewDidEndEditing(_ textView: UITextView) {
if (textEntry.tvMessage.text?.isEmpty)! {
textEntry.tvMessage.text = "Write a message"
textEntry.tvMessage.textColor = .lightGray
}
}
}
extension MessageView {
func initViews() {
if #available(iOS 11.0, *) {
bottomConstraint = NSLayoutConstraint(item: textEntry, attribute: .bottom, relatedBy: .equal, toItem: self.safeAreaLayoutGuide, attribute: .bottom, multiplier: 1, constant: 0)
} else {
// Fallback on earlier versions
bottomConstraint = NSLayoutConstraint(item: textEntry, attribute: .bottom, relatedBy: .equal, toItem: self, attribute: .bottom, multiplier: 1, constant: 0)
}
textEntry.translatesAutoresizingMaskIntoConstraints = false
textEntry.tvMessage.text = "Write a message"
textEntry.tvMessage.textColor = .lightGray
textEntry.tvMessage.delegate = self
}
func setupLayout() {
self.addSubview(textEntry)
textEntry.leadingAnchor.constraint(equalTo: self.leadingAnchor).isActive = true
textEntry.trailingAnchor.constraint(equalTo: self.trailingAnchor).isActive = true
self.addConstraint(bottomConstraint!)
textEntryHeightConstraint = textEntry.heightAnchor.constraint(lessThanOrEqualToConstant: 150)
textEntryHeightConstraint?.isActive = true
}
}