Skip to content

Instantly share code, notes, and snippets.

@cristoferdomingues
Created September 21, 2016 18:08
Show Gist options
  • Save cristoferdomingues/6fb4f116ed9abad50fe7e84e7193113e to your computer and use it in GitHub Desktop.
Save cristoferdomingues/6fb4f116ed9abad50fe7e84e7193113e to your computer and use it in GitHub Desktop.
// custom directive to fade in the header bar after scrolling
(function() {
'use strict';
angular
.module('dbaq.ionCoverHeader', [])
.directive('ionCoverHeader', ['$document', '$timeout', '$ionicScrollDelegate', function($document, $timeout, $ionicScrollDelegate) {
/**
* updates the background opacity of an element
*
* this method retrieves automatically the background RGB and set the alpha
*
* @param elem, the DOM element to update the background opacity
* @param alpha, the opacity to apply, anything between 0 and 1.
*/
var updateBackgroundAlpha = function(elem, alpha) {
var currentColor = getComputedStyle(elem).getPropertyValue('background-color');
var match = /rgba?\((\d+)\s*,\s*(\d+)\s*,\s*(\d+)\s*(,\s*\d+[\.\d+]*)*\)/g.exec(currentColor);
elem.style.backgroundColor = 'rgba(' + [match[1], match[2], match[3], alpha].join(',') + ')';
};
/**
* shows the header bar
*
* @param header, the bar-header DOM element
* @param headerTitle, the title DOM element in the bar-header (could be null)
* @param opaqueAt, the value in pixels where the bar-header should be totaly opaque
* @param amt, the current scrolling value, the value in pixels from the top
*/
var showHeader = function(header, headerTitle, opaqueAt, amt) {
var fadeAmt = 1 - (Math.min(opaqueAt, amt) / opaqueAt);
ionic.requestAnimationFrame(function() {
updateBackgroundAlpha(header, (1 - fadeAmt));
if (headerTitle) {
headerTitle.style.opacity = (1 - fadeAmt);
}
});
};
/**
* applies the required style on the header bar and the content
*
* - set the background opacity to 0
* - set the .title element opacity to 0 if exists
* - remove the background image of the header bar
* - set the content top property to 0
*
* @param header, the bar-header DOM element
* @param headerTitle, the title DOM element in the bar-header (could be null)
* @param content, the scroll-content DOM element
*/
var initStyles = function(header, headerTitle, content) {
//header bar background opacity to 0
updateBackgroundAlpha(header, 0);
//header bar background image to none
header.style.backgroundImage = 'none';
//header bar title opactity to 0
if (headerTitle) {
headerTitle.style.opacity = 0;
}
//set the content top property to 0
content.style.top = 0;
};
var computeAmt = function(opaqueAt, scrollTop) {
return scrollTop > 0 ? (opaqueAt - Math.max(0, (opaqueAt - scrollTop))) : 0;
}
return {
restrict: 'A',
link: function($scope, $element, $attr) {
var opaqueAt = $attr.ionCoverHeader || 200;
//retrieves elements that we need, the header bar, the header bar title, the content
var headerElem = $element[0].querySelector('.bar-header');
var contentElem = $element[0].querySelector('.scroll-content');
var ionNavBarElem;
var headerTitleElem;
//check if elems exist
if (!headerElem) {
//if no ion-header-bar, we are looking for an ion-nav-bar
ionNavBarElem = $document[0].querySelector('.nav-bar-container');
if (!ionNavBarElem) {
console.error('ionCoverHeader - no .bar-header or .nav-bar-container element found.');
return;
}
}
if (!contentElem) {
console.error('ionCoverHeader - no .scroll-content element found. Scroll must be enabled on your ion-content.');
return;
}
var onScroll = function(e) {
var scrollTop = e.detail ? e.detail.scrollTop : (e.target ? e.target.scrollTop : null);
showHeader(headerElem, headerTitleElem, opaqueAt, computeAmt(opaqueAt, scrollTop));
};
var init = function (headerElem, headerTitleElem, contentElem) {
// makes the header bar transparent and the content stick to the top
initStyles(headerElem, headerTitleElem, contentElem);
// binds the scroll event to the content
angular.element(contentElem).bind('scroll', onScroll);
};
// init
if (!ionNavBarElem) {
// retrieves the headerTitleElem
headerTitleElem = headerElem.querySelector('.title');
init(headerElem, headerTitleElem, contentElem);
} else {
var ionNavBarCachedElem = null;
var ionNavBarActiveElem = null;
$scope.$on('$ionicView.beforeEnter', function(){
// retrieves both bars generated by <ion-nav-bar> directives
// the active one becomes the cached one and the cached becomes the active one
ionNavBarCachedElem = ionNavBarElem.querySelector('[nav-bar="active"]');
ionNavBarActiveElem = ionNavBarElem.querySelector('[nav-bar="cached"]');
// the header elem is the header in the active bar
headerElem = ionNavBarActiveElem.querySelector('.bar-header');
// retrieves the headerTitleElem
headerTitleElem = headerElem.querySelector('.title');
// hides the cached bar
ionNavBarCachedElem.style.opacity = 0;
init(headerElem, headerTitleElem, contentElem);
// the timeout allows to fix a race condition when using ion-nav-bar on the title opacity
$timeout(function() {
headerTitleElem.style.opacity = 0;
}, 100);
});
// if the view was cached, the scroll position might be greater than 0
// in that case we need to show the header accordingly
$scope.$on('$ionicView.enter', function(){
$timeout(function() {
if ($ionicScrollDelegate.getScrollPosition().top > 0 ) {
showHeader(headerElem, headerTitleElem, opaqueAt, computeAmt(opaqueAt, $ionicScrollDelegate.getScrollPosition().top));
}
});
});
// since the bars are reused for other views, we need to restore the opacity
$scope.$on('$ionicView.beforeLeave', function(){
angular.element(contentElem).unbind('scroll', onScroll);
ionNavBarCachedElem.style.opacity = 1;
$timeout(function() {
updateBackgroundAlpha(headerElem, 1);
headerTitleElem.style.opacity = 1;
});
});
}
}
};
}]);
})();
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment