I have been trying to get a UITextView
to resize all week. I don't see how this should be done, so I have decided to include practically all relevant code.
I have this conversation view:
This conversationview is a UIViewController
with a UITableView
inside (using constraints). I have a custom UIView
subclass ConversationToolbar
set as inputAccessoryView
(the UIViewController
containing it can become the first responder, so the view is visible at all times), that contains 2 subviews. One for the UITextView
and left and right buttons, and one for the emoticons. The emoticons only show when the left button is tapped:
And when one is chosen, it shows in a floating label:
I now have trouble to resize this UITextView
when multiple lines are used. I have tried calculating all frames myself, but then that seems to conflict with my constraints in some weird way. Almost always is the UITextView
either too small or it resizes only after I press another key to update the view. Or the UITextView
gets bigger over the keyboard, or it slides out of view when the keyboard is dismissed.
I have removed all resizing abilities from my code and I would like to know what I need to do to make this resize.
In my ConversationViewController
:
var toolbar: ConversationToolbar!
override var inputAccessoryView: UIView! {
get {
if toolbar == nil {
toolbar = NSBundle.mainBundle().loadNibNamed("ConversationToolbar", owner: nil, options: nil).last! as ConversationToolbar
toolbar.frame.size = CGSize(width: UIScreen.mainScreen().bounds.size.width, height: 80)
toolbar.delegate = self
toolbar.setDraft(conversation.draft)
}
return toolbar
}
}
With ConversationToolbar.xib
being:
<?xml version="1.0" encoding="UTF-8" standalone="no"?>
<document type="com.apple.InterfaceBuilder3.CocoaTouch.XIB" version="3.0" toolsVersion="6254" systemVersion="14D87p" targetRuntime="iOS.CocoaTouch" propertyAccessControl="none" useAutolayout="YES" useTraitCollections="YES">
<dependencies>
<plugIn identifier="com.apple.InterfaceBuilder.IBCocoaTouchPlugin" version="6247"/>
</dependencies>
<objects>
<placeholder placeholderIdentifier="IBFilesOwner" id="-1" userLabel="File's Owner"/>
<placeholder placeholderIdentifier="IBFirstResponder" id="-2" customClass="UIResponder"/>
<view contentMode="scaleToFill" id="iN0-l3-epB" customClass="ConversationToolbar" customModule="Heaven_Help" customModuleProvider="target">
<rect key="frame" x="0.0" y="0.0" width="600" height="600"/>
<autoresizingMask key="autoresizingMask" widthSizable="YES" heightSizable="YES"/>
<subviews>
<view contentMode="scaleToFill" translatesAutoresizingMaskIntoConstraints="NO" id="s5O-PN-dtz">
<rect key="frame" x="0.0" y="554" width="600" height="46"/>
<subviews>
<button opaque="NO" contentMode="scaleToFill" horizontalCompressionResistancePriority="749" contentHorizontalAlignment="center" contentVerticalAlignment="center" buttonType="roundedRect" lineBreakMode="middleTruncation" translatesAutoresizingMaskIntoConstraints="NO" id="pbw-hg-sNn">
<rect key="frame" x="0.0" y="0.0" width="36" height="46"/>
<inset key="contentEdgeInsets" minX="8" minY="0.0" maxX="8" maxY="0.0"/>
<state key="normal" title="πΆ">
<color key="titleShadowColor" white="0.5" alpha="1" colorSpace="calibratedWhite"/>
</state>
<connections>
<action selector="emoPress:" destination="iN0-l3-epB" eventType="touchUpInside" id="hLw-rH-Hym"/>
</connections>
</button>
<button opaque="NO" contentMode="scaleToFill" contentHorizontalAlignment="center" contentVerticalAlignment="center" buttonType="roundedRect" lineBreakMode="middleTruncation" translatesAutoresizingMaskIntoConstraints="NO" id="Vid-Ac-jz3">
<rect key="frame" x="548" y="0.0" width="52" height="46"/>
<inset key="contentEdgeInsets" minX="8" minY="0.0" maxX="8" maxY="0.0"/>
<state key="normal" title="Send">
<color key="titleShadowColor" white="0.5" alpha="1" colorSpace="calibratedWhite"/>
</state>
<connections>
<action selector="sendPress:" destination="iN0-l3-epB" eventType="touchUpInside" id="rzU-Vk-nJa"/>
</connections>
</button>
<textView clipsSubviews="YES" multipleTouchEnabled="YES" contentMode="scaleToFill" translatesAutoresizingMaskIntoConstraints="NO" id="Czv-f6-jOP">
<rect key="frame" x="36" y="8" width="512" height="30"/>
<color key="backgroundColor" white="1" alpha="1" colorSpace="calibratedWhite"/>
<fontDescription key="fontDescription" type="system" pointSize="14"/>
<textInputTraits key="textInputTraits" autocapitalizationType="sentences"/>
</textView>
</subviews>
<color key="backgroundColor" white="1" alpha="1" colorSpace="calibratedWhite"/>
<constraints>
<constraint firstAttribute="height" constant="46" id="D1D-QM-5n2"/>
<constraint firstAttribute="trailing" secondItem="Vid-Ac-jz3" secondAttribute="trailing" id="H9Y-xT-aqe"/>
<constraint firstAttribute="centerY" secondItem="pbw-hg-sNn" secondAttribute="centerY" id="IYf-5R-S97"/>
<constraint firstItem="Czv-f6-jOP" firstAttribute="leading" secondItem="pbw-hg-sNn" secondAttribute="trailing" id="LpH-ir-M9U"/>
<constraint firstAttribute="centerY" secondItem="Vid-Ac-jz3" secondAttribute="centerY" id="NQ1-m1-9rk"/>
<constraint firstAttribute="bottom" secondItem="Vid-Ac-jz3" secondAttribute="bottom" id="UUt-1r-emN"/>
<constraint firstItem="Czv-f6-jOP" firstAttribute="top" secondItem="s5O-PN-dtz" secondAttribute="top" constant="8" id="VWB-7N-LrK"/>
<constraint firstAttribute="bottom" secondItem="Czv-f6-jOP" secondAttribute="bottom" constant="8" id="WTi-8a-kaM"/>
<constraint firstItem="pbw-hg-sNn" firstAttribute="leading" secondItem="s5O-PN-dtz" secondAttribute="leading" id="a4Q-W4-ROh"/>
<constraint firstAttribute="bottom" secondItem="pbw-hg-sNn" secondAttribute="bottom" id="hGG-Xe-FZZ"/>
<constraint firstItem="Vid-Ac-jz3" firstAttribute="leading" secondItem="Czv-f6-jOP" secondAttribute="trailing" id="jc6-18-MYq"/>
</constraints>
</view>
<view contentMode="scaleToFill" translatesAutoresizingMaskIntoConstraints="NO" id="rh6-cD-U1e">
<rect key="frame" x="0.0" y="508" width="600" height="46"/>
<color key="backgroundColor" white="1" alpha="1" colorSpace="calibratedWhite"/>
</view>
<label opaque="NO" userInteractionEnabled="NO" contentMode="left" horizontalHuggingPriority="251" verticalHuggingPriority="251" text="Label" lineBreakMode="tailTruncation" baselineAdjustment="alignBaselines" adjustsFontSizeToFit="NO" translatesAutoresizingMaskIntoConstraints="NO" id="6zz-GF-eHs">
<rect key="frame" x="279" y="525" width="42" height="21"/>
<fontDescription key="fontDescription" type="system" pointSize="17"/>
<color key="textColor" cocoaTouchSystemColor="darkTextColor"/>
<nil key="highlightedColor"/>
</label>
</subviews>
<color key="backgroundColor" white="1" alpha="1" colorSpace="custom" customColorSpace="calibratedWhite"/>
<constraints>
<constraint firstAttribute="centerX" secondItem="6zz-GF-eHs" secondAttribute="centerX" id="3at-fx-ZCR"/>
<constraint firstAttribute="bottom" secondItem="s5O-PN-dtz" secondAttribute="bottom" id="3r5-GG-6Eo"/>
<constraint firstItem="s5O-PN-dtz" firstAttribute="height" secondItem="rh6-cD-U1e" secondAttribute="height" id="MBP-k2-Qre"/>
<constraint firstItem="s5O-PN-dtz" firstAttribute="leading" secondItem="iN0-l3-epB" secondAttribute="leading" id="PLK-DE-38r"/>
<constraint firstItem="s5O-PN-dtz" firstAttribute="top" secondItem="6zz-GF-eHs" secondAttribute="bottom" constant="8" symbolic="YES" id="PRr-qQ-oyf"/>
<constraint firstAttribute="trailing" secondItem="s5O-PN-dtz" secondAttribute="trailing" id="PqA-VB-NxV"/>
<constraint firstItem="s5O-PN-dtz" firstAttribute="top" secondItem="rh6-cD-U1e" secondAttribute="bottom" id="ZxJ-8p-Mjq"/>
<constraint firstItem="rh6-cD-U1e" firstAttribute="leading" secondItem="iN0-l3-epB" secondAttribute="leading" id="lsS-5I-Saq"/>
<constraint firstAttribute="trailing" secondItem="rh6-cD-U1e" secondAttribute="trailing" id="yRP-hS-dpr"/>
</constraints>
<connections>
<outlet property="emoButton" destination="pbw-hg-sNn" id="VJx-J0-hBJ"/>
<outlet property="emoLabel" destination="6zz-GF-eHs" id="pUW-yD-pIq"/>
<outlet property="emoView" destination="rh6-cD-U1e" id="0YV-Wx-clp"/>
<outlet property="sendButton" destination="Vid-Ac-jz3" id="6FV-Q2-ufA"/>
<outlet property="textSuperView" destination="s5O-PN-dtz" id="BIT-bH-p4M"/>
<outlet property="textView" destination="Czv-f6-jOP" id="syf-v4-LLy"/>
</connections>
</view>
</objects>
</document>
And finally my ConversationToolbar.swift
:
import Foundation
class ConversationToolbar: UIView, UITextViewDelegate {
@IBOutlet weak var textView: UITextView!
@IBOutlet weak var emoView: UIView!
@IBOutlet weak var sendButton: UIButton!
@IBOutlet weak var textSuperView: UIView!
@IBOutlet weak var emoButton: UIButton!
@IBOutlet weak var emoLabel: UILabel!
var delegate: ConversationToolbarDelegate!
var emobuttons: [String: UIButton]!
var emoSelected: String?
var clickableSend: Bool {
get {
return ((delegate?.hasEnoughCredits() ?? false) && !(textView?.text?.isEmpty ?? true)) ?? false
}
}
override func awakeFromNib() {
textView.delegate = self
sendButton.enabled = clickableSend
self.autoresizingMask = .FlexibleHeight
// Make textView pretty
textView.backgroundColor = UIColor.whiteColor() // (white: 250/255, alpha: 1)
textView.font = UIFont.systemFontOfSize(17)
textView.layer.borderColor = UIColor(red: 200/255, green: 200/255, blue: 205/255, alpha:1).CGColor
textView.layer.borderWidth = 0.5
textView.layer.cornerRadius = 5
textView.scrollsToTop = false
textView.textContainerInset = UIEdgeInsetsMake(4, 3, 3, 3)
textView.autoresizingMask = .FlexibleHeight
// Add a nice border to the view
textSuperView.layer.borderColor = UIColor(red: 200/255, green: 200/255, blue: 205/255, alpha:1).CGColor
textSuperView.layer.borderWidth = 0.5
textSuperView.backgroundColor = UIColor(white: 235/255, alpha: 1)
textSuperView.autoresizingMask = .FlexibleHeight
// Prettify emoView
emoView.layer.borderColor = UIColor(red: 200/255, green: 200/255, blue: 205/255, alpha:1).CGColor
emoView.layer.borderWidth = 0.5
emoView.backgroundColor = UIColor(white: 235/255, alpha: 1)
// Emobar setup
emobuttons = StaticData.getEmoButtons()
let unusedSpace = UIScreen.mainScreen().bounds.width - emobuttons.sum {
button in
return button.intrinsicContentSize().width
}
let spaceBetweenButtons = Int(unusedSpace) / (emobuttons.count + 1)
var visualLayout = "H:|"
for button in emobuttons {
button.1.setTranslatesAutoresizingMaskIntoConstraints(false)
visualLayout += "-(space)-[\(button.0)]"
emoView.addSubview(button.1)
button.1.addTarget(self, action: "emoChosen:", forControlEvents: .TouchUpInside)
}
emoView.addConstraints(NSLayoutConstraint.constraintsWithVisualFormat("\(visualLayout)-(space)-|", options: .AlignAllCenterY, metrics: ["space":spaceBetweenButtons], views: emobuttons))
emoView.addConstraint(NSLayoutConstraint(item: emoView, attribute: .CenterY, relatedBy: .Equal, toItem: emobuttons.values.array.first!, attribute: .CenterY, multiplier: 1, constant: 0))
// Prettify toolbar itself
self.backgroundColor = UIColor.clearColor()
// start hidden
emoView.hidden = true
emoLabel.hidden = emoSelected == nil
}
@IBAction func emoPress(sender: UIButton) {
emoView.hidden = !emoView.hidden
updateEmoLabel()
if !emoView.hidden {
emoLabel.hidden = true
}
}
@IBAction func sendPress(sender: UIButton) {
delegate.sendMessage(textView.text, feeling: emoSelected)
textView.text = ""
emoSelected = nil
sendButton.enabled = false
textViewDidChange(textView)
updateEmoLabel()
}
func emoChosen(sender: UIButton) {
emoView.hidden = true
emoSelected = sender.titleLabel?.text == "π«" ? nil : sender.titleLabel?.text
updateEmoLabel()
}
func setDraft(draft: String) {
textView.text = draft
}
func updateEmoLabel() {
emoLabel.text = emoSelected
emoLabel.hidden = emoSelected == nil
}
/// MARK: UITextFieldDelegate
func textViewDidChange(textView: UITextView) {
sendButton.enabled = clickableSend
}
}
protocol ConversationToolbarDelegate {
func sendMessage(text: String, feeling: String?)
func hasEnoughCredits() -> Bool
}