Resizing text field in inputAccessoryView

2019-03-19 20:12发布

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:

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:

Emotion view

And when one is chosen, it shows in a floating label:

Floating emotion

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="                

2条回答
叛逆
2楼-- · 2019-03-19 20:41

I have solved this problem with AutoLayout. I have added a new constraint defining the height of my UITextField and I am setting the constant of that constraint in textView(textView: UITextView, shouldChangeTextInRange range: NSRange, replacementText text: String) -> Bool:

func textView(textView: UITextView, shouldChangeTextInRange range: NSRange, replacementText text: String) -> Bool {
    let oldHeight = textView.frame.height
    let newText = (textView.text as NSString).stringByReplacingCharactersInRange(range, withString: text)
    let newSize = (newText as NSString).boundingRectWithSize(CGSize(width: textView.frame.width - textView.textContainerInset.right - textView.textContainerInset.left - 10, height: CGFloat.max), options: .UsesLineFragmentOrigin, attributes: [NSFontAttributeName: textView.font], context: nil)
    let heightChange = newSize.height + textView.textContainerInset.top + textView.textContainerInset.bottom + 2.719 - oldHeight

    textFieldHeightLayoutConstraint.constant += heightChange
    return true
}

The problem I had was that I was setting AutoLayout and UIView.frame to different settings, which lead to them fighting.

I am an idiot.

查看更多
狗以群分
3楼-- · 2019-03-19 20:57

I solved this issue with resizing inputAccessoryView long time ago, but did not fix the issues with proper UITextView resize for iOS8 until today. Here is my sample app - github

It uses frames for iOS7 resizing (UITextEffectsWindow does layout manually and creating constraints in inputAccessoryView's heirarchy means creating autolayout engine, which causes autolayout engine failure after strange transformations with inf/nan frames) and constraints for iOS8 resizing. Anyway, layout of views inside inputAccessoryView is never done correctly, so we have to perform frame calculations.

Example1 Example2

查看更多
登录 后发表回答