在 iOS 8 中动态调整 inputAccessoryView 的大小
Resize inputAccessoryView dynamically in iOS 8
基本上我试图在 inputAccessoryView 属性.
中创建一个调整大小的 UITextView
我有一个 viewController,方法 canBecomeFirstResponder 返回 true 和一个视图,我通过自定义 class(从 XIB 获取它)实例化。在此视图中有一个 UITextView。
我尝试从 class 内部调整完整的 inputAccessoryView 的大小。我尝试了几种方法:设置框架方向,尝试使用高度限制。它似乎只调整了一半:
这基本上就是我想要的(有或没有自动布局,但在 iOS 7/8+ 中工作):
class MessageInputAccessory: UIView, UITextViewDelegate
{
@IBOutlet weak var textView: UITextView!
func textViewDidChange(textView: UITextView)
{
var contentSize = textView.sizeThatFits(CGSizeMake(textView.frame.size.width, CGFloat.max))
self.frame.size.height = contentSize.height + 20
self.textView.reloadInputViews()
}
}
我找到了这个 post:Changing the frame of an inputAccessoryView in iOS 8。说明正在创建一个自动创建的约束。问题是,它不会为我创造约束。无论如何,禁用或启用自动布局(也通过 setTranslatesAutoresizingMaskIntoConstraints())。
它适用于我 iOS7/iOS8:
class MessageInputAccessory: UIView, UITextViewDelegate {
private var textView: UITextView!
private var heightConstraint: NSLayoutConstraint?
override init(frame: CGRect) {
super.init(frame: frame)
commonInit()
}
required init(coder aDecoder: NSCoder) {
super.init(coder: aDecoder)
commonInit()
}
func commonInit() {
self.userInteractionEnabled = true
textView = UITextView()
textView.delegate = self
textView.bounces = false
textView.scrollEnabled = false
textView.layer.cornerRadius = 5
textView.layer.borderWidth = 1
textView.layer.borderColor = UIColor.blueColor().CGColor
self.addSubview(textView)
}
override func layoutSubviews() {
super.layoutSubviews()
textView.frame = self.bounds
}
override func addConstraint(constraint: NSLayoutConstraint) {
self.heightConstraint = constraint
super.addConstraint(constraint)
}
func textViewDidChange(textView: UITextView) {
var contentSize = textView.sizeThatFits(CGSizeMake(textView.frame.size.width, CGFloat.max))
self.frame.size.height = contentSize.height
if let heightConstraint = self.heightConstraint {
heightConstraint.constant = self.frame.size.height
}
self.textView.reloadInputViews()
}
}
编辑: 这也适用于 xib (iOS7/iOS8):
class MessageInputAccessory: UIView, UITextViewDelegate {
@IBOutlet var textView: UITextView!
@IBOutlet var textViewHeightConstraint: NSLayoutConstraint!
private var heightConstraint: NSLayoutConstraint?
override func awakeFromNib() {
textView.layer.cornerRadius = 5
textView.layer.borderWidth = 1
textView.layer.borderColor = UIColor.blueColor().CGColor
}
override func layoutSubviews() {
textViewHeightConstraint.constant = self.bounds.size.height
super.layoutSubviews()
}
override func addConstraint(constraint: NSLayoutConstraint) {
if constraint.firstItem === self {
self.heightConstraint = constraint
}
super.addConstraint(constraint)
}
override func addConstraints(constraints: [AnyObject]) {
super.addConstraints(constraints)
}
func textViewDidChange(textView: UITextView) {
var contentSize = textView.sizeThatFits(CGSizeMake(textView.frame.size.width, CGFloat.max))
self.frame.size.height = contentSize.height
if let heightConstraint = self.heightConstraint {
heightConstraint.constant = self.frame.size.height
}
self.textView.reloadInputViews()
}
override func intrinsicContentSize() -> CGSize {
return self.bounds.size;
}
}
这是我的xib:
这不是一个很好的解决方案,但它确实有效。如果您知道更好的方法,请告诉我。
一个相当简单的解决方法是根本不调整实际的 inputAccessoryView 大小 - 如果您知道它需要的最大高度,您可以在该最大高度创建它,使其透明,然后添加可以根据需要调整大小的子视图。
使它工作所需的细节是 inputAccessoryView 需要是包含以下内容的 UIView 子类:
- (BOOL)pointInside:(CGPoint)point withEvent:(UIEvent *)event
{
point = [self.innerView convertPoint:point fromView:self];
return [self.innerView pointInside:point withEvent:event];
}
(其中 self.innerView 是您动态调整大小的子视图)。
这使得它声明子视图内的点击,但传递任何落在它之外的点击。
要注意的主要缺点是键盘通知会给您包含整个最大高度 inputAccessoryView 的框架。因此,如果您使用它们来(例如)调整插图,则需要在那里做一些额外的数学运算。
SWIFT 5 解
如果有人像我一样一直试图在 Whosebug 中寻找输入附件视图的解决方案,我已经制作了一个简单的项目演示,用于使用 UITextView 动态调整输入附件的大小。它还在 UITextView 顶部带有一个可点击按钮,以演示在 Input Accessory View 顶部添加的视图。所有这些都加载在 XIB 中以便于定制。写在Swift 5,还负责X设备的安全区。
class InputAccessoryView: UIView, UITextViewDelegate {
@IBOutlet weak var textView: UITextView!
@IBOutlet weak var accessoryButtonViewHeightConstraint: NSLayoutConstraint!
@IBOutlet weak var accessoryButtonView: UIView!
// MARK: - Init
required init?(coder aDecoder: NSCoder) {
super.init(coder: aDecoder)
self.setup()
}
override init(frame: CGRect) {
super.init(frame: frame)
self.setup()
}
private func setup() {
let view = self.viewFromNibForClass()
view?.frame = self.bounds
view?.autoresizingMask = [.flexibleHeight, .flexibleWidth]
self.accessoryButtonViewHeightConstraint.constant = 0
if let view = view {
self.addSubview(view)
self.textView.translatesAutoresizingMaskIntoConstraints = false
}
}
override func didMoveToWindow() {
super.didMoveToWindow()
if let window = self.window {
self.bottomAnchor.constraint(lessThanOrEqualTo: window.safeAreaLayoutGuide.bottomAnchor).isActive = true
}
}
private func viewFromNibForClass() -> UIView? {
let bundle = Bundle(for: type(of: self))
let nib = UINib(nibName: String(describing: type(of: self)), bundle: bundle)
let view = nib.instantiate(withOwner: self, options: nil).first as? UIView
return view
}
func textViewDidChange(_ textView: UITextView) {
self.accessoryButtonViewHeightConstraint.constant = 40
self.accessoryButtonView.alpha = 1
self.updateHeight(textView.contentSize.height + 20 + self.accessoryButtonViewHeightConstraint.constant)
}
private func updateHeight(_ height: CGFloat) {
for constraint in self.constraints where constraint.firstAttribute == .height {
constraint.constant = height
}
}
@IBAction func accessoryButtonTouchUpInside(_ sender: Any) {
let height = self.frame.size.height - 40
self.updateHeight(height)
self.accessoryButtonViewHeightConstraint.constant = 0
}
}
基本上我试图在 inputAccessoryView 属性.
中创建一个调整大小的 UITextView我有一个 viewController,方法 canBecomeFirstResponder 返回 true 和一个视图,我通过自定义 class(从 XIB 获取它)实例化。在此视图中有一个 UITextView。
我尝试从 class 内部调整完整的 inputAccessoryView 的大小。我尝试了几种方法:设置框架方向,尝试使用高度限制。它似乎只调整了一半:
这基本上就是我想要的(有或没有自动布局,但在 iOS 7/8+ 中工作):
class MessageInputAccessory: UIView, UITextViewDelegate
{
@IBOutlet weak var textView: UITextView!
func textViewDidChange(textView: UITextView)
{
var contentSize = textView.sizeThatFits(CGSizeMake(textView.frame.size.width, CGFloat.max))
self.frame.size.height = contentSize.height + 20
self.textView.reloadInputViews()
}
}
我找到了这个 post:Changing the frame of an inputAccessoryView in iOS 8。说明正在创建一个自动创建的约束。问题是,它不会为我创造约束。无论如何,禁用或启用自动布局(也通过 setTranslatesAutoresizingMaskIntoConstraints())。
它适用于我 iOS7/iOS8:
class MessageInputAccessory: UIView, UITextViewDelegate {
private var textView: UITextView!
private var heightConstraint: NSLayoutConstraint?
override init(frame: CGRect) {
super.init(frame: frame)
commonInit()
}
required init(coder aDecoder: NSCoder) {
super.init(coder: aDecoder)
commonInit()
}
func commonInit() {
self.userInteractionEnabled = true
textView = UITextView()
textView.delegate = self
textView.bounces = false
textView.scrollEnabled = false
textView.layer.cornerRadius = 5
textView.layer.borderWidth = 1
textView.layer.borderColor = UIColor.blueColor().CGColor
self.addSubview(textView)
}
override func layoutSubviews() {
super.layoutSubviews()
textView.frame = self.bounds
}
override func addConstraint(constraint: NSLayoutConstraint) {
self.heightConstraint = constraint
super.addConstraint(constraint)
}
func textViewDidChange(textView: UITextView) {
var contentSize = textView.sizeThatFits(CGSizeMake(textView.frame.size.width, CGFloat.max))
self.frame.size.height = contentSize.height
if let heightConstraint = self.heightConstraint {
heightConstraint.constant = self.frame.size.height
}
self.textView.reloadInputViews()
}
}
编辑: 这也适用于 xib (iOS7/iOS8):
class MessageInputAccessory: UIView, UITextViewDelegate {
@IBOutlet var textView: UITextView!
@IBOutlet var textViewHeightConstraint: NSLayoutConstraint!
private var heightConstraint: NSLayoutConstraint?
override func awakeFromNib() {
textView.layer.cornerRadius = 5
textView.layer.borderWidth = 1
textView.layer.borderColor = UIColor.blueColor().CGColor
}
override func layoutSubviews() {
textViewHeightConstraint.constant = self.bounds.size.height
super.layoutSubviews()
}
override func addConstraint(constraint: NSLayoutConstraint) {
if constraint.firstItem === self {
self.heightConstraint = constraint
}
super.addConstraint(constraint)
}
override func addConstraints(constraints: [AnyObject]) {
super.addConstraints(constraints)
}
func textViewDidChange(textView: UITextView) {
var contentSize = textView.sizeThatFits(CGSizeMake(textView.frame.size.width, CGFloat.max))
self.frame.size.height = contentSize.height
if let heightConstraint = self.heightConstraint {
heightConstraint.constant = self.frame.size.height
}
self.textView.reloadInputViews()
}
override func intrinsicContentSize() -> CGSize {
return self.bounds.size;
}
}
这是我的xib:
这不是一个很好的解决方案,但它确实有效。如果您知道更好的方法,请告诉我。
一个相当简单的解决方法是根本不调整实际的 inputAccessoryView 大小 - 如果您知道它需要的最大高度,您可以在该最大高度创建它,使其透明,然后添加可以根据需要调整大小的子视图。
使它工作所需的细节是 inputAccessoryView 需要是包含以下内容的 UIView 子类:
- (BOOL)pointInside:(CGPoint)point withEvent:(UIEvent *)event
{
point = [self.innerView convertPoint:point fromView:self];
return [self.innerView pointInside:point withEvent:event];
}
(其中 self.innerView 是您动态调整大小的子视图)。
这使得它声明子视图内的点击,但传递任何落在它之外的点击。
要注意的主要缺点是键盘通知会给您包含整个最大高度 inputAccessoryView 的框架。因此,如果您使用它们来(例如)调整插图,则需要在那里做一些额外的数学运算。
SWIFT 5 解
如果有人像我一样一直试图在 Whosebug 中寻找输入附件视图的解决方案,我已经制作了一个简单的项目演示,用于使用 UITextView 动态调整输入附件的大小。它还在 UITextView 顶部带有一个可点击按钮,以演示在 Input Accessory View 顶部添加的视图。所有这些都加载在 XIB 中以便于定制。写在Swift 5,还负责X设备的安全区。
class InputAccessoryView: UIView, UITextViewDelegate {
@IBOutlet weak var textView: UITextView!
@IBOutlet weak var accessoryButtonViewHeightConstraint: NSLayoutConstraint!
@IBOutlet weak var accessoryButtonView: UIView!
// MARK: - Init
required init?(coder aDecoder: NSCoder) {
super.init(coder: aDecoder)
self.setup()
}
override init(frame: CGRect) {
super.init(frame: frame)
self.setup()
}
private func setup() {
let view = self.viewFromNibForClass()
view?.frame = self.bounds
view?.autoresizingMask = [.flexibleHeight, .flexibleWidth]
self.accessoryButtonViewHeightConstraint.constant = 0
if let view = view {
self.addSubview(view)
self.textView.translatesAutoresizingMaskIntoConstraints = false
}
}
override func didMoveToWindow() {
super.didMoveToWindow()
if let window = self.window {
self.bottomAnchor.constraint(lessThanOrEqualTo: window.safeAreaLayoutGuide.bottomAnchor).isActive = true
}
}
private func viewFromNibForClass() -> UIView? {
let bundle = Bundle(for: type(of: self))
let nib = UINib(nibName: String(describing: type(of: self)), bundle: bundle)
let view = nib.instantiate(withOwner: self, options: nil).first as? UIView
return view
}
func textViewDidChange(_ textView: UITextView) {
self.accessoryButtonViewHeightConstraint.constant = 40
self.accessoryButtonView.alpha = 1
self.updateHeight(textView.contentSize.height + 20 + self.accessoryButtonViewHeightConstraint.constant)
}
private func updateHeight(_ height: CGFloat) {
for constraint in self.constraints where constraint.firstAttribute == .height {
constraint.constant = height
}
}
@IBAction func accessoryButtonTouchUpInside(_ sender: Any) {
let height = self.frame.size.height - 40
self.updateHeight(height)
self.accessoryButtonViewHeightConstraint.constant = 0
}
}