diff --git a/src/bottom-navigation/angular/index.ts b/src/bottom-navigation/angular/index.ts new file mode 100644 index 000000000..438abb5a4 --- /dev/null +++ b/src/bottom-navigation/angular/index.ts @@ -0,0 +1,14 @@ +import { Directive, NgModule } from '@angular/core'; +import { registerElement } from '@nativescript/angular'; +import { BottomNavigation } from '@nativescript-community/ui-material-bottomnavigation'; + +@Directive({ selector: 'MDBottomNavigation' }) +export class MaterialBottomNavigationDirective {} + +@NgModule({ + declarations: [MaterialBottomNavigationDirective], + exports: [MaterialBottomNavigationDirective] +}) +export class NativeScriptMaterialBottomNavigationModule {} + +registerElement('MDBottomNavigation', () => BottomNavigation); diff --git a/src/bottom-navigation/angular/package.json b/src/bottom-navigation/angular/package.json new file mode 100644 index 000000000..dafd159ea --- /dev/null +++ b/src/bottom-navigation/angular/package.json @@ -0,0 +1,18 @@ +{ + "name": "@nativescript-community/ui-material-bottomnavigation-angular", + "main": "index.js", + "ngPackage": { + "dest":"../../../packages/bottomnavigation/angular", + "lib": { + "entryFile": "index.ts", + "umdModuleIds": { + "@nativescript/core": "ns-core", + "@nativescript/angular": "ns-angular", + "@nativescript-community/ui-material-bottomnavigation": "ns-material-bottomnavigation" + } + }, + "whitelistedNonPeerDependencies": [ + "." + ] + } +} diff --git a/src/bottom-navigation/angular/tsconfig.json b/src/bottom-navigation/angular/tsconfig.json new file mode 100644 index 000000000..c47c0b31a --- /dev/null +++ b/src/bottom-navigation/angular/tsconfig.json @@ -0,0 +1,18 @@ +{ + "extends": "../../../tsconfig.json", + "compilerOptions": { + "rootDir": "./", + "paths": { + "tns-core-modules": ["./node_modules/@nativescript/core"], + "tns-core-modules/*": ["./node_modules/@nativescript/core/*"], + "@nativescript-community/ui-material-core": ["packages/core/index"], + "@nativescript-community/ui-material-core/*": ["packages/core/*"], + "@nativescript-community/ui-material-bottomnavigation": ["packages/bottomnavigation/index"], + "@nativescript-community/ui-material-bottomnavigation/*": ["packages/bottomnavigation/*"] + } + }, + "include": ["./**/*.ts", "../../../references.d.ts", "../../references.d.ts"], + "angularCompilerOptions": { + "enableIvy": true + } +} diff --git a/src/bottom-navigation/index.android.ts b/src/bottom-navigation/index.android.ts index bccd7754a..b6c2a6888 100644 --- a/src/bottom-navigation/index.android.ts +++ b/src/bottom-navigation/index.android.ts @@ -6,6 +6,7 @@ import { TabStripItem } from '@nativescript-community/ui-material-core/tab-navig // Requires import { Application, CSSType, Color, Font, Frame, ImageSource, Utils, View, getIconSpecSize } from '@nativescript/core'; import { TextTransform, getTransformedText } from '@nativescript/core/ui/text-base'; +export { TabContentItem, TabStrip, TabStripItem }; // TODO: Impl trace // import { Trace } from "../../../trace"; @@ -344,19 +345,21 @@ export class BottomNavigation extends TabNavigationBase { iterateIndexRange(newIndex, offsideItems, lastIndex, (i) => toLoad.push(i)); - items.forEach((item, i) => { - const indexOfI = toLoad.indexOf(i); - if (indexOfI < 0) { - toUnload.push(i); - } - }); + if (this.unloadOnTabChange) { + items.forEach((item, i) => { + const indexOfI = toLoad.indexOf(i); + if (indexOfI < 0) { + toUnload.push(i); + } + }); - toUnload.forEach((index) => { - const item = items[index]; - if (items[index]) { - item.unloadView(item.content); - } - }); + toUnload.forEach((index) => { + const item = items[index]; + if (items[index]) { + item.unloadView(item.content); + } + }); + } const newItem = items[newIndex]; const selectedView = newItem && newItem.content; @@ -417,11 +420,10 @@ export class BottomNavigation extends TabNavigationBase { this.setTabStripItems(null); } - const fragmentToDetach = this._currentFragment; - if (fragmentToDetach) { - this.destroyItem((fragmentToDetach as any).index, fragmentToDetach); - this.removeFragment(fragmentToDetach); - } + this.items.forEach((item, i) => { + item.unloadView(item.content); + }); + this.disposeTabFragments(); } public disposeNativeView() { @@ -495,7 +497,12 @@ export class BottomNavigation extends TabNavigationBase { const fragmentToDetach = this._currentFragment; if (fragmentToDetach) { - this.destroyItem((fragmentToDetach as any).index, fragmentToDetach); + console.log('unloadOnTabChange', this.unloadOnTabChange); + if (this.unloadOnTabChange) { + this.destroyItem((fragmentToDetach as any).index, fragmentToDetach); + } else { + this.hideFragment(fragmentToDetach as any); + } } const fragment = this.instantiateItem(this._contentView, index); @@ -532,6 +539,9 @@ export class BottomNavigation extends TabNavigationBase { if (fragment != null) { fragment.setMenuVisibility(true); fragment.setUserVisibleHint(true); + if (!this.unloadOnTabChange) { + this.showFragment(fragment); + } } this._currentFragment = fragment; @@ -545,7 +555,6 @@ export class BottomNavigation extends TabNavigationBase { } } } - private destroyItem(position: number, fragment: androidx.fragment.app.Fragment): void { if (fragment) { this.removeFragment(fragment); @@ -553,11 +562,66 @@ export class BottomNavigation extends TabNavigationBase { this._currentFragment = null; } } - if (this.items && this.items[position]) { this.items[position].canBeLoaded = false; } } + private hideFragment(fragment: androidx.fragment.app.Fragment, fragmentManager?: any) { + if (!fragmentManager) { + fragmentManager = this._getFragmentManager(); + } + if (fragment) { + if (!fragment.isAdded() || fragment.isRemoving()) { + // ignore + return; + } else { + const fragmentExitTransition = fragment.getExitTransition(); + if (fragmentExitTransition && fragmentExitTransition instanceof org.nativescript.widgets.CustomTransition) { + fragmentExitTransition.setResetOnTransitionEnd(true); + } + if (fragment && fragment.isAdded() && !fragment.isRemoving()) { + const pfm = (fragment as any).getParentFragmentManager ? (fragment as any).getParentFragmentManager() : null; + if (pfm && !pfm.isDestroyed()) { + try { + if (pfm.isStateSaved()) { + pfm.beginTransaction().hide(fragment).commitNowAllowingStateLoss(); + } else { + pfm.beginTransaction().hide(fragment).commitNow(); + } + } catch (e) {} + } + } + } + } + } + private showFragment(fragment: androidx.fragment.app.Fragment, fragmentManager?: any) { + if (!fragmentManager) { + fragmentManager = this._getFragmentManager(); + } + if (fragment) { + if (!fragment.isAdded() || fragment.isRemoving()) { + // ignore + return; + } else { + const fragmentExitTransition = fragment.getExitTransition(); + if (fragmentExitTransition && fragmentExitTransition instanceof org.nativescript.widgets.CustomTransition) { + fragmentExitTransition.setResetOnTransitionEnd(true); + } + if (fragment && fragment.isAdded() && !fragment.isRemoving()) { + const pfm = (fragment as any).getParentFragmentManager ? (fragment as any).getParentFragmentManager() : null; + if (pfm && !pfm.isDestroyed()) { + try { + if (pfm.isStateSaved()) { + pfm.beginTransaction().show(fragment).commitNowAllowingStateLoss(); + } else { + pfm.beginTransaction().show(fragment).commitNow(); + } + } catch (e) {} + } + } + } + } + } private removeFragment(fragment: androidx.fragment.app.Fragment, fragmentManager?: any) { if (!fragmentManager) { fragmentManager = this._getFragmentManager(); diff --git a/src/bottom-navigation/index.d.ts b/src/bottom-navigation/index.d.ts index f2e6e6de6..3391ceab6 100644 --- a/src/bottom-navigation/index.d.ts +++ b/src/bottom-navigation/index.d.ts @@ -2,7 +2,9 @@ import { TabNavigationBase } from '@nativescript-community/ui-material-core/tab-navigation-base/tab-navigation-base'; import { TabStrip } from '@nativescript-community/ui-material-core/tab-navigation-base/tab-strip'; import { CoercibleProperty, EventData, Property } from '@nativescript/core'; +import { TabStripItem } from '@nativescript-community/ui-material-core/tab-navigation-base/tab-strip-item'; +export { TabContentItem, TabStrip, TabStripItem }; /** * Defines the data for the TabView.selectedIndexChanged event. */ diff --git a/src/bottom-navigation/index.ios.ts b/src/bottom-navigation/index.ios.ts index 15063d21f..dacef84c4 100644 --- a/src/bottom-navigation/index.ios.ts +++ b/src/bottom-navigation/index.ios.ts @@ -5,9 +5,10 @@ import { TabStrip } from '@nativescript-community/ui-material-core/tab-navigatio import { TabStripItem } from '@nativescript-community/ui-material-core/tab-navigation-base/tab-strip-item'; // Types // Requires -import { Application, CSSType, Color, Device, Font, Frame, IOSHelper, ImageSource, Utils, View, getIconSpecSize } from '@nativescript/core'; +import { CSSType, Color, Device, Font, Frame, IOSHelper, ImageSource, Utils, View, getIconSpecSize } from '@nativescript/core'; import { TextTransform, getTransformedText } from '@nativescript/core/ui/text-base'; import { iOSNativeHelper } from '@nativescript/core/utils'; +export { TabContentItem, TabStrip, TabStripItem }; // TODO: // import { profile } from "../../profiling"; @@ -79,10 +80,14 @@ class UITabBarControllerImpl extends UITabBarController { if (majorVersion >= 13) { const owner = this._owner.get(); - if (owner && this.traitCollection.hasDifferentColorAppearanceComparedToTraitCollection && this.traitCollection.hasDifferentColorAppearanceComparedToTraitCollection(previousTraitCollection)) { + if ( + owner && + this.traitCollection.hasDifferentColorAppearanceComparedToTraitCollection && + this.traitCollection.hasDifferentColorAppearanceComparedToTraitCollection(previousTraitCollection) + ) { owner.notify({ eventName: IOSHelper.traitCollectionColorAppearanceChangedEvent, - object: owner, + object: owner }); } } @@ -125,7 +130,7 @@ class UITabBarControllerDelegateImpl extends NSObject implements UITabBarControl tabStrip.notify({ eventName: TabStrip.itemTapEvent, object: tabStrip, - index: position, + index: position }); } } @@ -230,7 +235,7 @@ function updateTitleAndIconPositions(tabStripItem: TabStripItem, tabBarItem: UIT if (isIconAboveTitle) { tabBarItem.titlePositionAdjustment = { horizontal: 0, - vertical: -20, + vertical: -20 }; } else { tabBarItem.titlePositionAdjustment = { horizontal: 0, vertical: 0 }; @@ -243,14 +248,14 @@ function updateTitleAndIconPositions(tabStripItem: TabStripItem, tabBarItem: UIT top: 6, left: 0, bottom: -6, - right: 0, + right: 0 }); } else { tabBarItem.imageInsets = new UIEdgeInsets({ top: 0, left: 0, bottom: 0, - right: 0, + right: 0 }); } } @@ -303,14 +308,19 @@ export class BottomNavigation extends TabNavigationBase { } this._ios.delegate = this._delegate; + this.onSelectedIndexChanged(selectedIndex, selectedIndex); } public onUnloaded() { this._ios.delegate = null; this._ios.moreNavigationController.delegate = null; super.onUnloaded(); + this.items.forEach((item, i) => { + item.unloadView(item.content); + }); } + // @ts-ignore get ios(): UITabBarController { return this._ios; } @@ -328,11 +338,12 @@ export class BottomNavigation extends TabNavigationBase { if (!items) { return; } - - const oldItem = items[oldIndex]; - if (oldItem) { - oldItem.canBeLoaded = false; - oldItem.unloadView(oldItem.content); + if (this.unloadOnTabChange) { + const oldItem = items[oldIndex]; + if (oldItem) { + oldItem.canBeLoaded = false; + oldItem.unloadView(oldItem.content); + } } const newItem = items[newIndex]; @@ -704,7 +715,7 @@ export class BottomNavigation extends TabNavigationBase { const iconSpecSize = getIconSpecSize({ width: inWidth, - height: inHeight, + height: inHeight }); const widthPts = iconSpecSize.width; @@ -743,7 +754,6 @@ export class BottomNavigation extends TabNavigationBase { // if (Trace.isEnabled()) { // Trace.write("TabView._onSelectedIndexPropertyChangedSetNativeValue(" + value + ")", Trace.categories.Debug); // } - if (value > -1) { (this._ios as any)._willSelectViewController = this._ios.viewControllers[value]; this._ios.selectedIndex = value; diff --git a/src/bottom-navigation/vue/component.ts b/src/bottom-navigation/vue/component.ts new file mode 100644 index 000000000..6b13b653f --- /dev/null +++ b/src/bottom-navigation/vue/component.ts @@ -0,0 +1,28 @@ +export default { + model: { + prop: 'selectedIndex', + event: 'selectedIndexChange' + }, + + render(h) { + return h( + 'NativeMDBottomNavigation', + { + on: this.$listeners, + attrs: this.$attrs + }, + this.$slots.default + ); + }, + + methods: { + registerTabStrip(tabStrip) { + this.$el.setAttribute('tabStrip', tabStrip); + }, + registerTabContentItem(tabContentItem) { + const items = this.$el.nativeView.items || []; + + this.$el.setAttribute('items', items.concat([tabContentItem])); + } + } +}; diff --git a/src/bottom-navigation/vue/index.ts b/src/bottom-navigation/vue/index.ts new file mode 100644 index 000000000..0ffcb5fe3 --- /dev/null +++ b/src/bottom-navigation/vue/index.ts @@ -0,0 +1,21 @@ +import { BottomNavigation, TabContentItem, TabStrip, TabStripItem } from '../'; + +let installed = false; + +export default { + install(Vue) { + if (!installed) { + installed = true; + Vue.registerElement('MDBottomNavigation', () => BottomNavigation, { + model: { + prop: 'selectedIndex', + event: 'selectedIndexChange' + }, + component: require('./component').default + }); + Vue.registerElement('MDTabContentItem', () => TabContentItem, {}); + Vue.registerElement('MDTabStripItem', () => TabStripItem, {}); + Vue.registerElement('MDTabStrip', () => TabStrip, {}); + } + } +}; diff --git a/src/core/tab-navigation-base/tab-content-item/tab-content-item-common.ts b/src/core/tab-navigation-base/tab-content-item/tab-content-item-common.ts index 8bae542e5..146cba983 100644 --- a/src/core/tab-navigation-base/tab-content-item/tab-content-item-common.ts +++ b/src/core/tab-navigation-base/tab-content-item/tab-content-item-common.ts @@ -5,7 +5,7 @@ import { TabNavigationBase } from '../tab-navigation-base'; export const traceCategory = 'TabView'; -@CSSType('TabContentItem') +@CSSType('MDTabContentItem') export abstract class TabContentItemBase extends ContentView implements TabContentItemDefinition, AddChildFromBuilder { public eachChild(callback: (child: View) => boolean) { if (this.content) { diff --git a/src/core/tab-navigation-base/tab-navigation-base/index.d.ts b/src/core/tab-navigation-base/tab-navigation-base/index.d.ts index 8413a6f68..bd53328da 100644 --- a/src/core/tab-navigation-base/tab-navigation-base/index.d.ts +++ b/src/core/tab-navigation-base/tab-navigation-base/index.d.ts @@ -7,13 +7,13 @@ import { TabStripItem } from '../tab-strip-item'; */ export interface SelectedIndexChangedEventData extends EventData { /** - * The old selected index. - */ + * The old selected index. + */ oldIndex: number; /** - * The new selected index. - */ + * The new selected index. + */ newIndex: number; } @@ -22,226 +22,231 @@ export interface SelectedIndexChangedEventData extends EventData { */ export class TabNavigationBase extends View { /** - * Gets or sets the items of the tab navigation. - */ + * Gets or sets the items of the tab navigation. + */ items: TabContentItem[]; /** - * Gets or sets the tab strip of the tab navigation. - */ + * Wheter to unload tabs on tab changed + */ + unloadOnTabChange: boolean; + + /** + * Gets or sets the tab strip of the tab navigation. + */ tabStrip: TabStrip; /** - * Gets or sets the selectedIndex of the tab navigation. - */ + * Gets or sets the selectedIndex of the tab navigation. + */ selectedIndex: number; /** - * Gets the native android widget that represents the user interface for this component. Valid only when running on Android OS. - */ + * Gets the native android widget that represents the user interface for this component. Valid only when running on Android OS. + */ android: any /* android.view.View */; //android.support.v4.view.ViewPager; /** - * Gets the native iOS widget that represents the user interface for this component. Valid only when running on iOS. - */ + * Gets the native iOS widget that represents the user interface for this component. Valid only when running on iOS. + */ ios: any /* UITabBarController */; /** - * String value used when hooking to the selectedIndexChanged event. - */ + * String value used when hooking to the selectedIndexChanged event. + */ public static selectedIndexChangedEvent: string; /** - * A basic method signature to hook an event listener (shortcut alias to the addEventListener method). - * @param eventNames - String corresponding to events (e.g. "propertyChange"). Optionally could be used more events separated by `,` (e.g. "propertyChange", "change"). - * @param callback - Callback function which will be executed when event is raised. - * @param thisArg - An optional parameter which will be used as `this` context for callback execution. - */ + * A basic method signature to hook an event listener (shortcut alias to the addEventListener method). + * @param eventNames - String corresponding to events (e.g. "propertyChange"). Optionally could be used more events separated by `,` (e.g. "propertyChange", "change"). + * @param callback - Callback function which will be executed when event is raised. + * @param thisArg - An optional parameter which will be used as `this` context for callback execution. + */ on(eventNames: string, callback: (data: EventData) => void, thisArg?: any); /** - * Raised when the selected index changes. - */ + * Raised when the selected index changes. + */ on(event: 'selectedIndexChanged', callback: (args: SelectedIndexChangedEventData) => void, thisArg?: any); /** - * @private - * Method is intended to be overridden by inheritors and used as "protected" - */ + * @private + * Method is intended to be overridden by inheritors and used as "protected" + */ onItemsChanged(oldItems: TabContentItem[], newItems: TabContentItem[]): void; /** - * @private - * Method is intended to be overridden by inheritors and used as "protected" - */ + * @private + * Method is intended to be overridden by inheritors and used as "protected" + */ onSelectedIndexChanged(oldIndex: number, newIndex: number): void; /** - * @private - * Method is intended to be overridden by inheritors and used as "protected" - */ + * @private + * Method is intended to be overridden by inheritors and used as "protected" + */ getTabBarBackgroundColor(): any; /** - * @private - * Method is intended to be overridden by inheritors and used as "protected" - */ + * @private + * Method is intended to be overridden by inheritors and used as "protected" + */ getTabBarBackgroundArgbColor(): any; /** - * @private - * Method is intended to be overridden by inheritors and used as "protected" - */ + * @private + * Method is intended to be overridden by inheritors and used as "protected" + */ setTabBarBackgroundColor(value: any): void; /** - * @private - * Method is intended to be overridden by inheritors and used as "protected" - */ + * @private + * Method is intended to be overridden by inheritors and used as "protected" + */ getTabBarColor(): any; /** - * @private - * Method is intended to be overridden by inheritors and used as "protected" - */ + * @private + * Method is intended to be overridden by inheritors and used as "protected" + */ setTabBarColor(value: any): void; /** - * @private - * Method is intended to be overridden by inheritors and used as "protected" - */ + * @private + * Method is intended to be overridden by inheritors and used as "protected" + */ getTabBarFontInternal(): any; /** - * @private - * Method is intended to be overridden by inheritors and used as "protected" - */ + * @private + * Method is intended to be overridden by inheritors and used as "protected" + */ setTabBarFontInternal(value: any): void; /** - * @private - * Method is intended to be overridden by inheritors and used as "protected" - */ + * @private + * Method is intended to be overridden by inheritors and used as "protected" + */ getTabBarTextTransform(): any; /** - * @private - * Method is intended to be overridden by inheritors and used as "protected" - */ + * @private + * Method is intended to be overridden by inheritors and used as "protected" + */ setTabBarTextTransform(value: any): void; /** - * @private - * Method is intended to be overridden by inheritors and used as "protected" - */ + * @private + * Method is intended to be overridden by inheritors and used as "protected" + */ getTabBarHighlightColor(): any; /** - * @private - * Method is intended to be overridden by inheritors and used as "protected" - */ + * @private + * Method is intended to be overridden by inheritors and used as "protected" + */ setTabBarHighlightColor(value: any); /** - * @private - * Method is intended to be overridden by inheritors and used as "protected" - */ + * @private + * Method is intended to be overridden by inheritors and used as "protected" + */ getTabBarSelectedItemColor(): Color; /** - * @private - * Method is intended to be overridden by inheritors and used as "protected" - */ + * @private + * Method is intended to be overridden by inheritors and used as "protected" + */ setTabBarSelectedItemColor(value: Color); /** - * @private - * Method is intended to be overridden by inheritors and used as "protected" - */ + * @private + * Method is intended to be overridden by inheritors and used as "protected" + */ getTabBarUnSelectedItemColor(): Color; /** - * @private - * Method is intended to be overridden by inheritors and used as "protected" - */ + * @private + * Method is intended to be overridden by inheritors and used as "protected" + */ setTabBarUnSelectedItemColor(value: Color); /** - * @private - * Method is intended to be overridden by inheritors and used as "protected" - */ + * @private + * Method is intended to be overridden by inheritors and used as "protected" + */ setTabBarItemTitle(tabStripItem: TabStripItem, value: any): any; /** - * @private - * Method is intended to be overridden by inheritors and used as "protected" - */ + * @private + * Method is intended to be overridden by inheritors and used as "protected" + */ getTabBarItemBackgroundColor(tabStripItem: TabStripItem): any; /** - * @private - * Method is intended to be overridden by inheritors and used as "protected" - */ + * @private + * Method is intended to be overridden by inheritors and used as "protected" + */ setTabBarItemBackgroundColor(tabStripItem: TabStripItem, value: any): void; /** - * @private - * Method is intended to be overridden by inheritors and used as "protected" - */ + * @private + * Method is intended to be overridden by inheritors and used as "protected" + */ getTabBarItemColor(tabStripItem: TabStripItem): any; /** - * @private - * Method is intended to be overridden by inheritors and used as "protected" - */ + * @private + * Method is intended to be overridden by inheritors and used as "protected" + */ setTabBarItemColor(tabStripItem: TabStripItem, value: any): void; /** - * @private - * Method is intended to be overridden by inheritors and used as "protected" - */ + * @private + * Method is intended to be overridden by inheritors and used as "protected" + */ setTabBarIconColor(tabStripItem: TabStripItem, value: any): void; /** - * @private - * Method is intended to be overridden by inheritors and used as "protected" - */ + * @private + * Method is intended to be overridden by inheritors and used as "protected" + */ setTabBarIconSource(tabStripItem: TabStripItem, value: any): void; /** - * @private - * Method is intended to be overridden by inheritors and used as "protected" - */ + * @private + * Method is intended to be overridden by inheritors and used as "protected" + */ getTabBarItemFontSize(tabStripItem: TabStripItem): any; /** - * @private - * Method is intended to be overridden by inheritors and used as "protected" - */ + * @private + * Method is intended to be overridden by inheritors and used as "protected" + */ setTabBarItemFontSize(tabStripItem: TabStripItem, value: any): void; /** - * @private - * Method is intended to be overridden by inheritors and used as "protected" - */ + * @private + * Method is intended to be overridden by inheritors and used as "protected" + */ getTabBarItemFontInternal(tabStripItem: TabStripItem): any; /** - * @private - * Method is intended to be overridden by inheritors and used as "protected" - */ + * @private + * Method is intended to be overridden by inheritors and used as "protected" + */ setTabBarItemFontInternal(tabStripItem: TabStripItem, value: any): void; /** - * @private - * Method is intended to be overridden by inheritors and used as "protected" - */ + * @private + * Method is intended to be overridden by inheritors and used as "protected" + */ getTabBarItemTextTransform(tabStripItem: TabStripItem): any; /** - * @private - * Method is intended to be overridden by inheritors and used as "protected" - */ + * @private + * Method is intended to be overridden by inheritors and used as "protected" + */ setTabBarItemTextTransform(tabStripItem: TabStripItem, value: any): void; } diff --git a/src/core/tab-navigation-base/tab-navigation-base/index.ts b/src/core/tab-navigation-base/tab-navigation-base/index.ts index ea1152f46..63339109f 100644 --- a/src/core/tab-navigation-base/tab-navigation-base/index.ts +++ b/src/core/tab-navigation-base/tab-navigation-base/index.ts @@ -1,5 +1,5 @@ // Types -import { AddArrayFromBuilder, AddChildFromBuilder, CoercibleProperty, Color, EventData, Property, View, ViewBase } from '@nativescript/core'; +import { AddArrayFromBuilder, AddChildFromBuilder, CoercibleProperty, Color, EventData, Property, View, ViewBase, booleanConverter } from '@nativescript/core'; import { TabNavigationBase as TabNavigationBaseDefinition } from '.'; import { TabContentItem } from '../tab-content-item'; import { TabStrip } from '../tab-strip'; @@ -26,6 +26,7 @@ export interface SelectedIndexChangedEventData extends EventData { export class TabNavigationBase extends View implements TabNavigationBaseDefinition, AddChildFromBuilder, AddArrayFromBuilder { public static selectedIndexChangedEvent = 'selectedIndexChanged'; + public unloadOnTabChange: boolean; public items: TabContentItem[]; public tabStrip: TabStrip; public selectedIndex: number; @@ -117,7 +118,7 @@ export class TabNavigationBase extends View implements TabNavigationBaseDefiniti eventName: TabNavigationBase.selectedIndexChangedEvent, object: this, oldIndex, - newIndex, + newIndex } as SelectedIndexChangedEventData); } @@ -248,7 +249,6 @@ export class TabNavigationBase extends View implements TabNavigationBaseDefiniti } } - const MIN_ICON_SIZE = 24; const MAX_ICON_WIDTH = 31; const MAX_ICON_HEIGHT = 28; @@ -301,7 +301,7 @@ export const selectedIndexProperty = new CoercibleProperty parseInt(v, 10), + valueConverter: (v) => parseInt(v, 10) }); selectedIndexProperty.register(TabNavigationBase); @@ -311,7 +311,7 @@ export const itemsProperty = new Property({ name: 'items', valueChanged: (target, oldValue, newValue) => { target.onItemsChanged(oldValue, newValue); - }, + } }); itemsProperty.register(TabNavigationBase); @@ -319,6 +319,13 @@ export const tabStripProperty = new Property({ name: 'tabStrip', valueChanged: (target, oldValue, newValue) => { target.onTabStripChanged(oldValue, newValue); - }, + } }); tabStripProperty.register(TabNavigationBase); + +export const unloadOnTabChangeProperty = new Property({ + name: 'unloadOnTabChange', + defaultValue: true, + valueConverter: booleanConverter +}); +unloadOnTabChangeProperty.register(TabNavigationBase); diff --git a/src/core/tab-navigation-base/tab-strip-item/index.ts b/src/core/tab-navigation-base/tab-strip-item/index.ts index 585e7bb4d..8fa6196a5 100644 --- a/src/core/tab-navigation-base/tab-strip-item/index.ts +++ b/src/core/tab-navigation-base/tab-strip-item/index.ts @@ -7,7 +7,7 @@ import { TabNavigationBase } from '../tab-navigation-base'; import { TabStrip } from '../tab-strip'; -@CSSType('TabStripItem') +@CSSType('MDTabStripItem') export class TabStripItem extends View implements TabStripItemDefinition, AddChildFromBuilder { public static tapEvent = 'tap'; public static selectEvent = 'select'; diff --git a/src/core/tab-navigation-base/tab-strip/index.d.ts b/src/core/tab-navigation-base/tab-strip/index.d.ts index 73c149d46..d3c9d96ed 100644 --- a/src/core/tab-navigation-base/tab-strip/index.d.ts +++ b/src/core/tab-navigation-base/tab-strip/index.d.ts @@ -72,7 +72,7 @@ export interface TabStripItemEventData extends EventData { /** * The index of the TabStripItem. */ - index: number; + index?: number; } export const iosIconRenderingModeProperty: Property; diff --git a/src/core/tab-navigation-base/tab-strip/index.ts b/src/core/tab-navigation-base/tab-strip/index.ts index 0024681df..48fae8618 100644 --- a/src/core/tab-navigation-base/tab-strip/index.ts +++ b/src/core/tab-navigation-base/tab-strip/index.ts @@ -13,30 +13,20 @@ export const traceCategory = 'TabView'; export const highlightColorProperty = new Property({ name: 'highlightColor', equalityComparer: Color.equals, - valueConverter: (v) => new Color(v), + valueConverter: (v) => new Color(v) }); export const selectedItemColorProperty = new Property({ name: 'selectedItemColor', equalityComparer: Color.equals, - valueConverter: (v) => new Color(v), + valueConverter: (v) => new Color(v) }); export const unSelectedItemColorProperty = new Property({ name: 'unSelectedItemColor', equalityComparer: Color.equals, - valueConverter: (v) => new Color(v), + valueConverter: (v) => new Color(v) }); -/** - * Event data containing information for the TabStripItem's index. - */ -export interface TabStripItemEventData extends EventData { - /** - * The index of the TabStripItem. - */ - index: number; -} - -@CSSType('TabStrip') +@CSSType('MDTabStrip') export class TabStrip extends View implements TabStripDefinition, AddChildFromBuilder, AddArrayFromBuilder { public static itemTapEvent = 'itemTap'; public items: TabStripItem[]; @@ -175,7 +165,7 @@ const itemsProperty = new Property({ name: 'items', valueChanged: (target, oldValue, newValue) => { target.onItemsChanged(oldValue, newValue); - }, + } }); itemsProperty.register(TabStrip); @@ -185,7 +175,7 @@ iosIconRenderingModeProperty.register(TabStrip); export const isIconSizeFixedProperty = new Property({ name: 'isIconSizeFixed', defaultValue: true, - valueConverter: booleanConverter, + valueConverter: booleanConverter }); isIconSizeFixedProperty.register(TabStrip); diff --git a/src/tabs/tabs-common.ts b/src/tabs/tabs-common.ts index 48b3fd771..e2fd24730 100644 --- a/src/tabs/tabs-common.ts +++ b/src/tabs/tabs-common.ts @@ -1,6 +1,8 @@ import { cssProperty } from '@nativescript-community/ui-material-core'; // Types -import { CSSType, Color, Property, TabNavigationBase, booleanConverter } from '@nativescript/core'; +import { CSSType, Color, Property, booleanConverter } from '@nativescript/core'; +import { TabNavigationBase } from '@nativescript-community/ui-material-core/tab-navigation-base/tab-navigation-base'; + import { Tabs as TabsDefinition } from './tabs'; export const traceCategory = 'TabView'; @@ -21,14 +23,18 @@ export class TabsBase extends TabNavigationBase implements TabsDefinition { // TODO: Add Unit tests export const swipeEnabledProperty = new Property({ - name: 'swipeEnabled', defaultValue: true, valueConverter: booleanConverter + name: 'swipeEnabled', + defaultValue: true, + valueConverter: booleanConverter }); swipeEnabledProperty.register(TabsBase); // TODO: Add Unit tests // TODO: Coerce to max number of items? export const offscreenTabLimitProperty = new Property({ - name: 'offscreenTabLimit', defaultValue: 1, valueConverter: (v) => parseInt(v, 10) + name: 'offscreenTabLimit', + defaultValue: 1, + valueConverter: (v) => parseInt(v, 10) }); offscreenTabLimitProperty.register(TabsBase); diff --git a/src/tabs/tabs.android.ts b/src/tabs/tabs.android.ts index 88c36640b..2fb73ddc4 100644 --- a/src/tabs/tabs.android.ts +++ b/src/tabs/tabs.android.ts @@ -1,22 +1,10 @@ -import { - Application, - CoercibleProperty, - Color, - Font, - Frame, - ImageSource, - Property, - TabContentItem, - TabStrip, - TabStripItem, - TextTransform, - Utils, - getIconSpecSize, - getTransformedText, - isIOS, - tabStripProperty, -} from '@nativescript/core'; +import { Application, CoercibleProperty, Color, Font, Frame, ImageSource, Property, TextTransform, Utils, getIconSpecSize, getTransformedText, isIOS } from '@nativescript/core'; +import { TabStrip } from '@nativescript-community/ui-material-core/tab-navigation-base/tab-strip'; +import { TabStripItem } from '@nativescript-community/ui-material-core/tab-navigation-base/tab-strip-item'; +import { TabContentItem } from '@nativescript-community/ui-material-core/tab-navigation-base/tab-content-item'; import { TabsBase, animationEnabledProperty, offscreenTabLimitProperty, swipeEnabledProperty } from './tabs-common'; +import { itemsProperty, selectedIndexProperty, tabStripProperty } from '@nativescript-community/ui-material-core/tab-navigation-base/tab-navigation-base'; +export { TabContentItem, TabStrip, TabStripItem }; export * from './tabs-common'; @@ -34,38 +22,6 @@ let PagerAdapter: PagerAdapter; let TabsBar: any; let appResources: android.content.res.Resources; -const itemsProperty = new Property({ - name: 'items', - valueChanged: (target, oldValue, newValue) => { - target.onItemsChanged(oldValue, newValue); - }, -}); -const selectedIndexProperty = new CoercibleProperty({ - name: 'selectedIndex', - defaultValue: -1, - affectsLayout: isIOS, - valueChanged: (target, oldValue, newValue) => { - target.onSelectedIndexChanged(oldValue, newValue); - }, - coerceValue: (target, value) => { - const items = target.items; - if (items) { - const max = items.length - 1; - if (value < 0) { - value = 0; - } - if (value > max) { - value = max; - } - } else { - value = -1; - } - - return value; - }, - valueConverter: (v) => parseInt(v, 10), -}); - function makeFragmentName(viewId: number, id: number): string { return 'android:viewpager:' + viewId + ':' + id; } @@ -968,7 +924,7 @@ export class Tabs extends TabsBase { } [itemsProperty.setNative](value: TabContentItem[]) { this.setItems(value); - selectedIndexProperty.coerce(this); + selectedIndexProperty.coerce(this as any); } [tabStripProperty.getDefault](): TabStrip { @@ -1007,6 +963,3 @@ function tryCloneDrawable(value: android.graphics.drawable.Drawable, resources: return value; } - -itemsProperty.register(Tabs); -selectedIndexProperty.register(Tabs); diff --git a/src/tabs/tabs.d.ts b/src/tabs/tabs.d.ts index 329770fe7..19a05949f 100644 --- a/src/tabs/tabs.d.ts +++ b/src/tabs/tabs.d.ts @@ -3,8 +3,12 @@ * @module "ui/tabs" */ /** */ -import { Property, TabContentItem, TabNavigationBase, TabStrip } from '@nativescript/core'; - +import { Property } from '@nativescript/core'; +import { TabNavigationBase } from '@nativescript-community/ui-material-core/tab-navigation-base/tab-navigation-base'; +import { TabContentItem } from '@nativescript-community/ui-material-core/tab-navigation-base/tab-content-item'; +import { TabStrip } from '@nativescript-community/ui-material-core/tab-navigation-base/tab-strip'; +import { TabStripItem } from '@nativescript-community/ui-material-core/tab-navigation-base/tab-strip-item'; +export { TabContentItem, TabStrip, TabStripItem }; /** * Represents a swipeable tabs view. */ diff --git a/src/tabs/tabs.ios.ts b/src/tabs/tabs.ios.ts index ea939f7c2..d46996c39 100644 --- a/src/tabs/tabs.ios.ts +++ b/src/tabs/tabs.ios.ts @@ -1,8 +1,13 @@ import { rippleColorProperty, themer } from '@nativescript-community/ui-material-core'; -import { Color, Device, Font, Frame, IOSHelper, ImageSource, TabContentItem, TabStrip, TabStripItem, TextTransform, Utils, View, ViewBase, getIconSpecSize } from '@nativescript/core'; -import { itemsProperty, selectedIndexProperty, tabStripProperty } from '@nativescript/core/ui/tab-navigation-base/tab-navigation-base'; +import { Color, Device, Font, Frame, IOSHelper, ImageSource, Trace, Utils, View, ViewBase, getIconSpecSize } from '@nativescript/core'; import { TabsBase, swipeEnabledProperty } from './tabs-common'; +import { itemsProperty, selectedIndexProperty, tabStripProperty } from '@nativescript-community/ui-material-core/tab-navigation-base/tab-navigation-base'; +import { TabStrip } from '@nativescript-community/ui-material-core/tab-navigation-base/tab-strip'; +import { TabStripItem } from '@nativescript-community/ui-material-core/tab-navigation-base/tab-strip-item'; +import { TabContentItem } from '@nativescript-community/ui-material-core/tab-navigation-base/tab-content-item'; +export { TabContentItem, TabStrip, TabStripItem }; + // TODO // import { profile } from "../../profiling"; @@ -276,7 +281,6 @@ class UIPageViewControllerDataSourceImpl extends NSObject implements UIPageViewC // if (traceEnabled()) { // traceWrite("TabView.delegate.SHOULD_select(" + tabBarController + ", " + viewController + ");", traceCategories.Debug); // } - const owner = this._owner.get(); let selectedIndex = owner.selectedIndex; @@ -299,9 +303,8 @@ class UIPageViewControllerDataSourceImpl extends NSObject implements UIPageViewC } public pageViewControllerViewControllerAfterViewController(pageViewController: UIPageViewController, viewController: UIViewController): UIViewController { - // TODO - // if (traceEnabled()) { - // traceWrite("TabView.delegate.SHOULD_select(" + tabBarController + ", " + viewController + ");", traceCategories.Debug); + // if (Trace.isEnabled()) { + // traceWrite('TabView.delegate.SHOULD_select(' + tabBarController + ', ' + viewController + ');', traceCategories.Debug); // } const owner = this._owner.get(); @@ -586,20 +589,21 @@ export class Tabs extends TabsBase { iterateIndexRange(newIndex, offsideItems, lastIndex, (i) => toLoad.push(i)); - items.forEach((item, i) => { - const indexOfI = toLoad.indexOf(i); - if (indexOfI < 0) { - toUnload.push(i); - } - }); - - toUnload.forEach((index) => { - const item = items[index]; - if (items[index]) { - item.unloadView(item.content); - } - }); + if (this.unloadOnTabChange) { + items.forEach((item, i) => { + const indexOfI = toLoad.indexOf(i); + if (indexOfI < 0) { + toUnload.push(i); + } + }); + toUnload.forEach((index) => { + const item = items[index]; + if (items[index]) { + item.unloadView(item.content); + } + }); + } const newItem = items[newIndex]; const selectedView = newItem && newItem.content; if (selectedView instanceof Frame) { @@ -705,7 +709,6 @@ export class Tabs extends TabsBase { tabStripItems[this.selectedIndex]._emit(TabStripItem.selectEvent); } } - items.forEach((item, i) => { const controller = this.getViewController(item); @@ -737,6 +740,7 @@ export class Tabs extends TabsBase { // TODO: investigate why this call is necessary to actually toggle item appearance this.viewController.tabBar.sizeToFit(); if (this.selectedIndex) { + console.log('setSelectedItemAnimated', this.selectedIndex); this.viewController.tabBar.setSelectedItemAnimated(this.tabBarItems[this.selectedIndex], false); } } @@ -1084,7 +1088,6 @@ export class Tabs extends TabsBase { // if (traceEnabled()) { // traceWrite("TabView._onSelectedIndexPropertyChangedSetNativeValue(" + value + ")", traceCategories.Debug); // } - if (value > -1) { const item = this.items[value]; const controllers = NSMutableArray.alloc().initWithCapacity(1); diff --git a/src/tabs/vue/tabsComponent.ts b/src/tabs/vue/component.ts similarity index 85% rename from src/tabs/vue/tabsComponent.ts rename to src/tabs/vue/component.ts index d2bd780cc..0324e9bae 100644 --- a/src/tabs/vue/tabsComponent.ts +++ b/src/tabs/vue/component.ts @@ -1,7 +1,7 @@ export default { model: { prop: 'selectedIndex', - event: 'selectedIndexChange', + event: 'selectedIndexChange' }, render(h) { @@ -9,7 +9,7 @@ export default { 'NativeMDTabs', { on: this.$listeners, - attrs: this.$attrs, + attrs: this.$attrs }, this.$slots.default ); @@ -23,6 +23,6 @@ export default { const items = this.$el.nativeView.items || []; this.$el.setAttribute('items', items.concat([tabContentItem])); - }, - }, + } + } }; diff --git a/src/tabs/vue/index.ts b/src/tabs/vue/index.ts index 21324430d..e1f96cfb3 100644 --- a/src/tabs/vue/index.ts +++ b/src/tabs/vue/index.ts @@ -1,4 +1,4 @@ -import { Tabs } from '../tabs'; +import { TabContentItem, TabStrip, TabStripItem, Tabs } from '../tabs'; let installed = false; @@ -9,10 +9,13 @@ export default { Vue.registerElement('MDTabs', () => Tabs, { model: { prop: 'selectedIndex', - event: 'selectedIndexChange', + event: 'selectedIndexChange' }, - component: require('./tabsComponent').default, + component: require('./component').default }); + Vue.registerElement('MDTabContentItem', () => TabContentItem, {}); + Vue.registerElement('MDTabStripItem', () => TabStripItem, {}); + Vue.registerElement('MDTabStrip', () => TabStrip, {}); } - }, + } };