首页
学习
活动
专区
圈层
工具
发布
社区首页 >问答首页 >离子3输入项在iOS上不显示插入符号

离子3输入项在iOS上不显示插入符号
EN

Stack Overflow用户
提问于 2018-01-18 12:16:54
回答 1查看 1.1K关注 0票数 3

我有一个离子3应用程序。在一个页面上,我有一个带有一些字段的表单。

代码语言:javascript
复制
        <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>

当我选择第一个选项卡时,键盘就会显示出来,输入项也会被正确地聚焦,也就是说:显示一个闪烁的插入符号。

不过,当我在显示键盘所需区域下方的位置单击某个字段时,我不会得到插入符号,尽管该字段实际上是聚焦的。当我打字的时候,卡拉克人就会被放进战场。

主要区别在于,当单击下字段时,当键盘显示时,窗体会向上移动。

怎么解决这个问题?

我正在运行iPad 2017的应用程序iOS 11.2.2。

package.json:

代码语言:javascript
复制
{
  "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"
    ]
  }
}

app.module.ts:

代码语言:javascript
复制
...
imports: [
    BrowserModule,
    BrowserAnimationsModule,
    HttpClientModule,
    IonicModule.forRoot(MyApp, {scrollAssist: false, autoFocusAssist: 'delay'})
],

在app.component.ts中:

代码语言:javascript
复制
this.platform.ready().then(() => {
        console.log('Platform is ready!');
        this.keyboard.disableScroll(false);
        ...

谢谢!

EN

回答 1

Stack Overflow用户

发布于 2018-02-09 09:08:01

我有这个hackish解决方案,但我想必须有一个更好的解决方案。但是由于user2158259的评论,我还是会发出去的。请不要因为我张贴它而惩罚我;-)

1)如果您有包/插件,请删除它们:

代码语言:javascript
复制
ionic cordova plugin remove ionic-plugin-keyboard
npm uninstall ionic-plugin-keyboard --save
npm uninstall @ionic-native/keyboard --save

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

代码语言:javascript
复制
this.keyboard.disableScroll(true);

3)在应用程序文件夹中创建一个子文件夹,并添加以下两个文件:

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

代码语言:javascript
复制
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

代码语言:javascript
复制
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-滚动指令:

代码语言:javascript
复制
<ion-content kb-scroll>
    ... your form here ...
</ion-content>

6)现在出现了真正肮脏的部分(我们需要这种服务的原因将变得越来越清楚)。似乎离子插入符号的重绘是在屏幕上发生变化时触发的,所以我们需要强制这样做。

我在我的<span>模板中添加了一个<ion-nav>,该模板包含根<ion-nav>标记: app.html

代码语言:javascript
复制
<!-- 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中添加以下代码:

代码语言:javascript
复制
@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更新时,该订阅服务器将更新应用程序组件的滴答值,从而导致屏幕重新绘制,尽管滴答值呈现在屏幕可见区域之外。这似乎导致离子插入符的位置正确。

奖励:这也适用于位于屏幕一半以上的文本区域(=屏幕高度-键盘高度)。只需将kb-滚动指令添加到您的<textarea>标记即可。

请注意,这是一个非常麻烦的解决方案。

欢迎任何评论或改进!

票数 0
EN
页面原文内容由Stack Overflow提供。腾讯云小微IT领域专用引擎提供翻译支持
原文链接:

https://stackoverflow.com/questions/48321152

复制
相关文章

相似问题

领券
问题归档专栏文章快讯文章归档关键词归档开发者手册归档开发者手册 Section 归档