我有一个离子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>当我选择第一个选项卡时,键盘就会显示出来,输入项也会被正确地聚焦,也就是说:显示一个闪烁的插入符号。
不过,当我在显示键盘所需区域下方的位置单击某个字段时,我不会得到插入符号,尽管该字段实际上是聚焦的。当我打字的时候,卡拉克人就会被放进战场。
主要区别在于,当单击下字段时,当键盘显示时,窗体会向上移动。
怎么解决这个问题?
我正在运行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"
]
}
}app.module.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);
...谢谢!
发布于 2018-02-09 09:08:01
我有这个hackish解决方案,但我想必须有一个更好的解决方案。但是由于user2158259的评论,我还是会发出去的。请不要因为我张贴它而惩罚我;-)
1)如果您有包/插件,请删除它们:
ionic cordova plugin remove ionic-plugin-keyboard
npm uninstall ionic-plugin-keyboard --save
npm uninstall @ionic-native/keyboard --save2)删除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-滚动指令:
<ion-content kb-scroll>
... your form here ...
</ion-content>6)现在出现了真正肮脏的部分(我们需要这种服务的原因将变得越来越清楚)。似乎离子插入符号的重绘是在屏幕上发生变化时触发的,所以我们需要强制这样做。
我在我的<span>模板中添加了一个<ion-nav>,该模板包含根<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更新时,该订阅服务器将更新应用程序组件的滴答值,从而导致屏幕重新绘制,尽管滴答值呈现在屏幕可见区域之外。这似乎导致离子插入符的位置正确。
奖励:这也适用于位于屏幕一半以上的文本区域(=屏幕高度-键盘高度)。只需将kb-滚动指令添加到您的<textarea>标记即可。
请注意,这是一个非常麻烦的解决方案。
欢迎任何评论或改进!
https://stackoverflow.com/questions/48321152
复制相似问题