Mucho tiempo lurker – primer cartel!

Estoy teniendo un problema, mientras que la recreación de una barra con un UITextView como WhatsApp hace.

Estoy usando una costumbre UIView subclase, y perezosamente instanciar en:

- (UIView *)inputAccessoryView

y volviendo en SÍ:

- (BOOL)canBecomeFirstResponder

Ahora, quiero cambiar el tamaño de la inputAccessoryView cuando el UITextView crece en tamaño. En iOS 7, solo quiero cambiar el tamaño del marco de dicha vista – y no es de origen -, y, a continuación, llamar a reloadInputViews y que iba a funcionar: la vista se mueve hacia arriba de modo que es totalmente visible por encima del teclado.

En iOS 8, sin embargo, esto no funciona. La única forma de hacer el trabajo es para cambiar también el origen de la imagen a un valor negativo. Esto estaría bien, excepto que crea algunas fallas extrañas: por ejemplo, la UIView vuelve al ‘original’ de marco al entrar en cualquier texto.

Hay algo que me estoy perdiendo? Yo estoy bastante seguro de que WhatsApp utiliza inputAccessoryView porque de la manera que despedir el teclado de arrastre – sólo en la versión más reciente de la aplicación.

Por favor, hágamelo saber si usted me puede ayudar! O si hay alguna prueba que me gustaría correr!

Gracias! 🙂

Por CIERTO, aquí está el código que estoy utilizando para la actualización de la altura de la costumbre UIView llamado composeBar:

//ComposeBar frame size
CGRect frame = self.composeBar.frame;
frame.size.height += heightDifference;
frame.origin.y -= heightDifference;
self.composeBar.frame = frame;
[self.composeBar.textView reloadInputViews]; //Tried with this
[self reloadInputViews];                     //and this

Edit: el código fuente completo está disponible @ https://github.com/manuelmenzella/SocketChat-iOS

