ios - ionic 3 输入项在 iOS 上不显示插入符号

标签 ios keyboard ionic3

我有一个 ionic 3 应用程序。 在一个页面上,我有一个包含一些字段的表单。

        <form>
            <ion-item>
                <ion-label>First item</ion-label>
                <ion-input type="text" [(ngModel)]="title" name="title"></ion-input>
            </ion-item>
            ... some more simple fields ...
            <ion-item>
                <ion-label>Item below keyboard region</ion-label>
                <ion-textarea [(ngModel)]="description" name="description"></ion-textarea>
            </ion-item>
            <button ion-button type="submit" block>Add Todo</button>
        </form>

当我点击第一个时,会显示键盘并且输入项正确聚焦,即:显示闪烁的插入符号。

虽然,当我在显示键盘所需区域下方的位置单击某个字段时,我没有得到插入符号,尽管该字段实际上是聚焦的。当我打字时,karakter 会被放入字段中。

主要的区别在于,当点击下方字段时,表格会在键盘显示时向上移动。

如何解决这个问题?

我在 iPad 2017、iOS 11.2.2 上运行该应用。

package.json:

{
  "name": "my app",
  "version": "1.0.1",
  "author": "Ionic Framework",
  "homepage": "http://ionicframework.com/",
  "private": true,
  "scripts": {
    "clean": "ionic-app-scripts clean",
    "build": "ionic-app-scripts build --release",
    "lint": "ionic-app-scripts lint",
    "ionic:build": "ionic-app-scripts build",
    "ionic:serve": "ionic-app-scripts serve"
  },
  "dependencies": {
    "@angular/animations": "5.0.0",
    "@angular/common": "5.0.0",
    "@angular/compiler": "5.0.0",
    "@angular/compiler-cli": "5.0.0",
    "@angular/core": "5.0.0",
    "@angular/forms": "5.0.0",
    "@angular/http": "5.0.0",
    "@angular/platform-browser": "5.0.0",
    "@angular/platform-browser-dynamic": "5.0.0",
    "@ionic-native/app-version": "^4.5.2",
    "@ionic-native/calendar": "^4.3.2",
    "@ionic-native/call-number": "^4.4.2",
    "@ionic-native/camera": "^4.3.2",
    "@ionic-native/core": "4.3.0",
    "@ionic-native/date-picker": "^4.4.2",
    "@ionic-native/file": "^4.4.2",
    "@ionic-native/in-app-browser": "^4.3.3",
    "@ionic-native/keyboard": "^4.4.2",
    "@ionic-native/media-capture": "^4.4.0",
    "@ionic-native/native-page-transitions": "^4.3.2",
    "@ionic-native/splash-screen": "4.3.0",
    "@ionic-native/status-bar": "4.3.0",
    "@ionic/pro": "^1.0.9",
    "@ionic/storage": "2.0.1",
    "@ngx-translate/core": "^9.1.0",
    "@ngx-translate/http-loader": "^2.0.1",
    "call-number": "^1.0.1",
    "com.telerik.plugins.nativepagetransitions": "^0.6.5",
    "cordova-ios": "^4.5.4",
    "cordova-plugin-app-version": "^0.1.9",
    "cordova-plugin-calendar": "^4.6.0",
    "cordova-plugin-camera": "^2.4.1",
    "cordova-plugin-compat": "^1.2.0",
    "cordova-plugin-datepicker": "^0.9.3",
    "cordova-plugin-device": "^1.1.7",
    "cordova-plugin-file": "^5.0.0",
    "cordova-plugin-file-transfer": "^1.7.0",
    "cordova-plugin-inappbrowser": "^1.7.2",
    "cordova-plugin-ionic-webview": "^1.1.16",
    "cordova-plugin-media-capture": "^1.4.3",
    "cordova-plugin-privacyscreen": "^0.4.0",
    "cordova-plugin-splashscreen": "^4.1.0",
    "cordova-plugin-statusbar": "^2.3.0",
    "cordova-plugin-whitelist": "^1.3.3",
    "cordova-windows": "^5.0.0",
    "intl": "^1.2.5",
    "ionic-angular": "3.9.2",
    "ionic-plugin-keyboard": "^2.2.1",
    "ionicons": "3.0.0",
    "mx.ferreyra.callnumber": "0.0.2",
    "ng2-datepicker": "^2.2.1",
    "plist": "^2.1.0",
    "rxjs": "5.5.2",
    "sw-toolbox": "3.6.0",
    "zone.js": "0.8.18"
  },
  "devDependencies": {
    "@ionic/app-scripts": "3.1.0",
    "cors": "^2.8.4",
    "typescript": "2.4.2",
    "ws": "3.3.2"
  },
  "description": "An Ionic project",
  "cordova": {
    "plugins": {
      "com.telerik.plugins.nativepagetransitions": {},
      "cordova-plugin-camera": {
        "CAMERA_USAGE_DESCRIPTION": " ",
        "PHOTOLIBRARY_USAGE_DESCRIPTION": " "
      },
      "cordova-plugin-calendar": {
        "CALENDAR_USAGE_DESCRIPTION": "This app uses your calendar to plan sessions."
      },
      "cordova-plugin-privacyscreen": {},
      "ionic-plugin-keyboard": {},
      "cordova-plugin-whitelist": {},
      "cordova-plugin-device": {},
      "cordova-plugin-splashscreen": {},
      "cordova-plugin-ionic-webview": {},
      "cordova-plugin-inappbrowser": {},
      "cordova-plugin-media-capture": {
        "CAMERA_USAGE_DESCRIPTION": " ",
        "MICROPHONE_USAGE_DESCRIPTION": " ",
        "PHOTOLIBRARY_USAGE_DESCRIPTION": " "
      },
      "cordova-plugin-datepicker": {},
      "mx.ferreyra.callnumber": {},
      "cordova-plugin-statusbar": {},
      "call-number": {},
      "cordova-plugin-file": {
        "PHOTOLIBRARY_USAGE_DESCRIPTION": "This allows",
        "PHOTOLIBRARY_ADD_USAGE_DESCRIPTION": "This allows",
        "FILE_USAGE_DESCRIPTION": "This app uses your files to upload on sessions.",
        "CAMERA_USAGE_DESCRIPTION": " ",
        "MICROPHONE_USAGE_DESCRIPTION": " "
      },
      "cordova-plugin-app-version": {}
    },
    "platforms": [
      "windows",
      "ios"
    ]
  }
}

