Solución de Xamarin para: UITableView y problema de desplazamiento del teclado

Estaba teniendo el mismo problema que se describe en Problema de desplazamiento del teclado y UITableView pero estoy codificando en C# usando MonoTouch/Xamarin.iOS. Tomó un poco de trabajo obtener una solución de C# que funcionara, así que pensé en compartirla.

El problema que estaba tratando de resolver: tengo un UIViewController que contiene una vista de lista y algunos otros botones. Las filas son en sí mismas vistas personalizadas que contienen varias UILabels inertes y una UITextView que acepta entradas. Si el usuario tocó uno de los TextViews en la mitad inferior de la pantalla, el teclado cubriría el campo que estaba editando. Y, además, si fuera el final de la lista, ni siquiera podría desplazarse manualmente para verla.

Recibí tanta ayuda al leer las publicaciones en este sitio, que quería devolver algo. Al reunir fragmentos de varias publicaciones, creo que tengo una solución de C# (razonablemente) simple y que funciona. No tengo suficiente reputación para publicar un comentario, así que estoy creando una pregunta y respondiendo con la esperanza de que otros puedan ahorrar algo de tiempo. Vea a continuación mi solución y, por favor, avíseme si me falta algo.

preguntado el 14 de febrero de 14 a las 01:02

2 Respuestas

Aquí está solo el código relevante para ajustar el teclado y descartar el teclado cuando el usuario toca fuera de TextView (y el teclado).

Debo señalar que la advertencia es que mi TableView está en la parte inferior de la pantalla, por lo que no tengo que averiguar cómo se superpone con el teclado. Si tiene cosas debajo de TableView, deberá agregar algunas matemáticas.

public partial class myViewController : UIViewController
{
    UITapGestureRecognizer _tap;
    NSObject _shownotification;
    NSObject _hidenotification;

    public myViewController() : base("myViewController", null)
    {
        // This code dismisses the keyboard when the user touches anywhere
        // outside the keyboard.
        _tap = new UITapGestureRecognizer();
        _tap.AddTarget(() =>{
            View.EndEditing(true);
        });
        _tap.CancelsTouchesInView = false;
        View.AddGestureRecognizer(_tap);
    }

    public override void ViewWillAppear(bool animated)
    {
        base.ViewWillAppear(animated);

        // Register our callbacks
        _hidenotification = UIKeyboard.Notifications.ObserveDidHide(HideCallback);
        _shownotification = UIKeyboard.Notifications.ObserveWillShow(ShowCallback);
    }

    public override void ViewWillDisappear(bool animated)
    {
        // Unregister the callbacks
        if (_shownotification != null)
            _shownotification.Dispose();
        if (_hidenotification != null)
            _hidenotification.Dispose();

        base.ViewWillDisappear(animated);
    }

    void ShowCallback (object sender, MonoTouch.UIKit.UIKeyboardEventArgs args)
    {
        // This happens if the user focuses a textfield outside of the
        // tableview when the tableview is empty.
        UIView activeView = this.View.FindFirstResponder();
        if ((activeView == null) || (activeView == Customer))
            return;

        // Get the size of the keyboard
        RectangleF keyboardBounds = args.FrameEnd;

        // Create an inset and assign it to the tableview
        UIEdgeInsets contentInsets = new UIEdgeInsets(0.0f, 0.0f, keyboardBounds.Size.Height, 0.0f);
        myTableView.ContentInset = contentInsets;
        myTableView.ScrollIndicatorInsets = contentInsets;

        // Make sure the tapped location is visible.
        myTableView.ScrollRectToVisible(activeView.Frame, true);
    }

    void HideCallback (object sender, MonoTouch.UIKit.UIKeyboardEventArgs args)
    {
        // If the tableView's ContentInset is "zero", we don't need to
        // readjust the size
        if (myTableView.ContentInset.Top == UIEdgeInsets.Zero.Top)
            return;

        // Remove the inset when the keyboard is hidden so that the
        // TableView will use the whole screen again.
        UIView.BeginAnimations (""); {
            UIView.SetAnimationCurve (args.AnimationCurve);
            UIView.SetAnimationDuration (args.AnimationDuration);
            var viewFrame = View.Frame;
            var endRelative = View.ConvertRectFromView (args.FrameEnd, null);
            viewFrame.Height = endRelative.Y;
            View.Frame = viewFrame;

            myTableView.ContentInset = UIEdgeInsets.Zero;
            myTableView.ScrollIndicatorInsets = UIEdgeInsets.Zero;
        } UIView.CommitAnimations ();
    }
}

Gracias mick por publicar la solución de Objective-C.

contestado el 23 de mayo de 17 a las 13:05

Una ligera modificación explica la altura de una barra de herramientas en la parte inferior de la página. Además, una declaración de interrupción abandona el bucle foreach una vez que se identifica la vista de "primer respondedor":

void ShowCallback(object sender, UIKit.UIKeyboardEventArgs args)
        {
            // This happens if the user focuses a textfield outside of the
            // tableview when the tableview is empty.

            UIView activeView = new UIView();
            // Find what opened the keyboard
            foreach (UIView view in this.View.Subviews)
            {
                if (view.IsFirstResponder)
                {
                    activeView = view;
                    break;
                }
            }

            // Get the size of the keyboard
            var keyboardBounds = args.FrameEnd;

            // Create an inset and assign it to the tableview

            //need to subtract the navbar at the bottom of the scree
            nfloat toolbarHeight = 0f;
            if (!this.NavigationController.ToolbarHidden)
            {
                toolbarHeight = this.NavigationController.Toolbar.Frame.Height;
            }

            nfloat adjustedInset = keyboardBounds.Size.Height - toolbarHeight;

            UIEdgeInsets contentInsets = new UIEdgeInsets(0.0f, 0.0f, adjustedInset, 0.0f);
            ExerciseTableView.ContentInset = contentInsets;
            ExerciseTableView.ScrollIndicatorInsets = contentInsets;

            // Make sure the tapped location is visible.
            ExerciseTableView.ScrollRectToVisible(activeView.Frame, true);
        }

Respondido 06 Oct 16, 18:10

No es la respuesta que estás buscando? Examinar otras preguntas etiquetadas or haz tu propia pregunta.