A Sench Touch 2.4 custom TabPanel with inkbar and ripple effects consistent with Material Design specs.
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
/* | |
Demo: http://dankemper.net/t3/examples/sencha-touch-2.4.2/splitViewPortfolio/ | |
Note: this implementation assumes you are using the RippleService which can be found here: | |
https://github.com/fpt-software/Material-Controls-for-Sencha-Touch/blob/c849787aee8ac75ed168b31b26adea026f4e91d0/SenchaUI/packages/Material/src/helpers/RippleService.js | |
*/ | |
var allListeners = ((Ext.filterPlatform('chrome') || Ext.filterPlatform('android')) && (!Ext.filterPlatform('ios')))? [ | |
{ | |
event: 'show', | |
order: 'after', | |
fn: 'afterShow' | |
}, | |
{ | |
event: 'activeitemchange', | |
fn: 'activeItemChange' | |
} | |
] : null; | |
Ext.define('splitViewPortfolio.view.MaterialPanel', { | |
extend: 'Ext.tab.Panel', | |
requires: ['Material.helpers.RippleService'], | |
initialize: function () { | |
var self = this; | |
self.callParent(); | |
if ((Ext.filterPlatform('chrome') || Ext.filterPlatform('android')) && (!Ext.filterPlatform('ios'))) { | |
var rippleService = Material.RippleService; | |
rippleService.attachTabBehavior(this, this.element, { | |
inkColor: '#607d8b' | |
}); | |
if (Ext.os.is('Desktop')) { | |
Ext.Viewport.on('resize', 'handleResize', self, { scope: self, buffer: 100 }); | |
} | |
} | |
return this; | |
}, | |
config: { | |
listeners: allListeners | |
}, | |
activeItemChange: function (component, value, oldValue, eOpts) { | |
var inkBarConfig = component.stageInkBar(component); | |
var materialClass = '.' + component.getCls()[0]; | |
var tabBarInner = Ext.DomQuery.select(materialClass + ' .x-tabbar > .x-tabbar-inner'); | |
component.inkBarTransition(component, inkBarConfig.mdInkBar, inkBarConfig.selectedTabExt, Ext.get(tabBarInner[0])); | |
}, | |
afterShow: function (component, eOpts) { | |
// Stage ink bar. | |
// | |
var inkBarConfig = component.stageInkBar(component); | |
var materialClass = '.' + component.getCls()[0]; | |
var tabBarInner = Ext.DomQuery.select(materialClass + ' .x-tabbar > .x-tabbar-inner'); | |
component.inkBarTransition(component, inkBarConfig.mdInkBar, inkBarConfig.selectedTabExt, Ext.get(tabBarInner[0])); | |
}, | |
inkBarTransition: function (component, mdInkBar, selectedTabEl, tabBarEl) { | |
// Measuring and calculations for the ink bar. | |
// | |
var totalWidth = tabBarEl.getWidth(); | |
var mdInkBarCurrentOffsets = mdInkBar.getOffsetsTo(tabBarEl); | |
var offsets = selectedTabEl.getOffsetsTo(tabBarEl); | |
var l = offsets[0] + 'px'; | |
var r = totalWidth - offsets[0] - selectedTabEl.getWidth() + 'px'; | |
component.updateInkBarClassName(mdInkBar, mdInkBarCurrentOffsets[0], offsets[0]); | |
mdInkBar.applyStyles({ left: l, right: r }); | |
}, | |
stageInkBar: function (component) { | |
var extInkBar = null; | |
var materialClass = '.' + component.getCls()[0]; | |
var tabBarInner = Ext.DomQuery.select(materialClass + ' .x-tabbar > .x-tabbar-inner'); | |
var existingInkBar = Ext.DomQuery.select(materialClass + ' .x-tabbar > .x-tabbar-inner > .md-ink-bar'); | |
var selectedTab = Ext.DomQuery.select(materialClass + ' .x-tabbar > .x-tabbar-inner > .x-tab-active'); | |
var extSelectedTab = Ext.get(selectedTab[0]); | |
if (existingInkBar.length == 0) { | |
var mdInkBar = document.createElement('div'); | |
mdInkBar.className = 'md-ink-bar'; | |
extInkBar = new Ext.Element(mdInkBar); | |
extInkBar.appendTo(tabBarInner[0]); | |
extInkBar.applyStyles({ top: (extSelectedTab.getHeight() - extInkBar.getHeight()) + 'px' }); | |
component.setMdInkBar(extInkBar); | |
} else { | |
extInkBar = component.getMdInkBar(); | |
} | |
return { mdInkBar: extInkBar, selectedTabExt: extSelectedTab }; | |
}, | |
updateInkBarClassName: function (mdInkBar, mdInkBarOffsetLeft, selectedTabOffsetLeft) { | |
if (selectedTabOffsetLeft > mdInkBarOffsetLeft) { | |
mdInkBar.replaceCls('md-left', 'md-right'); | |
} else { | |
mdInkBar.replaceCls('md-right', 'md-left'); | |
} | |
}, | |
handleResize: function (component, eOpts, opts) { | |
opts.scope.activeItemChange(opts.scope); | |
} | |
}); |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
.md-ink-bar { | |
position: absolute; | |
left: auto; | |
right: auto; | |
bottom: 0; | |
height: 4px; | |
z-index: 300; | |
&.md-left { | |
transition: left ($swift-ease-in-out-duration * 0.45) $swift-ease-in-out-timing-function, right $swift-ease-in-out-duration $swift-ease-in-out-timing-function; | |
} | |
&.md-right { | |
transition: left $swift-ease-in-out-duration $swift-ease-in-out-timing-function, right ($swift-ease-in-out-duration * 0.45) $swift-ease-in-out-timing-function; | |
} | |
background-color: $amber-three-hundred; | |
} |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
/* | |
Demonstrates use of the MaterialPanel. Just be sure to include the class "cls" config with value of "md-tabpanel-x" where x represents the number | |
of tabpanels in your app. Most of the time you will only have/need one. Also include the "mdInkBar" config. Set "mdInkBar" to null. | |
*/ | |
Ext.define('splitViewPortfolio.view.SafeGrid', { | |
extend: 'splitViewPortfolio.view.MaterialPanel', | |
initialize: function () { | |
var self = this; | |
self.callParent(); | |
// Add a Listener. Listen for [Viewport ~ Orientation] Change. | |
// | |
Ext.Viewport.on('orientationchange', 'handleOrientationChange', self, { buffer: 50 }); | |
return this; | |
}, | |
config: { | |
activeTab: 0, | |
cls: 'md-tabpanel-1', | |
mdInkBar: null, | |
scrollable: false, | |
ui: 'light', | |
tabBar: { | |
ui: Ext.filterPlatform('blackberry') || Ext.filterPlatform('ie10') ? 'dark' : 'light', | |
layout: { | |
pack : 'center', | |
align: 'center' | |
}, | |
docked: Ext.filterPlatform('chrome') || Ext.filterPlatform('android') ? 'top' : 'bottom' | |
}, | |
items: [/* your tabpanel items here ... */] | |
// | |
// etc ... | |
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment