Changing the frame of an inputAccessoryView in iOS 8

后端 未结 9 2118
遇见更好的自我
遇见更好的自我 2020-12-13 02:42

Long time lurker - first time poster!

I am having an issue while recreating a bar with a UITextView like WhatsApp does it.

I am using a custom <

相关标签:
9条回答
  • 2020-12-13 02:55

    The issue is that in iOS 8, an NSLayoutConstraint that sets the inputAccessoryView's height equal to its initial frame height is installed automatically. In order to fix the layout problem, you need to update that constraint to the desired height and then instruct your inputAccessoryView to lay itself out.

    - (void)changeInputAccessoryView:(UIView *)inputAccessoryView toHeight:(CGFloat)height {
        for (NSLayoutConstraint *constraint in [inputAccessoryView constraints]) {
            if (constraint.firstAttribute == NSLayoutAttributeHeight) {
                constraint.constant = height;
                [inputAccessoryView layoutIfNeeded];
                break;
            }
        }
    }
    
    0 讨论(0)
  • 2020-12-13 02:57

    frist, get inputAccessoryView and set nil

    UIView *inputAccessoryView = yourTextView.inputAccessoryView;
    yourTextView.inputAccessoryView = nil;
    [yourTextView reloadInputViews];
    

    then set frame and layout

    inputAccessoryView.frame = XXX
    [inputAccessoryView setNeedsLayout];
    [inputAccessoryView layoutIfNeeded];
    

    last set new inputAccessoryView again and reload

    yourTextView.inputAccessoryView = inputAccessoryView;
    [yourTextView reloadInputViews];
    
    0 讨论(0)
  • 2020-12-13 03:04

    To fix this I used inputAccessoryView.autoresizingMask = UIViewAutoresizingFlexibleHeight;

    But of course this caused my textview to collapse. So adding a constraint to the toolbar and updating it when I have to, or adding the constraint to the textview itself and update it worked for me.

    0 讨论(0)
  • 2020-12-13 03:05

    Yep, iOS8 adds a private height constraint to the inputAccessoryView.

    Taking into account that recreating whole inputAccessoryView and replace old one is can be really expensive operation, you can just remove constraints before reload input views

    [inputAccessoryView removeConstraints:[inputAccessoryView constraints]];
    [textView reloadInputViews];
    

    Just another workaround

    0 讨论(0)
  • 2020-12-13 03:08

    To sum up JohnnyC's answer: set your inpitAccessoryView's autoresizingMask to .flexibleHeight, calculate its intrinsicContentSize and let the framework do the rest.

    Full code, updated for Swift 3:

    class InputAccessoryView: UIView, UITextViewDelegate {
    
        let textView = UITextView()
    
        override var intrinsicContentSize: CGSize {
            // Calculate intrinsicContentSize that will fit all the text
            let textSize = textView.sizeThatFits(CGSize(width: textView.bounds.width, height: CGFloat.greatestFiniteMagnitude))
            return CGSize(width: bounds.width, height: textSize.height)
        }
    
        override init(frame: CGRect) {
            super.init(frame: frame)
    
            // This is required to make the view grow vertically
            autoresizingMask = .flexibleHeight
    
            // Setup textView as needed
            addSubview(textView)
            textView.translatesAutoresizingMaskIntoConstraints = false
            addConstraints(NSLayoutConstraint.constraints(withVisualFormat: "H:|[textView]|", options: [], metrics: nil, views: ["textView": textView]))
            addConstraints(NSLayoutConstraint.constraints(withVisualFormat: "V:|[textView]|", options: [], metrics: nil, views: ["textView": textView]))
    
            textView.delegate = self
    
            // Disabling textView scrolling prevents some undesired effects,
            // like incorrect contentOffset when adding new line,
            // and makes the textView behave similar to Apple's Messages app
            textView.isScrollEnabled = false
        }
    
        required init?(coder aDecoder: NSCoder) {
            fatalError("init(coder:) has not been implemented")
        }
    
        // MARK: UITextViewDelegate
    
        func textViewDidChange(_ textView: UITextView) {
            // Re-calculate intrinsicContentSize when text changes
            invalidateIntrinsicContentSize()
        }
    
    }
    
    0 讨论(0)
  • 2020-12-13 03:08

    100% working and very simple solution is to enumerate all constraints and set new height value. Here is some C# code (xamarin):

    foreach (var constraint in inputAccessoryView.Constraints)
    {
        if (constraint.FirstAttribute == NSLayoutAttribute.Height)
        {
            constraint.Constant = newHeight;
        }
    }
    
    0 讨论(0)
提交回复
热议问题