应用程序模块.ts:

...
imports: [
    BrowserModule,
    BrowserAnimationsModule,
    HttpClientModule,
    IonicModule.forRoot(MyApp, {scrollAssist: false, autoFocusAssist: 'delay'})
],

在 app.component.ts 中:

this.platform.ready().then(() => {
        console.log('Platform is ready!');
        this.keyboard.disableScroll(false);
        ...

谢谢!

最佳答案

我有这个hackish 解决方案,但我想必须有更好的解决方案。但是因为user2158259的评论,我还是发一下吧。请不要因为发布它而惩罚我 ;-)

1) 删除包/插件(如果有):

ionic cordova plugin remove ionic-plugin-keyboard
npm uninstall ionic-plugin-keyboard --save
npm uninstall @ionic-native/keyboard --save

2) 删除 app.module.ts 中的任何引用,例如

this.keyboard.disableScroll(true);

3) 在应用文件夹中创建一个子文件夹并添加这两个文件:

device.service.ts 以下代码是我的 device.service.ts 的一个子集

import {ApplicationRef, EventEmitter, Injectable} from '@angular/core';

@Injectable()
export class DeviceService {

    public onTick: EventEmitter<string> = new EventEmitter();
    private tickValue = new Date().getTime();


    constructor(public appRef: ApplicationRef) {

        window.addEventListener('onresize', () => {
            console.log('DeviceService: on resize');
            this.doTick();
            setTimeout(() => {
                this.doTick();
            }, 100);
        }, false);

        window.addEventListener('transitionend', () => {
            console.log('transition ended');
            this.doTick();
        }, false);

        this.tickValue = new Date().getTime();
        setTimeout(() => {
            this.doTick();
        });

    }

    /**
     * getTickValue() returns a different value when something changed (orientation, keyboard up/down).
     * by adding this to the screen, the Ionic caret will be adjusted properly
     */
    getTickValue(): string {
        return this.tickValue + ' ' + window.innerWidth + ' ' + window.innerHeight + ' ' + window.orientation;
    }

    doTick(): void {
        this.tickValue = new Date().getTime();
        this.onTick.emit(String(this.tickValue));
        this.appRef.tick();
    }

}

kb-scroll.ts

import {ApplicationRef, Directive, ElementRef, HostListener, Renderer2} from '@angular/core';
import {DeviceService} from './device.service';

@Directive({
    selector: '[kb-scroll]' // Attribute selector
})
export class KbScrollDirective {

    constructor(public appRef: ApplicationRef,
                public elm: ElementRef,
                public renderer: Renderer2,
                public device: DeviceService) {
    }

    @HostListener('click', ['$event'])
    onClick($event) {
        let elmClickedY;
        let scrollContent: HTMLElement;

        if ('TEXTAREA' === this.elm.nativeElement.tagName) {
            scrollContent = $event.toElement;
            elmClickedY = $event.offsetY;
        } else if ('ION-CONTENT' === this.elm.nativeElement.tagName) {
            // calculate Y offset between click and top of scroll-content area
            scrollContent = this.elm.nativeElement.querySelector('.scroll-content');
            if (scrollContent) {
                // $event.offsetY is most likely small offset in clicked input field in scroll content
                // calculate the offsetY opposed to the container (div.scroll-content)
                let clickScreenY = $event.toElement.getBoundingClientRect().top + $event.offsetY;
                let scrollContentScreenY = scrollContent.getBoundingClientRect().top;
                elmClickedY = clickScreenY - scrollContentScreenY;
            } else {
                console.warn('KbScrollDirective: could not find .scroll-content div in ', this.elm.nativeElement);
            }
        } else {
            console.warn('KbScrollDirective: Can\'t handle ', this.elm.nativeElement.tagName);
        }

        //TODO: OK to 'RE-ASSIGN' window.onresize ?
        window.onresize = () => {
            if (scrollContent) {
                setTimeout(() => {
                    let elmHeight = scrollContent.clientHeight;
                    if (elmClickedY > elmHeight) {
                        let toScroll = elmClickedY - elmHeight;
                        scrollContent.scrollTop += toScroll + 40;
                        this.device.doTick();
                    }
                }, 100);
            }
        }
    }
}

4) 将此服务和指令添加到您的模块 5) 在你的 <ion-content> 上使用 kb-scroll 指令HTML 标签:

<ion-content kb-scroll>
    ... your form here ...
</ion-content>

6) 现在是真正肮脏的部分(而且我们需要该服务的原因会变得很清楚)。 似乎当屏幕上发生某些变化时会触发 Ionic 插入符号的重绘,因此我们需要强制执行此操作。

我添加了一个 <span>我的 HTML 模板包含根 <ion-nav>标签: app.html

<!-- invisible ticker, needed to get Keyboard caret into place -->
<div style="position: absolute; top:-100px">{{tickValue}}</div>

<!-- Disable swipe-to-go-back because it's poor UX to combine STGB with side menus -->
<ion-nav [root]="rootPage" #content swipeBackEnabled="false" class="root-content"></ion-nav>

7) 在您的 app.component.ts 中添加此代码:

@Component({
    templateUrl: 'app.html'
})
export class MyApp {
    @ViewChild(Nav) nav: Nav;

    ...

    tickValue: string;

    constructor(...,
                public device: DeviceService) {

        this.device.onTick.subscribe(tickValue => {
            this.tickValue = tickValue;
        });
    }

因此,每当 DeviceService#tickValue 更新时,此订阅者都会更新应用程序组件的刻度值,从而导致屏幕重绘,尽管刻度值呈现在屏幕的可见区域之外。这似乎导致 Ionic 插入符号被正确定位。

好处:这也适用于占据屏幕一半以上的文本区域(= 屏幕高度 - 键盘高度)。只需将 kb-scroll 指令添加到您的 <textarea> HTML 标签。

请注意这是一个非常骇人听闻的解决方案。

非常欢迎任何评论/改进!

关于ios - ionic 3 输入项在 iOS 上不显示插入符号,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/48321152/

相关文章:

android - 需要android和presenter的键码表

angular - 为什么 $app-direction : rtl not working?

javascript - 具有缩放和滑动器的 React-Native 图像查看器

java - Android - 如何禁用虚拟键盘中的某些键

ios - Core Image 渲染缓慢

ios - Xcode6-Beta3 更新后,无法使用 Swift 访问键盘信息

android - 使 Ionic 应用出现在 "Share"列表中并接收数据

javascript - 无法将日历数据保存到 firebase 中

ios - "Extra argument in call"我有这个错误....这段代码有什么问题

ios - 使用 Swift 从 Firebase 数据库创建过滤 TableView 的最佳方法是什么