Skip to content

Commit

Permalink
fix(header): support collapsible header with multiple toolbars (#19909)
Browse files Browse the repository at this point in the history
* begin fix collapsible title with multi toolbars

* fix back button

* adjust large title positioning

* a few adjustments

* remove whitespace

* add types

* fix type
  • Loading branch information
liamdebeasi committed Nov 18, 2019
1 parent 3298fdd commit fc4bb2d
Show file tree
Hide file tree
Showing 4 changed files with 60 additions and 27 deletions.
7 changes: 5 additions & 2 deletions core/src/components/header/header.tsx
Expand Up @@ -101,7 +101,10 @@ export class Header implements ComponentInterface {
if (!mainHeaderIndex || !scrollHeaderIndex) { return; }

setHeaderActive(mainHeaderIndex, false);
setToolbarBackgroundOpacity(mainHeaderIndex.toolbars[0], 0);

mainHeaderIndex.toolbars.forEach(toolbar => {
setToolbarBackgroundOpacity(toolbar, 0);
});

readTask(() => {
const mainHeaderHeight = mainHeaderIndex.el.clientHeight;
Expand All @@ -114,7 +117,7 @@ export class Header implements ComponentInterface {
*/
const toolbarIntersection = (ev: any) => { handleToolbarIntersection(ev, mainHeaderIndex, scrollHeaderIndex); };
this.intersectionObserver = new IntersectionObserver(toolbarIntersection, { threshold: [0.25, 0.3, 0.4, 0.5, 0.6, 0.7, 0.8, 0.9, 1], rootMargin: `-${mainHeaderHeight}px 0px 0px 0px` });
this.intersectionObserver.observe(scrollHeaderIndex.toolbars[0].el);
this.intersectionObserver.observe(scrollHeaderIndex.toolbars[scrollHeaderIndex.toolbars.length - 1].el);

/**
* Handle scaling of large iOS titles and
Expand Down
5 changes: 4 additions & 1 deletion core/src/components/header/header.utils.ts
Expand Up @@ -72,7 +72,10 @@ const handleToolbarBorderIntersection = (ev: any, mainHeaderIndex: HeaderIndex)
if (!ev[0].isIntersecting) { return; }

const scale = ((1 - ev[0].intersectionRatio) * 100) / 75;
setToolbarBackgroundOpacity(mainHeaderIndex.toolbars[0], (scale === 1) ? undefined : scale);

mainHeaderIndex.toolbars.forEach(toolbar => {
setToolbarBackgroundOpacity(toolbar, (scale === 1) ? undefined : scale);
});
};

/**
Expand Down
24 changes: 23 additions & 1 deletion core/src/components/toolbar/test/title/index.html
Expand Up @@ -82,6 +82,28 @@ <h3>Smaller heading ${i}</h2>

this.innerHTML = `
<ion-header class="main-header" translucent>
<ion-toolbar class="main-toolbar">
<ion-segment>
<ion-segment-button value="all">
All
</ion-segment-button>
<ion-segment-button value="favorites">
Favorites
</ion-segment-button>
</ion-segment>
</ion-toolbar>
<ion-toolbar class="main-toolbar">
<ion-segment>
<ion-segment-button value="all">
All
</ion-segment-button>
<ion-segment-button value="favorites">
Favorites
</ion-segment-button>
</ion-segment>
</ion-toolbar>
<ion-toolbar class="main-toolbar">
<ion-buttons collapse>
<ion-back-button default-href="/"></ion-back-button>
Expand Down Expand Up @@ -139,7 +161,7 @@ <h3>Smaller heading ${i}</h2>
<ion-buttons slot="end" collapse>
<ion-button>Hello Page 3</ion-button>
</ion-buttons>
</ion-toolbar>
</ion-toolbar>
</ion-header>
<ion-content id="content" class="three-content" fullscreen color="dark">
Expand Down
51 changes: 28 additions & 23 deletions core/src/utils/transition/ios.transition.ts
Expand Up @@ -48,11 +48,17 @@ const createLargeTitleTransition = (rootAnimation: Animation, rtl: boolean, back
const shouldAnimationBackward = enteringLargeTitle !== null && leavingBackButton !== null && backDirection;

if (shouldAnimationForward) {
animateLargeTitle(rootAnimation, rtl, backDirection, leavingLargeTitle);
animateBackButton(rootAnimation, rtl, backDirection, enteringBackButton);
const leavingLargeTitleBox = leavingLargeTitle.getBoundingClientRect();
const enteringBackButtonBox = enteringBackButton.getBoundingClientRect();

animateLargeTitle(rootAnimation, rtl, backDirection, leavingLargeTitle, leavingLargeTitleBox, enteringBackButtonBox);
animateBackButton(rootAnimation, rtl, backDirection, enteringBackButton, leavingLargeTitleBox, enteringBackButtonBox);
} else if (shouldAnimationBackward) {
animateLargeTitle(rootAnimation, rtl, backDirection, enteringLargeTitle);
animateBackButton(rootAnimation, rtl, backDirection, leavingBackButton);
const enteringLargeTitleBox = enteringLargeTitle.getBoundingClientRect();
const leavingBackButtonBox = leavingBackButton.getBoundingClientRect();

animateLargeTitle(rootAnimation, rtl, backDirection, enteringLargeTitle, enteringLargeTitleBox, leavingBackButtonBox);
animateBackButton(rootAnimation, rtl, backDirection, leavingBackButton, enteringLargeTitleBox, leavingBackButtonBox);
}

return {
Expand All @@ -61,9 +67,8 @@ const createLargeTitleTransition = (rootAnimation: Animation, rtl: boolean, back
};
};

const animateBackButton = (rootAnimation: Animation, rtl: boolean, backDirection: boolean, backButtonEl: any) => {
const backButtonBounds = backButtonEl.getBoundingClientRect();
const BACK_BUTTON_START_OFFSET = (rtl) ? `calc(100% - ${backButtonBounds.right + 4}px)` : `${backButtonBounds.left - 4}px`;
const animateBackButton = (rootAnimation: Animation, rtl: boolean, backDirection: boolean, backButtonEl: any, largeTitleBox: DOMRect, backButtonBox: DOMRect) => {
const BACK_BUTTON_START_OFFSET = (rtl) ? `calc(100% - ${backButtonBox.right + 4}px)` : `${backButtonBox.left - 4}px`;
const START_TEXT_TRANSLATE = (rtl) ? '7px' : '-7px';
const END_TEXT_TRANSLATE = (rtl) ? '-4px' : '4px';

Expand All @@ -73,24 +78,24 @@ const animateBackButton = (rootAnimation: Animation, rtl: boolean, backDirection
const ICON_ORIGIN_X = (rtl) ? 'left' : 'right';

const FORWARD_TEXT_KEYFRAMES = [
{ offset: 0, opacity: 0, transform: `translate(${START_TEXT_TRANSLATE}, ${addSafeArea(8)}) scale(2.1)` },
{ offset: 1, opacity: 1, transform: `translate(${END_TEXT_TRANSLATE}, ${addSafeArea(-40)}) scale(1)` }
{ offset: 0, opacity: 0, transform: `translate(${START_TEXT_TRANSLATE}, ${addSafeArea(largeTitleBox.top - 40)}) scale(2.1)` },
{ offset: 1, opacity: 1, transform: `translate(${END_TEXT_TRANSLATE}, ${addSafeArea(backButtonBox.top - 46)}) scale(1)` }
];
const BACKWARD_TEXT_KEYFRAMES = [
{ offset: 0, opacity: 1, transform: `translate(${END_TEXT_TRANSLATE}, ${addSafeArea(-40)}) scale(1)` },
{ offset: 0, opacity: 1, transform: `translate(${END_TEXT_TRANSLATE}, ${addSafeArea(backButtonBox.top - 46)}) scale(1)` },
{ offset: 0.6, opacity: 0 },
{ offset: 1, opacity: 0, transform: `translate(${START_TEXT_TRANSLATE}, ${addSafeArea(8)}) scale(2.1)` }
{ offset: 1, opacity: 0, transform: `translate(${START_TEXT_TRANSLATE}, ${addSafeArea(largeTitleBox.top - 40)}) scale(2.1)` }
];
const TEXT_KEYFRAMES = (backDirection) ? BACKWARD_TEXT_KEYFRAMES : FORWARD_TEXT_KEYFRAMES;

const FORWARD_ICON_KEYFRAMES = [
{ offset: 0, opacity: 0, transform: `translate3d(${ICON_TRANSLATE}, ${addSafeArea(-35)}, 0) scale(0.6)` },
{ offset: 1, opacity: 1, transform: `translate3d(${ICON_TRANSLATE}, ${addSafeArea(-40)}, 0) scale(1)` }
{ offset: 0, opacity: 0, transform: `translate3d(${ICON_TRANSLATE}, ${addSafeArea(backButtonBox.top - 41)}, 0) scale(0.6)` },
{ offset: 1, opacity: 1, transform: `translate3d(${ICON_TRANSLATE}, ${addSafeArea(backButtonBox.top - 46)}, 0) scale(1)` }
];
const BACKWARD_ICON_KEYFRAMES = [
{ offset: 0, opacity: 1, transform: `translate(${ICON_TRANSLATE}, ${addSafeArea(-40)}) scale(1)` },
{ offset: 0.2, opacity: 0, transform: `translate(${ICON_TRANSLATE}, ${addSafeArea(-35)}) scale(0.6)` },
{ offset: 1, opacity: 0, transform: `translate(${ICON_TRANSLATE}, ${addSafeArea(-35)}) scale(0.6)` }
{ offset: 0, opacity: 1, transform: `translate(${ICON_TRANSLATE}, ${addSafeArea(backButtonBox.top - 46)}) scale(1)` },
{ offset: 0.2, opacity: 0, transform: `translate(${ICON_TRANSLATE}, ${addSafeArea(backButtonBox.top - 41)}) scale(0.6)` },
{ offset: 1, opacity: 0, transform: `translate(${ICON_TRANSLATE}, ${addSafeArea(backButtonBox.top - 41)}) scale(0.6)` }
];
const ICON_KEYFRAMES = (backDirection) ? BACKWARD_ICON_KEYFRAMES : FORWARD_ICON_KEYFRAMES;

Expand Down Expand Up @@ -138,22 +143,22 @@ const animateBackButton = (rootAnimation: Animation, rtl: boolean, backDirection
rootAnimation.addAnimation([enteringBackButtonTextAnimation, enteringBackButtonIconAnimation]);
};

const animateLargeTitle = (rootAnimation: Animation, rtl: boolean, backDirection: boolean, largeTitleEl: any) => {
const largeTitleBounds = largeTitleEl.getBoundingClientRect();
const TITLE_START_OFFSET = (rtl) ? `calc(100% - ${largeTitleBounds.right}px)` : `${largeTitleBounds.left}px`;
const animateLargeTitle = (rootAnimation: Animation, rtl: boolean, backDirection: boolean, largeTitleEl: any, largeTitleBox: DOMRect, backButtonBox: DOMRect) => {
const TITLE_START_OFFSET = (rtl) ? `calc(100% - ${largeTitleEl.right}px)` : `${largeTitleEl.left}px`;
const START_TRANSLATE = (rtl) ? '-18px' : '18px';
const ORIGIN_X = (rtl) ? 'right' : 'left';

const BACKWARDS_KEYFRAMES = [
{ offset: 0, opacity: 0, transform: `translate(${START_TRANSLATE}, ${addSafeArea(0)}) scale(0.49)` },
{ offset: 0, opacity: 0, transform: `translate(${START_TRANSLATE}, ${addSafeArea(backButtonBox.top - 4)}) scale(0.49)` },
{ offset: 0.1, opacity: 0 },
{ offset: 1, opacity: 1, transform: `translate(0, ${addSafeArea(49)}) scale(1)` }
{ offset: 1, opacity: 1, transform: `translate(0, ${addSafeArea(largeTitleBox.top - 2)}) scale(1)` }
];
const FORWARDS_KEYFRAMES = [
{ offset: 0, opacity: 0.99, transform: `translate(0, ${addSafeArea(49)}) scale(1)` },
{ offset: 0, opacity: 0.99, transform: `translate(0, ${addSafeArea(largeTitleBox.top - 2)}) scale(1)` },
{ offset: 0.6, opacity: 0 },
{ offset: 1, opacity: 0, transform: `translate(${START_TRANSLATE}, ${addSafeArea(0)}) scale(0.5)` }
{ offset: 1, opacity: 0, transform: `translate(${START_TRANSLATE}, ${addSafeArea(backButtonBox.top - 4)}) scale(0.5)` }
];

const KEYFRAMES = (backDirection) ? BACKWARDS_KEYFRAMES : FORWARDS_KEYFRAMES;

const clonedTitleEl = getClonedElement('ion-title');
Expand Down

0 comments on commit fc4bb2d

Please sign in to comment.