Ionic 5 hide & show tab menu

이상훈
상훈 Devlog
Published in
7 min readAug 20, 2020
Photo by Daniel Korpai on Unsplash

탭 메뉴는 아래와 같이 모바일 화면 하단에 위치하여 서비스의 가장 상위 레벨의 경로 처리할 수 있도록 하는 네비게이터이다.

데스크탑 화면과 달리 모바일 화면은 사용자가 보는 공간이 좁기 때문에 같은 정보라도 더 간결하게 표현되어야 한다. 또한 안드로이드에서는 경우에 따라 화면 상단/하단에 url 검색창이나 뒤로가기, 홈버튼 등의 안드로이드 자체 툴바가 있어 컨텐츠를 표시할 수 있는 공간이 더 적어지는 경우도 있다.

따라서 가장 상위 레벨의 경로에서는 탭 메뉴가 보이더라도 한단계 더 진입한 페이지(상세페이지, 내 정보 페이지…)에서는 탭 메뉴는 숨기고 해당 컨텐츠에 더 집중할 수 있도록 할 필요가 있었다.

ionic 3까지만해도 tabsHideOnSubPages 옵션을 통해 탭 메뉴들을 경우에 따라 보여지게 하거나 숨길 수 있었지만 ionic 4 이상부터는 해당 기능이 제거되었다.

TabService

먼저 탭 메뉴를 페이지 경로에 따라 숨기거나 보여지게 하도록 하는 서비스를 구현한다.

생성자에서 platform.ready()가되는 시점에 checkNavigationEvent를 호출한다. checkNavigationEvent 는 모든 생명주기 이벤트가 트리거되는 시점이 아닌 NavigationEnd 즉, 페이지가 변경될 때만 감지하여 처리하는 메소드이다.

import { Injectable } from '@angular/core';
import { NavigationEnd, Router } from '@angular/router';
import { Platform } from '@ionic/angular';
@Injectable({
providedIn: 'root'
})
export class TabService {
hideTabPages: string[] = [
'my-info',
'payments'
...
]
constructor(private router: Router, private platform: Platform) {
this.platform.ready().then(() => {
this.checkNavigationEvent();
});
}
checkNavigationEvent() {
this.router.events
.pipe(filter((e) => e instanceof NavigationEnd))
.subscribe((e: any) => {
this.hideOrShowTab(e);
});
}
hideOrShowTab(e: NavigationEnd) { ... }
}

탭을 보여줄것인지 숨길 것인지는 페이지 경로를 hideTabPages 화이트리스트로 가지고 적절히 필터링을 할 것이다. 페이지 경로 예시는 다음과 같다.

/my-info
/payments
...

hideOrShowTab()에서는 페이지 변경 이벤트를 적절히 파싱하여 페이지 경로를 가져온 다음, hideTabPages 화이트리스트와 일치하면 hide()를 아니라면 show()를 호출한다.

hideOrShowTab(e: NavigationEnd) {
const urlArray = e.url.split('/');
const pageUrl = urlArray[urlArray.length - 1];
const pageUrlParent = urlArray[urlArray.length - 2];
const page = pageUrl.split('?')[0];
const hideParamPage = this.routeParamPages.indexOf(pageUrlParent) > -1 && !isNaN(Number(page));
const shouldHide = this.hideTabPages.indexOf(page) > -1 || hideParamPage;

shouldHide ? this.hide() : this.show()
}

hide() 메소드에서는 탭 엘리먼트를 가져와 display: none스타일을 적용하고 show() 메소드에서는 그 반대로 적용한다.

hide() {
const tabBar = document.getElementById('tabBar');
if (tabBar !== null && tabBar.style.display !== 'none') tabBar.style.display = 'none';
}
show() {
const tabBar = document.getElementById('tabBar');
if (tabBar !== null && tabBar.style.display !== 'flex') tabBar.style.display = 'flex';
}

TabsPageComponent

탭 메뉴가 정의되어 있는 컴포넌트에서는 아래와 같이 탭 엘리먼트에 접근하기 위해 tabBar아이디를 부여한다.

<ion-tabs>
<ion-tab-bar #tabBar id="tabBar" slot="bottom">
<ng-container *ngFor="let tab of tabs">
<ion-tab-button [tab]="tab.name">
<ion-icon [name]="tab.icon"></ion-icon>
<ion-label>{{tab.label}}</ion-label>
</ion-tab-button>
</ng-container>
</ion-tab-bar>
</ion-tabs>

AppComponent

마지막으로 TabService의 인스턴스를 생성하기 위해(생성자를 호출하기 위해) 최상위 컴포넌트 생성자에 TabService를 아래와 같이 추가한다.

constructor(
...
private tabService: TabService
) {this.initializeApp()}

이때까지 작업한 내용을 정리하면 다음과 같다.

  • TabService에서는 platform 로드 시 NavigationEnd 이벤트의 경우에 탭을 보이거나 숨기는 함수를 호출한다.
  • 탭 메뉴 엘리먼트에 접근할 아이디를 부여한다.
  • 최상위 컴포넌트에서 TabService 인스턴스를 생성한다.

라우터 파라미터 처리

마지막으로 추가해야할 부분은 다음과 같은 라우터 파라미터가 포함된 페이지경로 처리이다. 파라미터가 있는 부분을 제외한 경로를 가져와야 한다.

/event-detail/102
/group/3
...

TabService에 다음과 같이 라우터 파라미터가 있는 화이트리스트를 추가한다.

routeParamPages: string[] = [
'event-detail',
'group',
...
];

hideOrShowTab메소드에서 페이지 경로가 routeParamPages 화이트리스트에 포함되는지 체크하고 shouldHide 플래그에 or 연산자로 조건을 추가한다.

hideOrShowTab(e: NavigationEnd) {
...
const hideParamPage = this.routeParamPages.indexOf(pageUrlParent) > -1 && !isNaN(Number(page));
const shouldHide = this.hideTabPages.indexOf(page) > -1 || hideParamPage;
shouldHide ? this.hide() : this.show())
}

정리

모바일 화면에서는 최대한 컨텐츠에 집중할 수 있도록 간결하게 표현되어야 했다.

탭을 숨길 페이지는 라우터 파리미터가 있는 경로를 포함하여 화이트리스트로 그 목록을 가지도록 하였다.

최상단 레벨의 페이지에서는 탭 메뉴를 통해 네비게이션이 수행되고, 한단계 더 진입한 화면에서는 탭 메뉴를 없애고 그만큼 컨텐츠가 보여지는 부분을 확장시킬 수 있었다.

--

--

이상훈
상훈 Devlog

Frontend Developer 😁😁 #angular #javascript #typescript #scala #node