以编程方式创建输入附件视图
Posted
技术标签:
【中文标题】以编程方式创建输入附件视图【英文标题】:Creating an Input Accessory View programmatically 【发布时间】:2018-05-02 18:41:31 【问题描述】:我正在尝试以编程方式创建键盘附件视图。我已经设置了一个容器视图,并在其中尝试设置一个文本字段、发布按钮和一个表情符号。 这是我正在尝试制作的示例。
Click here to view the image.
这是我正在使用的代码。我认为问题出在我设置约束时。 我脑海中闪过的几个问题是:
是否需要为容器视图设置约束?
如何向文本字段添加适当的约束?
override var inputAccessoryView: UIView?
get
//Set up the container
let containerView = UIView()
containerView.backgroundColor = #colorLiteral(red: 0.9784782529, green: 0.9650371671, blue: 0.9372026324, alpha: 1)
containerView.frame = CGRect(x: 0, y: 0, width: view.frame.width, height: 60)
let textField = UITextField()
textField.placeholder = "Add a reframe..."
textField.isSecureTextEntry = false
textField.textAlignment = .left
textField.borderStyle = .none
textField.translatesAutoresizingMaskIntoConstraints = false
textField.translatesAutoresizingMaskIntoConstraints = false
textField.leadingAnchor.constraint(equalTo: containerView.leadingAnchor).isActive = true
textField.trailingAnchor.constraint(equalTo: containerView.trailingAnchor).isActive = true
textField.bottomAnchor.constraint(equalTo: containerView.bottomAnchor).isActive = true
textField.topAnchor.constraint(equalTo: containerView.topAnchor).isActive = true
textField.heightAnchor.constraint(equalToConstant: 50)
containerView.addSubview(textField)
return containerView
这是我不断遇到的错误。
*** 由于未捕获的异常“NSGenericException”而终止应用程序,原因:“无法使用锚激活约束,因为它们没有共同的祖先。约束或其锚点是否引用不同视图层次结构中的项目?这是非法的。'
编辑:
查看帖子控制器
lazy var containerView: CommentInputAccessoryView =
let frame = CGRect(x: 0, y: 0, width: view.frame.width, height: 60)
let commentInputAccessoryView = CommentInputAccessoryView(frame: frame)
commentInputAccessoryView.delegate = self
return commentInputAccessoryView
()
//Setting up the keyboard accessory view for comments.
override var inputAccessoryView: UIView?
get
return containerView
override var canBecomeFirstResponder: Bool
return true
CommentInputAccessoryView
protocol CommentInputAccessoryViewDelegate
func didSend(for comment: String)
class CommentInputAccessoryView: UIView
var delegate: CommentInputAccessoryViewDelegate?
func clearCommentTextView()
commentTextView.text = nil
showPlaceholderLabel()
let commentTextView: UITextView =
let text = UITextView()
text.translatesAutoresizingMaskIntoConstraints = false
//text.placeholder = "Add a reframe..."
text.textAlignment = .left
text.backgroundColor = #colorLiteral(red: 0.9784782529, green: 0.9650371671, blue: 0.9372026324, alpha: 1)
text.layer.cornerRadius = 50/2
text.layer.masksToBounds = true
text.isScrollEnabled = false
text.font = UIFont.systemFont(ofSize: 16)
text.textContainerInset = UIEdgeInsets(top: 12, left: 12, bottom: 12, right: 64)
//text.borderStyle = .none
return text
()
let placeholderLabel: UILabel =
let label = UILabel()
label.translatesAutoresizingMaskIntoConstraints = false
label.text = "Add a response..."
label.textColor = .black
label.font = UIFont.systemFont(ofSize: 16)
return label
()
func showPlaceholderLabel()
placeholderLabel.isHidden = false
let sendButton: UIButton =
let send = UIButton(type: .system)
//let sendButton = UIImageView(image: #imageLiteral(resourceName: "arrowUp"))
send.translatesAutoresizingMaskIntoConstraints = false
send.setTitle("Send", for: .normal)
send.setTitleColor(#colorLiteral(red: 0.2901960784, green: 0.3725490196, blue: 0.937254902, alpha: 1), for: .normal)
send.contentEdgeInsets = UIEdgeInsets(top: 0, left: 0, bottom: 0, right: 10)
send.addTarget(self, action: #selector(handlePostComment), for: .touchUpInside)
return send
()
let hugButton: UIButton =
let hug = UIButton()
hug.translatesAutoresizingMaskIntoConstraints = false
hug.setTitle("????", for: .normal)
hug.backgroundColor = #colorLiteral(red: 0.9784782529, green: 0.9650371671, blue: 0.9372026324, alpha: 1)
hug.contentEdgeInsets = UIEdgeInsets(top: 12, left: 12, bottom: 12, right: 12)
hug.layer.cornerRadius = 25
hug.layer.masksToBounds = true
return hug
()
override init(frame: CGRect)
super.init(frame: frame)
autoresizingMask = .flexibleHeight
addSubview(commentTextView)
addSubview(sendButton)
addSubview(hugButton)
addSubview(placeholderLabel)
if #available(ios 11.0, *)
commentTextView.bottomAnchor.constraint(equalTo: safeAreaLayoutGuide.bottomAnchor, constant: -10).isActive = true
hugButton.bottomAnchor.constraint(equalTo: safeAreaLayoutGuide.bottomAnchor, constant: -10).isActive = true
else
commentTextView.leadingAnchor.constraint(equalTo: safeAreaLayoutGuide.leadingAnchor, constant: 8).isActive = true
commentTextView.topAnchor.constraint(equalTo: self.topAnchor, constant: 10).isActive = true
commentTextView.trailingAnchor.constraint(equalTo: hugButton.leadingAnchor, constant: 8)
placeholderLabel.leadingAnchor.constraint(equalTo: commentTextView.leadingAnchor, constant: 18).isActive = true
placeholderLabel.centerYAnchor.constraint(equalTo: self.commentTextView.centerYAnchor).isActive = true
sendButton.trailingAnchor.constraint(equalTo: self.commentTextView.trailingAnchor, constant: -10).isActive = true
sendButton.centerYAnchor.constraint(equalTo: self.commentTextView.bottomAnchor, constant: -22).isActive = true
hugButton.leadingAnchor.constraint(equalTo: self.commentTextView.trailingAnchor, constant: 10).isActive = true
hugButton.trailingAnchor.constraint(equalTo: self.trailingAnchor, constant: -8).isActive = true
hugButton.widthAnchor.constraint(equalToConstant: 40)
//hugButton.centerYAnchor.constraint(equalTo: self.commentTextView.centerYAnchor).isActive = true
NotificationCenter.default.addObserver(self, selector: #selector(handleTextChanged), name: .UITextViewTextDidChange, object: nil)
override var intrinsicContentSize: CGSize
return .zero
@objc func handleTextChanged()
placeholderLabel.isHidden = !self.commentTextView.text.isEmpty
@objc func handlePostComment()
guard let commentText = commentTextView.text else return
delegate?.didSend(for: commentText)
required init?(coder aDecoder: NSCoder)
fatalError("init(coder:) has not been implemented")
这里有一些照片可能有助于了解正在发生的事情。
InputAccessoryView 工作: Click here
TextView 扩展: Click here.
【问题讨论】:
以下是面向未来观众的完整答案:这不是 pod。 github.com/29satnam/InputAccessoryView @Dipali,你是如何将最大高度设置为 UITextview 的? 我使用了您的逻辑,但无法显示分隔线。你遇到过这个问题吗? 【参考方案1】:在应用约束之前,视图应该处于视图层次结构中,否则将引发错误。要消除错误,只需在 let textField = UITextField()
之后执行 containerView.addSubview(textField)
。
关于您发布的示例图片,最初的解决方案可能是这样的
override var inputAccessoryView: UIView?
get
//Set up the container
let containerView = UIView()
containerView.backgroundColor = #colorLiteral(red: 0.9784782529, green: 0.9650371671, blue: 0.9372026324, alpha: 1)
containerView.frame = CGRect(x: 0, y: 0, width: view.frame.width, height: 60)
let textField = UITextField()
containerView.addSubview(textField)
textField.translatesAutoresizingMaskIntoConstraints = false
textField.placeholder = "Add a reframe..."
textField.textAlignment = .left
textField.backgroundColor = .white
textField.layer.cornerRadius = 50/2
textField.layer.masksToBounds = true
textField.borderStyle = .none
textField.leadingAnchor.constraint(equalTo: containerView.leadingAnchor, constant: 8).isActive = true
textField.bottomAnchor.constraint(equalTo: containerView.bottomAnchor, constant: -5).isActive = true
textField.topAnchor.constraint(equalTo: containerView.topAnchor, constant: 10).isActive = true
textField.leftView = UIView(frame: CGRect(x: 0, y: 0, width: 15, height: textField.frame.height)) // adding left padding so it's not sticked to border
textField.leftViewMode = .always
let arrow = UIImageView(image: #imageLiteral(resourceName: "arrowUp"))
containerView.addSubview(arrow)
arrow.translatesAutoresizingMaskIntoConstraints = false
arrow.trailingAnchor.constraint(equalTo: textField.trailingAnchor, constant: -10).isActive = true
arrow.centerYAnchor.constraint(equalTo: textField.centerYAnchor).isActive = true
let button = UIButton()
containerView.addSubview(button)
button.translatesAutoresizingMaskIntoConstraints = false
button.setTitle("?", for: .normal)
button.contentEdgeInsets = UIEdgeInsets(top: 5, left: 5, bottom: 5, right: 5)
button.leadingAnchor.constraint(equalTo: textField.trailingAnchor, constant: 10).isActive = true
button.trailingAnchor.constraint(equalTo: containerView.trailingAnchor, constant: -8).isActive = true
button.centerYAnchor.constraint(equalTo: textField.centerYAnchor).isActive = true
// Negative values for constraints can be avoided if we change order of views when applying constrains
// f.e. instead of button.trailingAnchor.constraint(equalTo: containerView.trailingAnchor, constant: -8).isActive = true
// write containerView.trailingAnchor.constraint(equalTo: button.trailingAnchor, constant: 8).isActive = true
return containerView
【讨论】:
这太棒了!谢谢!我在 iphone x 上预览时遇到了一些问题,如何更改约束以对齐到安全位置而不是手机底部? @DipaliBajaj 很高兴它可以帮助您接受答案:)。完全忘记了 iPhone X。每个UIView
上都有safeAreaLayoutGuide
属性,可用于设置约束。例如,修复 emoji 按钮以使其在 iPhone X 的横向模式下可见是button.safeAreaLayoutGuide.trailingAnchor.constraint(equalTo: containerView.safeAreaLayoutGuide.trailingAnchor, constant: -8).isActive = true
。
感谢您的帮助。对此,我真的非常感激。我没有使用文本字段,而是包含了多行的文本视图。在模拟器中,当您在 CommentTextView 中键入多行时,它会展开并将按钮推出视图。你知道我该如何解决这个问题吗?
@DipaliBajaj 不确定是什么导致了问题。您是否在控制台中有一些警告限制已被破坏?
没有警告!我不确定为什么它也在扩展。约束似乎是正确的。以上是关于以编程方式创建输入附件视图的主要内容,如果未能解决你的问题,请参考以下文章