Ionic 2?で戻るボタンのアクションを処理するにはどうすればよいですか?
どのページがユーザーに表示されているかに応じて、何をすべきかを知りたい。
この質問に対する良い答えは見つかりませんでしたが、しばらくして、自分でそれを行う方法を見つけました。皆さんと共有します。
ありがとう
以下がその方法です。
すべてのPageコンポーネントで、backButtonAction()
という関数を作成しました。これは、すべてのページに対してカスタムコードを実行します。
コード:
import { Component } from '@angular/core';
import { Platform, NavController, ModalController } from 'ionic-angular';
import { DetailsModal } from './details';
@Component({
selector: 'page-appointments',
templateUrl: 'appointments.html'
})
export class AppointmentsPage {
modal: any;
constructor(private modalCtrl: ModalController, public navCtrl: NavController, public platform: Platform) {
// initialize your page here
}
backButtonAction(){
/* checks if modal is open */
if(this.modal && this.modal.index === 0) {
/* closes modal */
this.modal.dismiss();
} else {
/* exits the app, since this is the main/first tab */
this.platform.exitApp();
// this.navCtrl.setRoot(AnotherPage); <-- if you wanted to go to another page
}
}
openDetails(appointment){
this.modal = this.modalCtrl.create(DetailsModal, {appointment: appointment});
this.modal.present();
}
}
そして、app.component.ts
、platform.registerBackButtonAction
メソッドは、戻るボタンがクリックされるたびに呼び出されるコールバックを登録します。その中で、関数backButtonAction
が現在のページに存在するかどうかを確認し、存在しない場合は、メイン/最初のタブに移動します。
すべてのページに対してカスタマイズされたアクションを実行する必要がない場合、これを単純化できます。アプリをポップするか終了するだけです。
この特定のページでモーダルが開いているかどうかを確認する必要があるため、このようにしました。
コード:
platform.registerBackButtonAction(() => {
let nav = app.getActiveNav();
let activeView: ViewController = nav.getActive();
if(activeView != null){
if(nav.canGoBack()) {
nav.pop();
}else if (typeof activeView.instance.backButtonAction === 'function')
activeView.instance.backButtonAction();
else nav.parent.select(0); // goes to the first tab
}
});
現在のページが最初のタブである場合、アプリは閉じます(backButtonAction
メソッドで定義されているとおり)。
Ionic最新バージョン3.xx app.component.tsファイル
import { Platform, Nav, Config, ToastController} from 'ionic-angular';
constructor(public toastCtrl: ToastController,public platform: Platform) {
platform.ready().then(() => {
//back button handle
//Registration of Push in Android and Windows Phone
var lastTimeBackPress=0;
var timePeriodToExit=2000;
platform.registerBackButtonAction(() => {
// get current active page
let view = this.nav.getActive();
if(view.component.name=="TabsPage"){
//Double check to exit app
if(new Date().getTime() - lastTimeBackPress < timePeriodToExit){
this.platform.exitApp(); //Exit from app
}else{
let toast = this.toastCtrl.create({
message: 'Press back again to exit App?',
duration: 3000,
position: 'bottom'
});
toast.present();
lastTimeBackPress=new Date().getTime();
}
}else{
// go to previous page
this.nav.pop({});
}
});
});
}
ここや他のソースからの回答を使用して、必要なことを達成しました。実稼働(--prod)用のアプリケーションをビルドするとき、JSがuい、単純化するため、このアプローチは機能しないことに気付きました。
this.nav.getActive().name == 'PageOne'
そのため、「if」ステートメントでnextを使用します。
view.instance instanceof PageOne
したがって、最終的なコードは次のようになります。
this.platform.ready().then(() => {
//Back button handling
var lastTimeBackPress = 0;
var timePeriodToExit = 2000;
this.platform.registerBackButtonAction(() => {
// get current active page
let view = this.nav.getActive();
if (view.instance instanceof PageOne) {
if (new Date().getTime() - lastTimeBackPress < timePeriodToExit) {
this.platform.exitApp(); //Exit from app
} else {
let toast = this.toastCtrl.create({
message: 'Tap Back again to close the application.',
duration: 2000,
position: 'bottom',
});
toast.present();
lastTimeBackPress = new Date().getTime();
}
} else if (view.instance instanceof PageTwo || view.instance instanceof PageThree) {
this.openPage(this.pages[0]);
} else {
this.nav.pop({}); // go to previous page
}
});
});
here のIonic 2 RC.4ドキュメントによると:
Platform
APIのregisterBackButtonAction(callback, priority)
メソッドを使用して、戻るボタンを押したときにアクションを登録できます。
ユーザーがネイティブプラットフォームの戻るボタン(「ハードウェア」の戻るボタンとも呼ばれます)を押すと、戻るボタンイベントがトリガーされます。このイベントは、AndroidおよびWindowsプラットフォームで実行されているCordovaアプリ内でのみ使用されます。 iOSにはAndroidまたはWindowsデバイスと同じ意味でハードウェアの戻るボタンが付属していないため、このイベントはiOSでは発生しません。
ハードウェアの戻るボタンのアクションを登録して優先順位を設定すると、ハードウェアの戻るボタンが押されたときに呼び出すアクションをアプリで制御できます。このメソッドは、登録された戻るボタンアクションの中で最も高い優先度を持ち、呼び出されるべきものを決定します。
パラメーター :
戻り値:Function:呼び出されたときに戻るボタンアクションの登録を解除する関数。
Ionic 3 Lazy Loading、platform.is( 'cordova')に関しては、すべてのバックシナリオを処理する以下のメソッドを作成したブラウザのバック動作を処理する必要性を感じたことはありません。
// If a view controller is loaded. Just dismiss it.
let nav = this.app.getActiveNav();
let activePortal = this._ionicApp._loadingPortal.getActive() ||
this._ionicApp._modalPortal.getActive() ||
this._ionicApp._toastPortal.getActive() ||
this._ionicApp._overlayPortal.getActive();
if(activePortal && activePortal.index === 0) {
/* closes modal */
activePortal.dismiss();
return;
}
// If a state is pushed: Pop it.
if (this.nav.canGoBack()) {
this.nav.pop();
return;
} else
// Else If its a tabs page:
if (this.nav.getActiveChildNav()) {
const tabs: Tabs = this.nav.getActiveChildNav();
const currentTab = tabs.getActiveChildNavs()[0];
// If any page is pushed inside the current tab: Pop it
if(currentTab.canGoBack()) {
currentTab.pop();
return;
}
else
// If home tab is not selected then select it.
if(tabs.getIndex(currentTab) !=0){
tabs.select(0);
return;
}
}
else
// If a menu is open: close it.
if (this.menu.isOpen()) {
this.menu.close();
return;
}
if (this.exitApp) {
this.platform.exitApp();
return;
}
this.exitApp = true;
const toast = this.toastCtrl.create({
message: this.exitMessage || 'press again to exit',
duration: 4000,
position: 'bottom',
cssClass: 'exit-toastr',
});
toast.present();
setTimeout(() => {
this.exitApp = false;
}, 2000);
最も簡単な方法を見つけました。次のコードを
app.component
に追加するだけです。
this.platform.registerBackButtonAction((event) => {
let activePortal = this.ionicApp._loadingPortal.getActive() ||
this.ionicApp._modalPortal.getActive() ||
this.ionicApp._toastPortal.getActive() ||
this.ionicApp._overlayPortal.getActive();
if(activePortal && activePortal.index === 0) {
/* closes modal */
activePortal.dismiss();
} else {
if(this.nav.getActive().name == 'Homepage') { // your homepage
this.platform.exitApp();
}
else {
if(this.nav.canGoBack())
this.nav.pop();
this.nav.setRoot(Homepage);
}
}
},101);
それでおしまい! すべてのページにコードを追加する必要はありません!
@amr abdulazizとは少し異なるアプローチがあります。戻るまたは終了を制御するためにsetTimeoutを使用しています。これにより、戻るボタンを実装するための別のオプションが提供されることを願っています。
initBackButtonBehaviour() {
this.platform.registerBackButtonAction(() => {
console.log("Back button pressed");
if (this.readyToExit) {
this.platform.exitApp();
return;
}
let activePortal = this.ionicApp._loadingPortal.getActive() ||
this.ionicApp._modalPortal.getActive() ||
this.ionicApp._toastPortal.getActive() ||
this.ionicApp._overlayPortal.getActive();
if (activePortal) {
activePortal.dismiss();
activePortal.onDidDismiss(() => { });
return; // stop any further action after closing any pop up modal or overlay
}
if (this.menuCtrl.isOpen()) {
this.menuCtrl.close();
return; // stop any further action after menu closed
}
else if (this.nav.canGoBack()) {
this.nav.pop();
return; // stop any further action after navigation pop
}
else {
let activePage = this.nav.getActive().instance;
let whiteListPages = [HomePage];
// if current page is not in whitelistPage
// then back to home or login page first
if (whiteListPages.indexOf(activePage.constructor) < 0) {
this.nav.setRoot(HomePage);
return;
} else if (whiteListPages.indexOf(activePage.constructor) >= 0) {
this.utils.showToast('Press back button again to exit', 1500);
this.readyToExit = true;
setTimeout(() => {
this.readyToExit = false;
}, 1500);
} else {
console.error('cannot handle back button');
}
}
}, 101);
長い検索後のベストプラクティスソリューション。
100%動作し、実際のデバイスでテストしました
this.Platform.registerBackButtonAction(() => {
// try to dismiss any popup or modal
console.log("Back button action called");
let activePortal = this.ionicApp._loadingPortal.getActive() ||
this.ionicApp._modalPortal.getActive() ||
this.ionicApp._toastPortal.getActive() ||
this.ionicApp._overlayPortal.getActive();
if (activePortal) {
// ready = false;
activePortal.dismiss();
activePortal.onDidDismiss(() => { });
console.log("handled with portal");
return;
}
// try to close the menue
if(this.MenuController.isOpen()){
this.closeMenu();
return;
}
else if(this.nav.canGoBack()){
this.nav.pop();
return;
}else{
let activePage = this.nav.getActive().instance;
let whitelistPages = [LoginPage, HomePage];
// if current page is not in whitelistPage
// then back to home or login page first
if (whitelistPages.indexOf(activePage.constructor) < 0) {
this.nav.setRoot(this.userLoggedIn ? HomePage : LoginPage);
return;
}else if(whitelistPages.indexOf(activePage.constructor) > 0){
this.AppUtilities.showConfirm("Exit","Are you want to exist the app ? ").subscribe(
()=>{
this.Platform.exitApp();
},
()=>{}
)
}else{
console.error('cannot handel back button')
}
}
});
バックボタンハンドルについて多くのことを調査しましたionic最新バージョン3.xx
//Check Hardware Back Button Double Tap to Exit And Close Modal On Hardware Back
let lastTimeBackPress = 0;
let timePeriodToExit = 2000;
this.platform.registerBackButtonAction(() => {
let activePortal = this.ionicApp._loadingPortal.getActive() || // Close If Any Loader Active
this.ionicApp._modalPortal.getActive() || // Close If Any Modal Active
this.ionicApp._overlayPortal.getActive(); // Close If Any Overlay Active
if (activePortal) {
activePortal.dismiss();
}
else if(this.nav.canGoBack()){
this.nav.pop();
}else{
//Double check to exit app
if (new Date().getTime() - lastTimeBackPress < timePeriodToExit) {
this.platform.exitApp(); //Exit from app
} else {
this.toast.create("Press back button again to exit");
lastTimeBackPress = new Date().getTime();
}
}
});
この機能を試すことができます:
registerBackButton() {
this.platform.registerBackButtonAction(() => {
if (this.menu.isOpen()) {
console.log("Menu is open!", "loggedInMenu");
this.menu.close();
console.log("this.menu.isOpen(): " + JSON.stringify(this.menu.isOpen()));
return;
}
console.log("Checking for other pages");
let checkHomePage = true;
let max = Globals.navCtrls.length;
for (let i = 0; i < Globals.navCtrls.length; i++) {
let n = Globals.navCtrls[i];
if (n) {
if (n.canGoBack()) {
console.log("Breaking the loop i: " + JSON.stringify(i));
let navParams = n.getActive().getNavParams();
if (navParams) {
console.log("navParams exists");
let resolve = navParams.get("resolve");
if (resolve) {
n.pop().then(() => resolve({}));
} else {
n.pop();
}
} else {
n.pop();
}
checkHomePage = false;
return;
}
} else console.log("n was null!");
}
if (this.nav.getActive().instance instanceof TabsPage && !this.nav.canGoBack()) {
let popPageVal = this.backbuttonService.popPage();
console.log("popPageVal: " + JSON.stringify(popPageVal));
if (popPageVal >= 0) {
console.log("Switching the tab to: ", popPageVal);
this.switchTab(popPageVal);
} else {
console.log("Last page is HomePage");
if (this.alert) {
this.alert.dismiss();
this.alert = null;
} else {
this.showAlert();
}
}
} else {
console.log("Last page is not HomePage");
if (this.nav.canGoBack()) {
console.log("We can go back!");
this.nav.pop();
}
}
});
}
showAlert() {
this.alert = this.alertController.create({
title: "Exit?",
message: "Are you sure you want to exit?",
buttons: [
{
text: "Cancel",
role: "cancel",
handler: () => {
this.alert = null;
}
},
{
text: "Exit",
handler: () => {
this.platform.exitApp();
}
}
]
});
this.alert.present();
}
switchTab(tabIndex) {
if (Globals.tabs && tabIndex >= 0) {
console.log("Switch condition met");
Globals.tabIndex = tabIndex;
Globals.tabs.select(tabIndex);
Globals.tabs.selectedIndex = tabIndex;
}
}
私はそれがあなたと働くことを望みます。
ルートページを設定するだけで、これを達成できました...
import {Component, ViewChild, Injector} from '@angular/core';
import {Platform, MenuController, Nav, App, IonicApp, NavController} from 'ionic-angular';
import {StatusBar} from '@ionic-native/status-bar';
import {SplashScreen} from '@ionic-native/splash-screen';
import {InvitesPage} from "../pages/invites/invites";
import {RewardsPage} from "../pages/rewards/rewards";
import {ConnectionsPage} from "../pages/connections/connections";
import {MessagesPage} from "../pages/messages/messages";
import {ResourcesPage} from "../pages/resources/resources";
import {SignoutPage} from "../pages/signout/signout";
import {DashboardPage} from "../pages/dashboard/dashboard";
import {AccountPage} from "../pages/account/account";
import {HomePage} from "../pages/home/home";
import {TriviaPage} from "../pages/trivia/trivia";
import {Events} from "ionic-angular/util/events";
@Component({
templateUrl: 'app.html'
})
export class MyApp {
@ViewChild(Nav) nav: NavController;
// make HelloIonicPage the root (or first) page
public rootPage: any; //if logged in, go to dashboard.
public pages: Array<{title: string, component: any}>;
public user: any;
public routeHistory: Array<any>;
constructor(public platform: Platform,
public menu: MenuController,
public statusBar: StatusBar,
public splashScreen: SplashScreen,
private _app: App,
private _ionicApp: IonicApp,
private _menu: MenuController,
protected injector: Injector,
public _events: Events) {
this.initializeApp();
// set our app's pages
this.pages = [
{title: 'My Account', component: AccountPage},
{title: 'Dashboard', component: DashboardPage},
{title: 'Invites', component: InvitesPage},
{title: 'Rewards', component: RewardsPage},
{title: 'Connections', component: ConnectionsPage},
{title: 'Messages', component: MessagesPage},
{title: 'Resources', component: ResourcesPage},
{title: 'Trivia', component: TriviaPage},
{title: 'Sign Out', component: SignoutPage}
];
this.routeHistory = [];
this.user = {firstName: ''};
}
initializeApp() {
this.platform.ready().then(() => {
this._setupBrowserBackButtonBehavior();
let self = this;
if (sessionStorage.getItem('user')) {
this.user = JSON.parse(sessionStorage.getItem('user'));
self.rootPage = TriviaPage;
} else {
self.rootPage = HomePage;
}
this.routeHistory.Push(self.rootPage);
// Okay, so the platform is ready and our plugins are available.
// Here you can do any higher level native things you might need.
this.statusBar.styleDefault();
this.splashScreen.hide();
});
}
openPage(page) {
// close the menu when clicking a link from the menu
this.menu.close();
// navigate to the new page if it is not the current page
this.nav.setRoot(page.component);
//store route history
this.routeHistory.Push(page.component);
}
private _setupBrowserBackButtonBehavior() {
// Register browser back button action(s)
window.onpopstate = (evt) => {
// Close menu if open
if (this._menu.isOpen()) {
this._menu.close();
return;
}
// Close any active modals or overlays
let activePortal = this._ionicApp._loadingPortal.getActive() ||
this._ionicApp._modalPortal.getActive() ||
this._ionicApp._toastPortal.getActive() ||
this._ionicApp._overlayPortal.getActive();
if (activePortal) {
activePortal.dismiss();
return;
}
if (this.routeHistory.length > 1) {
this.routeHistory.pop();
this.nav.setRoot(this.routeHistory[this.routeHistory.length - 1]);
}
};
// Fake browser history on each view enter
this._app.viewDidEnter.subscribe((app) => {
if (this.routeHistory.length > 1) {
history.pushState(null, null, "");
}
});
}
}