概述
- 这个解决方案的预处理部分,参考了完美处理安卓硬件返回按钮这篇文章,并在这个基础上添加监听返回键执行自定义操作等。
- 预处理点击返回键关闭键盘、返回上一页、最小化 app,然后进一步处理 ActionSheet、Alert、Menu 、Select 等打开的时候的问题。
效果预览
安装
-
把 demo/src/core/common/back.service.ts 文件拷贝到到你的项目中。 demo 地址
-
安装 App Minimize 插件。
ionic cordova plugin add cordova-plugin-appminimize
npm install --save @ionic-native/app-minimize
- 在你的项目 app.module.ts 添加 BackService 和 AppMinimize 供应商
import { AppMinimize } from '@ionic-native/app-minimize';
import { BackService } from ...;
@NgModule({
declarations: [
...
],
imports: [
...
],
providers: [
AppMinimize,
BackService
]
})
export class AppModule { }
BackService
一个监听返回键,触发自定义操作的服务
接口成员
state
有未执行的自定义操作返回 true,无未执行的自定义操作返回 false
subscribe(calback)
添加自定义返回键操作
Param | Type | Details |
---|---|---|
calback | function | 自定义操作的函数 |
unsubscribe()
移除一个自定义返回键操作
publish()
发起一个自定义返回键操作
clear()
清除所有所有自定义操作
使用
有些项目的第一页不是 Tabs,而是需要登录后,才跳转到 Tabs,所以我们需要在两个地方写预处理,首先给 MyApp 添加预处理方法,然后给 Tabs 添加预处理
预处理
给 MyApp 添加预处理方法
在 app.html 添加模板变量 #myContent
<ion-nav [root]="rootPage" #myContent></ion-nav>
在 app.component.ts 添加以下代码
import { Platform, Keyboard, NavController } from 'ionic-angular';
import { AppMinimize } from '@ionic-native/app-minimize';
import { BackService } from ...;
export class MyApp {
@ViewChild('myContent')
navCtrl: NavController;
constructor(
private platform: Platform,
private keyboard: Keyboard,
private appMinimize: AppMinimize,
private backService: BackService
) {
platform.ready().then(() => {
...
this.registerBack();
});
}
// 注册返回键
private registerBack() {
this.platform.registerBackButtonAction(() => {
if (this.keyboard.isOpen()) {
// 关闭键盘
this.keyboard.close();
} else if (this.backService.state) {
// 触发自定义返回事件
this.backService.publish();
} else if (this.navCtrl.canGoBack()) {
// 返回上一页
this.navCtrl.pop();
} else {
// 最小化app
this.appMinimize.minimize();
}
}, 101);
}
}
给 Tabs 添加预处理方法
在 tabs.ts 添加以下代码
import { Component, ViewChild } from '@angular/core';
import {
IonicPage,
NavController,
Platform,
Keyboard,
Tabs
} from 'ionic-angular';
import { AppMinimize } from '@ionic-native/app-minimize';
import { BackService } from ...;
...
export class TabsPage {
...
@ViewChild(Tabs)
tabs: Tabs;
constructor(
private navCtrl: NavController,
private platform: Platform,
private keyboard: Keyboard,
private appMinimize: AppMinimize,
private backService: BackService
) {}
ionViewDidLoad() {
this.registerBack();
}
// 注册返回键
private registerBack() {
this.platform.registerBackButtonAction(() => {
// 关闭键盘
if (this.keyboard.isOpen()) {
return this.keyboard.close();
}
// 触发自定义返回事件
if (this.backService.state) {
return this.backService.publish();
}
const activeVC = this.navCtrl.getActive();
const page = activeVC.instance;
if (!(page instanceof TabsPage)) {
if (!this.navCtrl.canGoBack()) {
// 最小化app
return this.appMinimize.minimize();
}
return this.navCtrl.pop();
}
const tabs = page.tabs;
const activeNav = tabs.getSelected();
if (!activeNav.canGoBack()) {
// 关闭Menu
if (this.menuCtrl.isOpen()) {
return this.menuCtrl.close();
}
// 最小化app
return this.appMinimize.minimize();
}
return activeNav.pop();
}, 102);
}
}
进一步处理
通过重载 ActionSheet、Alert、Loading、Modal、Popover 等的 create 方法来监听返回键。
ActionSheet
- 创建一个 action-sheet.service.ts,然后添加一下代码
import { Injectable } from '@angular/core';
import {
ActionSheetController,
ActionSheet,
ActionSheetOptions
} from 'ionic-angular';
import { BackService } from './back.service';
@Injectable()
export class ActionSheetService {
constructor(
private actionSheetCtrl: ActionSheetController,
private backService: BackService
) {}
create(options?: ActionSheetOptions): ActionSheet {
const actionSheet = this.actionSheetCtrl.create(options);
// onWillDismiss的时候,取消订阅返回键
actionSheet.onWillDismiss(() => {
this.backService.unsubscribe();
});
this.backService.subscribe(() => {
// 点击返回键,关闭
actionSheet.dismiss();
});
return actionSheet;
}
}
- 在你的项目 app.module.ts 添加 ActionSheetService 供应商
import { ActionSheetService } from ...;
@NgModule({
declarations: [
...
],
imports: [
...
],
providers: [
ActionSheetService
]
})
export class AppModule { }
- 调用 ActionSheet 的地方,把 AlertController 改成 ActionSheetService 即可
import { ActionSheetService } from ...;
export class MyPage {
constructor(
private alertCtrl:ActionSheetService
) {}
presentActionSheet() {
const actionSheet = this.alertCtrl.create({
title: 'ActionSheet',
buttons: [
...
{
text: 'Cancel',
role: 'cancel',
handler: () => {
...
}
}
]
});
actionSheet.onDidDismiss(() => {
...
});
actionSheet.present();
}
Alert、Loading、Modal、Popover的实现方法跟 ActionSheet 一样
特殊处理
使用ion-select和ion-datetime需要做特殊处理。
ion-select
添加 模板引用变量 并绑定事件 click 事件
<ion-select [(ngModel)]="gender" #genderSelect (click)="openSelect()">
<ion-option value="f">Female</ion-option>
<ion-option value="m">Male</ion-option>
</ion-select>
然后添加以下代码
import { ViewChild } from '@angular/core';
import { Select } from 'ionic-angular';
import { BackService } from ...;
export class MyPage {
...
@ViewChild('genderSelect') genderSelect: Select;
constructor(private backService: BackService) {}
ionViewDidLoad() {
this.genderSelect.ionBlur.subscribe(() => {
this.backService.unsubscribe();
});
}
openSelect() {
this.backService.subscribe(() => {
this.genderSelect.close();
});
}
}
ion-datetime
添加 模板引用变量 并绑定事件 click 事件
<ion-item>
<ion-label>Date</ion-label>
<ion-datetime
[(ngModel)]="myDate"
#datePicker
(click)="openDatePicker()"
></ion-datetime>
</ion-item>
然后添加以下代码
import { ViewChild } from '@angular/core';
import { DateTime } from 'ionic-angular';
import { BackService } from ...;
export class MyPage {
...
@ViewChild('datePicker') datePicker: DateTime;
constructor(private backService: BackService) {}
ionViewDidLoad() {
this.datePicker.ionBlur.subscribe(() => {
this.backService.unsubscribe();
});
}
openDatePicker() {
this.backService.subscribe(() => {
this.datePicker.close();
});
}
}