我有一个 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/