9 Comentarios

  1. 33

    He estado golpeando mi cabeza contra la pared en este caso por bastante tiempo, ya que el comportamiento ha cambiado de iOS 7 a iOS 8. He probado de todo, hasta que la solución más obvia de todas trabajado para mí:

    inputAccessoryView.autoresizingMask = UIViewAutoresizingFlexibleHeight;

    duh!

    • Yo estaba haciendo exactamente lo mismo que usted. No creo que yo hubiera pensado en esto. Increíble!
    • He utilizado tu sugerencia en combinación con – (CGSize)intrinsicContentSize y ahora funciona. Sólo que la línea de código no funciona.
    • Y, a continuación, llamar -invalidateIntrinsicContentSize en el accesorio de la vista después de realizar los cambios.
    • Solución agradable! He aquí un completo trabajo código de ejemplo en mi respuesta: stackoverflow.com/a/32647908/3160561
    • ‘preciate! este es el mejor sol.
  2. 17

    Para resumir JohnnyC del respuesta: conjunto de su inpitAccessoryView del autoresizingMask a .flexibleHeight, calcular su intrinsicContentSize y dejar que el marco de hacer el resto.

    Código completo, actualizado para 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()
        }
    
    }
    • gracias, funciona para mí! ha habido un ligero cambio, en Swift 3 intristicContentSize no es una función ya que es una variable de ahora.
    • gracias por darse cuenta de esto, he actualizado el código Swift 3.
  3. 5

    El problema es que en iOS 8, una NSLayoutConstraint que establece el inputAccessoryView altura igual a su marco inicial de la altura se instala automáticamente. Con el fin de solucionar el problema de diseño, es necesario actualizar esa restricción a la altura deseada y, a continuación, pida a su inputAccessoryView a poner a sí mismo.

    - (void)changeInputAccessoryView:(UIView *)inputAccessoryView toHeight:(CGFloat)height {
        for (NSLayoutConstraint *constraint in [inputAccessoryView constraints]) {
            if (constraint.firstAttribute == NSLayoutAttributeHeight) {
                constraint.constant = height;
                [inputAccessoryView layoutIfNeeded];
                break;
            }
        }
    }
    • duplica mi respuesta
    • Nunca vi su respuesta (he 237 por LO puntos y han sido en MODO de ~4 años; claro que no me importa lo suficiente como para «duplicar» su respuesta). Por otra parte, su respuesta es en C# (poco común para iOS clientes) y no la fuerza de la inputAccessoryView a poner a sí mismo.
    • Estado luchando con este problemas para los días hasta que me encontró su respuesta.
    • no funcionará si usted no utilice restricciones
  4. 5

    Aquí una completa autónomos de solución (gracias @JohnnyC y @JoãoNunes para que me apunta en la dirección correcta, @stigi para explicar cómo animar intrinsicContent cambios):

    class InputAccessoryView: UIView {
    
        //InputAccessoryView is instantiated from nib, but it's not a requirement
        override func awakeFromNib() {
            super.awakeFromNib()        
            autoresizingMask = .FlexibleHeight
        }
    
        override func intrinsicContentSize() -> CGSize {
            let exactHeight = //calculate exact height of your view here
            return CGSize(width: UIViewNoIntrinsicMetric, height: exactHeight)
        }
    
        func somethingDidHappen() {
            //invalidate intrinsic content size, animate superview layout        
            UIView.animateWithDuration(0.2) {
                self.invalidateIntrinsicContentSize()
                self.superview?.setNeedsLayout()
                self.superview?.layoutIfNeeded()
            }
        }
    }
    • gracias amable señor! Esto funciona como un encanto!
    • Creo que esta es la mejor solución, pero ha sido en torno al tema que se llama dentro de la animan bloque de evitar el teclado de la notificación para que se desencadene? Por lo tanto, no es posible ajustar el desplazamiento de la vista de las posiciones…
    • no, yo no recuerdo haber dicho problema
    • 🙁 … tal vez está relacionado con iOS 9, raro.
  5. 3

    100% de trabajo y solución muy sencilla es la enumeración de todas las restricciones y establecer nuevo valor de altura. He aquí algunos de código de C# (xamarin):

    foreach (var constraint in inputAccessoryView.Constraints)
    {
        if (constraint.FirstAttribute == NSLayoutAttribute.Height)
        {
            constraint.Constant = newHeight;
        }
    }
  6. 1

    Por desgracia, iOS8 añade un privado altura de la restricción a la inputAccessoryView, y esta restricción es no público.

    Recomiendo recreando el accesorio de la vista cuando su marco debe cambiar, y llame a reloadInputViews para que el nuevo es instalado.

    Esto es lo que yo hago, y que funciona como se espera.

    • OK, que bueno saber que por lo menos! Muchas gracias por su ayuda! ¿Te importaría compartir el código que se encarga de cambiar el tamaño y mover de la vista?
    • Como dije en mi comentario: cuando la entrada de accesorios de vista debe cambiar su marco, se debe reemplazar.
  7. 1

    Sí, iOS8 añade un privado altura de la restricción a la inputAccessoryView.

    Teniendo en cuenta que recrear todo el inputAccessoryView y reemplazar el viejo se puede ser realmente costoso de la operación, usted puede simplemente eliminar los obstáculos antes de volver a cargar la entrada de vistas

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

    Sólo otra solución

  8. 0

    Para solucionar esto he utilizado inputAccessoryView.autoresizingMask = UIViewAutoresizingFlexibleHeight;

    Pero por supuesto, esto hizo que mi textview al colapso.
    Así que la adición de una restricción a la barra de herramientas y actualización de la misma cuando tengo que, o añadiendo la restricción a la textview sí mismo y de actualización, que trabajó para mí.

  9. 0

    frist, obtener inputAccessoryView y establecer nil

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

    a continuación, establecer el marco y diseño

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

    último conjunto nuevo inputAccessoryView de nuevo y volver a cargar

    yourTextView.inputAccessoryView = inputAccessoryView;
    [yourTextView reloadInputViews];

Dejar respuesta

Please enter your comment!
Please enter your name here