Search code examples
iosnativescriptnativescript-angularnativescript-telerik-uiradlistview

Nativescript Chat UI iOS Issues


I am creating a chat UI interface in Nativescript and I almost have everything working, but I am having a few issues in iOS that I cannot figure out. Everything in Android works correctly.

Problem 1:

  • When I focus on the TextView and the keyboard opens up I cannot no longer scroll to the top of the chat. All the content seems to shift up (even without using IQKeyboardManager interestly enough).

Problem 2:

  • When I start typing in the TextView it instantly shifts to the bottom of the screen, hidden behind the keyboard and I cannot see what I am typing.

Here is a demo project I created on Playground that shows the problem. Playground Demo Project

Below is a GIF showing both of the issues.

Any help is appreciated. Thanks!

Chat UI Demo


Solution

  • Problem 1:

    This is because IQKeyboardManager hosts a ScrollView on top of the ViewController (Page) and RadListView has its own scrollable region. The solution would be adjusting the insets when keyboard is active.

    The code below takes keyboard height and caches it in application object when its first shown.

    import * as application from "@nativescript/core/application";
    
    let observer = application.ios.addNotificationObserver(
        UIKeyboardDidShowNotification,
        notification => {
            application.ios.removeNotificationObserver(
                observer,
                UIKeyboardDidShowNotification
            );
            (application as any)._keyboardHeight = notification.userInfo.valueForKey(
                UIKeyboardFrameBeginUserInfoKey
            ).CGRectValue.size.height;
        }
    );
    

    When text field is focused adjust the insets of list view

    textFieldFocus() {
            console.log("Focus on TextField");
            (this
                .radList as any)._originalContentInset = this.radList.ios.contentInset;
            if ((application as any)._keyboardHeight) {
                this.radList.ios.contentInset = UIEdgeInsetsMake(
                    (application as any)._keyboardHeight,
                    0,
                    0,
                    0
                );
            } else {
                setTimeout(() => this.textFieldFocus(), 100);
            }
        }
    

    Problem 2:

    This is because the text view layouts itself when text is updated. Preventing that may keep the scroll position intact. The override below checks if the field is focused and ignores layout calls.

    import { TextView } from "@nativescript/core/ui/text-view";
    
    TextView.prototype.requestLayout = function() {
        if (
            !arguments[0] &&
            this.nativeViewProtected &&
            this.nativeViewProtected.isFirstResponder
        ) {
            this.nativeViewProtected.setNeedsLayout();
            IQKeyboardManager.sharedManager().reloadLayoutIfNeeded();
        } else {
            View.prototype.requestLayout.call(this);
        }
    };
    

    Updated Playground