diff --git a/packages/core/platforms/ios/Podfile b/packages/core/platforms/ios/Podfile deleted file mode 100644 index 7ba729baa..000000000 --- a/packages/core/platforms/ios/Podfile +++ /dev/null @@ -1,4 +0,0 @@ -platform :ios, '9.0' -use_frameworks! - -pod 'MaterialComponents/Tabs', '~> 94.5' \ No newline at end of file diff --git a/packages/core/ui/tabs/index.android.ts b/packages/core/ui/tabs/index.android.ts deleted file mode 100644 index a7842f033..000000000 --- a/packages/core/ui/tabs/index.android.ts +++ /dev/null @@ -1,1006 +0,0 @@ -// Types -import { TabContentItem } from '../tab-navigation-base/tab-content-item'; -import { TabStrip } from '../tab-navigation-base/tab-strip'; -import { TabStripItem } from '../tab-navigation-base/tab-strip-item'; -import { TextTransform } from '../text-base'; - -// Requires -import * as application from '../../application'; -import { ImageSource } from '../../image-source'; -import { ad, isFontIconURI, layout, RESOURCE_PREFIX } from '../../utils/utils'; -import { Color } from '../../color'; -import { Frame } from '../frame'; -import { Font } from '../styling/font'; -import { getIconSpecSize, itemsProperty, selectedIndexProperty, tabStripProperty } from '../tab-navigation-base/tab-navigation-base'; -import { getTransformedText } from '../text-base'; -import { offscreenTabLimitProperty, swipeEnabledProperty, animationEnabledProperty, TabsBase } from './tabs-common'; - -export * from './tabs-common'; - -const ACCENT_COLOR = 'colorAccent'; -const PRIMARY_COLOR = 'colorPrimary'; -const DEFAULT_ELEVATION = 4; - -const TABID = '_tabId'; -const INDEX = '_index'; - -interface PagerAdapter { - new (owner: Tabs): androidx.viewpager.widget.PagerAdapter; -} - -let PagerAdapter: PagerAdapter; -let TabsBar: any; -let appResources: android.content.res.Resources; - -function makeFragmentName(viewId: number, id: number): string { - return 'android:viewpager:' + viewId + ':' + id; -} - -function getTabById(id: number): Tabs { - const ref = tabs.find((ref) => { - const tab = ref.get(); - - return tab && tab._domId === id; - }); - - return ref && ref.get(); -} - -function initializeNativeClasses() { - if (PagerAdapter) { - return; - } - - @NativeClass - class TabFragmentImplementation extends org.nativescript.widgets.FragmentBase { - private owner: Tabs; - private index: number; - private backgroundBitmap: android.graphics.Bitmap = null; - - constructor() { - super(); - - return global.__native(this); - } - - static newInstance(tabId: number, index: number): TabFragmentImplementation { - const args = new android.os.Bundle(); - args.putInt(TABID, tabId); - args.putInt(INDEX, index); - const fragment = new TabFragmentImplementation(); - fragment.setArguments(args); - - return fragment; - } - - public onCreate(savedInstanceState: android.os.Bundle): void { - super.onCreate(savedInstanceState); - const args = this.getArguments(); - this.owner = getTabById(args.getInt(TABID)); - this.index = args.getInt(INDEX); - if (!this.owner) { - throw new Error(`Cannot find TabView`); - } - } - - public onCreateView(inflater: android.view.LayoutInflater, container: android.view.ViewGroup, savedInstanceState: android.os.Bundle): android.view.View { - const tabItem = this.owner.items[this.index]; - - return tabItem.nativeViewProtected; - } - - public onDestroyView() { - const hasRemovingParent = this.getRemovingParentFragment(); - - // Get view as bitmap and set it as background. This is workaround for the disapearing nested fragments. - // TODO: Consider removing it when update to androidx.fragment:1.2.0 - if (hasRemovingParent && this.owner.selectedIndex === this.index) { - const bitmapDrawable = new android.graphics.drawable.BitmapDrawable(appResources, this.backgroundBitmap); - this.owner._originalBackground = this.owner.backgroundColor || new Color('White'); - this.owner.nativeViewProtected.setBackgroundDrawable(bitmapDrawable); - this.backgroundBitmap = null; - } - - super.onDestroyView(); - } - - public onPause(): void { - const hasRemovingParent = this.getRemovingParentFragment(); - - // Get view as bitmap and set it as background. This is workaround for the disapearing nested fragments. - // TODO: Consider removing it when update to androidx.fragment:1.2.0 - if (hasRemovingParent && this.owner.selectedIndex === this.index) { - this.backgroundBitmap = this.loadBitmapFromView(this.owner.nativeViewProtected); - } - - super.onPause(); - } - - private loadBitmapFromView(view: android.view.View): android.graphics.Bitmap { - // Another way to get view bitmap. Test performance vs setDrawingCacheEnabled - // const width = view.getWidth(); - // const height = view.getHeight(); - // const bitmap = android.graphics.Bitmap.createBitmap(width, height, android.graphics.Bitmap.Config.ARGB_8888); - // const canvas = new android.graphics.Canvas(bitmap); - // view.layout(0, 0, width, height); - // view.draw(canvas); - - view.setDrawingCacheEnabled(true); - const bitmap = android.graphics.Bitmap.createBitmap(view.getDrawingCache()); - view.setDrawingCacheEnabled(false); - - return bitmap; - } - } - - const POSITION_UNCHANGED = -1; - const POSITION_NONE = -2; - - @NativeClass - class FragmentPagerAdapter extends androidx.viewpager.widget.PagerAdapter { - public items: Array; - private mCurTransaction: androidx.fragment.app.FragmentTransaction; - private mCurrentPrimaryItem: androidx.fragment.app.Fragment; - - constructor(public owner: Tabs) { - super(); - - return global.__native(this); - } - - getCount() { - const items = this.items; - - return items ? items.length : 0; - } - - getPageTitle(index: number) { - const items = this.items; - if (index < 0 || index >= items.length) { - return ''; - } - - return ''; // items[index].title; - } - - startUpdate(container: android.view.ViewGroup): void { - if (container.getId() === android.view.View.NO_ID) { - throw new Error(`ViewPager with adapter ${this} requires a view containerId`); - } - } - - instantiateItem(container: android.view.ViewGroup, position: number): java.lang.Object { - const fragmentManager = this.owner._getFragmentManager(); - if (!this.mCurTransaction) { - this.mCurTransaction = fragmentManager.beginTransaction(); - } - - const itemId = this.getItemId(position); - const name = makeFragmentName(container.getId(), itemId); - - let fragment: androidx.fragment.app.Fragment = fragmentManager.findFragmentByTag(name); - if (fragment != null) { - this.mCurTransaction.attach(fragment); - } else { - fragment = TabFragmentImplementation.newInstance(this.owner._domId, position); - this.mCurTransaction.add(container.getId(), fragment, name); - } - - if (fragment !== this.mCurrentPrimaryItem) { - fragment.setMenuVisibility(false); - fragment.setUserVisibleHint(false); - } - - const tabItems = this.owner.items; - const tabItem = tabItems ? tabItems[position] : null; - if (tabItem) { - tabItem.canBeLoaded = true; - } - - return fragment; - } - - getItemPosition(object: java.lang.Object): number { - return this.items ? POSITION_UNCHANGED : POSITION_NONE; - } - - destroyItem(container: android.view.ViewGroup, position: number, object: java.lang.Object): void { - if (!this.mCurTransaction) { - const fragmentManager = this.owner._getFragmentManager(); - this.mCurTransaction = fragmentManager.beginTransaction(); - } - - const fragment: androidx.fragment.app.Fragment = object; - this.mCurTransaction.detach(fragment); - - if (this.mCurrentPrimaryItem === fragment) { - this.mCurrentPrimaryItem = null; - } - - const tabItems = this.owner.items; - const tabItem = tabItems ? tabItems[position] : null; - if (tabItem) { - tabItem.canBeLoaded = false; - } - } - - setPrimaryItem(container: android.view.ViewGroup, position: number, object: java.lang.Object): void { - const fragment = object; - if (fragment !== this.mCurrentPrimaryItem) { - if (this.mCurrentPrimaryItem != null) { - this.mCurrentPrimaryItem.setMenuVisibility(false); - this.mCurrentPrimaryItem.setUserVisibleHint(false); - } - - if (fragment != null) { - fragment.setMenuVisibility(true); - fragment.setUserVisibleHint(true); - } - - this.mCurrentPrimaryItem = fragment; - this.owner.selectedIndex = position; - - const tab = this.owner; - const tabItems = tab.items; - const newTabItem = tabItems ? tabItems[position] : null; - - if (newTabItem) { - tab._loadUnloadTabItems(tab.selectedIndex); - } - } - } - - finishUpdate(container: android.view.ViewGroup): void { - this._commitCurrentTransaction(); - } - - isViewFromObject(view: android.view.View, object: java.lang.Object): boolean { - return (object).getView() === view; - } - - saveState(): android.os.Parcelable { - // Commit the current transaction on save to prevent "No view found for id 0xa" exception on restore. - // Related to: https://github.com/NativeScript/NativeScript/issues/6466 - this._commitCurrentTransaction(); - - return null; - } - - restoreState(state: android.os.Parcelable, loader: java.lang.ClassLoader): void { - // - } - - getItemId(position: number): number { - return position; - } - - private _commitCurrentTransaction() { - if (this.mCurTransaction != null) { - this.mCurTransaction.commitNowAllowingStateLoss(); - this.mCurTransaction = null; - } - } - } - - @NativeClass - class TabsBarImplementation extends org.nativescript.widgets.TabsBar { - constructor(context: android.content.Context, public owner: Tabs) { - super(context); - - return global.__native(this); - } - - public onSelectedPositionChange(position: number, prevPosition: number): void { - const owner = this.owner; - if (!owner) { - return; - } - - const tabStripItems = owner.tabStrip && owner.tabStrip.items; - - if (position >= 0 && tabStripItems && tabStripItems[position]) { - tabStripItems[position]._emit(TabStripItem.selectEvent); - owner._setItemColor(tabStripItems[position]); - } - - if (prevPosition >= 0 && tabStripItems && tabStripItems[prevPosition]) { - tabStripItems[prevPosition]._emit(TabStripItem.unselectEvent); - owner._setItemColor(tabStripItems[prevPosition]); - } - } - - public onTap(position: number): boolean { - const owner = this.owner; - if (!owner) { - return false; - } - - const tabStrip = owner.tabStrip; - const tabStripItems = tabStrip && tabStrip.items; - - if (position >= 0 && tabStripItems[position]) { - tabStripItems[position]._emit(TabStripItem.tapEvent); - tabStrip.notify({ - eventName: TabStrip.itemTapEvent, - object: tabStrip, - index: position, - }); - } - - if (!owner.items[position]) { - return false; - } - - return true; - } - } - - PagerAdapter = FragmentPagerAdapter; - TabsBar = TabsBarImplementation; - appResources = application.android.context.getResources(); -} - -let defaultAccentColor: number = undefined; -function getDefaultAccentColor(context: android.content.Context): number { - if (defaultAccentColor === undefined) { - //Fallback color: https://developer.android.com/samples/SlidingTabsColors/src/com.example.android.common/view/SlidingTabStrip.html - defaultAccentColor = ad.resources.getPaletteColor(ACCENT_COLOR, context) || 0xff33b5e5; - } - - return defaultAccentColor; -} - -function setElevation(grid: org.nativescript.widgets.GridLayout, tabsBar: org.nativescript.widgets.TabsBar, tabsPosition: string) { - const compat = androidx.core.view.ViewCompat; - if (compat.setElevation) { - const val = DEFAULT_ELEVATION * layout.getDisplayDensity(); - - if (tabsPosition === 'top') { - compat.setElevation(grid, val); - } - - compat.setElevation(tabsBar, val); - } -} - -export const tabs = new Array>(); - -function iterateIndexRange(index: number, eps: number, lastIndex: number, callback: (i) => void) { - const rangeStart = Math.max(0, index - eps); - const rangeEnd = Math.min(index + eps, lastIndex); - for (let i = rangeStart; i <= rangeEnd; i++) { - callback(i); - } -} - -export class Tabs extends TabsBase { - private _tabsBar: org.nativescript.widgets.TabsBar; - private _viewPager: androidx.viewpager.widget.ViewPager; - private _pagerAdapter: androidx.viewpager.widget.PagerAdapter; - private _androidViewId: number = -1; - public _originalBackground: any; - private _textTransform: TextTransform = 'uppercase'; - private _selectedItemColor: Color; - private _unSelectedItemColor: Color; - public animationEnabled: boolean; - - constructor() { - super(); - tabs.push(new WeakRef(this)); - } - - get _hasFragments(): boolean { - return true; - } - - public onItemsChanged(oldItems: TabContentItem[], newItems: TabContentItem[]): void { - super.onItemsChanged(oldItems, newItems); - - if (oldItems) { - oldItems.forEach((item: TabContentItem, i, arr) => { - (item).index = 0; - (item).tabItemSpec = null; - item.setNativeView(null); - }); - } - } - - public createNativeView() { - initializeNativeClasses(); - // TODO - // if (Trace.isEnabled()) { - // Trace.write("TabView._createUI(" + this + ");", traceCategory); - // } - - const context: android.content.Context = this._context; - const nativeView = new org.nativescript.widgets.GridLayout(context); - const viewPager = new org.nativescript.widgets.TabViewPager(context); - const tabsBar = new TabsBar(context, this); - const lp = new org.nativescript.widgets.CommonLayoutParams(); - const primaryColor = ad.resources.getPaletteColor(PRIMARY_COLOR, context); - let accentColor = getDefaultAccentColor(context); - - lp.row = 1; - - if (this.tabsPosition === 'top') { - nativeView.addRow(new org.nativescript.widgets.ItemSpec(1, org.nativescript.widgets.GridUnitType.auto)); - nativeView.addRow(new org.nativescript.widgets.ItemSpec(1, org.nativescript.widgets.GridUnitType.star)); - - viewPager.setLayoutParams(lp); - } else { - nativeView.addRow(new org.nativescript.widgets.ItemSpec(1, org.nativescript.widgets.GridUnitType.star)); - nativeView.addRow(new org.nativescript.widgets.ItemSpec(1, org.nativescript.widgets.GridUnitType.auto)); - - tabsBar.setLayoutParams(lp); - } - - nativeView.addView(viewPager); - (nativeView).viewPager = viewPager; - - const adapter = new PagerAdapter(this); - viewPager.setAdapter(adapter); - (viewPager).adapter = adapter; - - nativeView.addView(tabsBar); - (nativeView).tabsBar = tabsBar; - - setElevation(nativeView, tabsBar, this.tabsPosition); - - if (accentColor) { - tabsBar.setSelectedIndicatorColors([accentColor]); - } - - if (primaryColor) { - tabsBar.setBackgroundColor(primaryColor); - } - - return nativeView; - } - - public initNativeView(): void { - super.initNativeView(); - if (this._androidViewId < 0) { - this._androidViewId = android.view.View.generateViewId(); - } - - const nativeView: any = this.nativeViewProtected; - this._tabsBar = (nativeView).tabsBar; - - const viewPager = (nativeView).viewPager; - viewPager.setId(this._androidViewId); - this._viewPager = viewPager; - this._pagerAdapter = (viewPager).adapter; - (this._pagerAdapter).owner = this; - } - - public _loadUnloadTabItems(newIndex: number) { - const items = this.items; - if (!items) { - return; - } - - const lastIndex = items.length - 1; - const offsideItems = this.offscreenTabLimit; - - let toUnload = []; - let toLoad = []; - - 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); - } - }); - - const newItem = items[newIndex]; - const selectedView = newItem && newItem.content; - if (selectedView instanceof Frame) { - (selectedView)._pushInFrameStackRecursive(); - } - - toLoad.forEach((index) => { - const item = items[index]; - if (this.isLoaded && items[index]) { - item.loadView(item.content); - } - }); - } - - public onLoaded(): void { - super.onLoaded(); - - if (this._originalBackground) { - this.backgroundColor = null; - this.backgroundColor = this._originalBackground; - this._originalBackground = null; - } - - this.setItems(this.items); - - if (this.tabStrip) { - this.setTabStripItems(this.tabStrip.items); - } - - // this.setAdapterItems(this.items); - } - - public onUnloaded(): void { - super.onUnloaded(); - - this.setItems(null); - this.setTabStripItems(null); - - // this.setAdapterItems(null); - } - - public disposeNativeView() { - this._tabsBar.setItems(null, null); - (this._pagerAdapter).owner = null; - this._pagerAdapter = null; - - this._tabsBar = null; - this._viewPager = null; - super.disposeNativeView(); - } - - public _onRootViewReset(): void { - super._onRootViewReset(); - - // call this AFTER the super call to ensure descendants apply their rootview-reset logic first - // i.e. in a scenario with tab frames let the frames cleanup their fragments first, and then - // cleanup the tab fragments to avoid - // android.content.res.Resources$NotFoundException: Unable to find resource ID #0xfffffff6 - this.disposeCurrentFragments(); - } - - private disposeCurrentFragments(): void { - const fragmentManager = this._getFragmentManager(); - const transaction = fragmentManager.beginTransaction(); - let fragments = >fragmentManager.getFragments().toArray(); - for (let i=0;i) { - if (!this._pagerAdapter) { - return false; - } - - const currentPagerAdapterItems = (this._pagerAdapter).items; - - // if both values are null, should not update - if (!items && !currentPagerAdapterItems) { - return false; - } - - // if one value is null, should update - if (!items || !currentPagerAdapterItems) { - return true; - } - - // if both are Arrays but length doesn't match, should update - if (items.length !== currentPagerAdapterItems.length) { - return true; - } - - const matchingItems = currentPagerAdapterItems.filter((currentItem) => { - return !!items.filter((item) => { - return item._domId === currentItem._domId; - })[0]; - }); - - // if both are Arrays and length matches, but not all items are the same, should update - if (matchingItems.length !== items.length) { - return true; - } - - // if both are Arrays and length matches and all items are the same, should not update - return false; - } - - private setItems(items: Array) { - if (this.shouldUpdateAdapter(items)) { - (this._pagerAdapter).items = items; - - if (items && items.length) { - items.forEach((item: TabContentItem, i) => { - (item).index = i; - }); - } - - this._pagerAdapter.notifyDataSetChanged(); - } - } - - private setTabStripItems(items: Array) { - const length = items ? items.length : 0; - if (length === 0) { - this._tabsBar.setItems(null, null); - - return; - } - - const tabItems = new Array(); - items.forEach((tabStripItem: TabStripItem, i, arr) => { - tabStripItem._index = i; - const tabItemSpec = this.createTabItemSpec(tabStripItem); - (tabStripItem).tabItemSpec = tabItemSpec; - tabItems.push(tabItemSpec); - }); - - const tabsBar = this._tabsBar; - tabsBar.setItems(tabItems, this._viewPager); - this.tabStrip.setNativeView(tabsBar); - items.forEach((item, i, arr) => { - const tv = tabsBar.getTextViewForItemAt(i); - item.setNativeView(tv); - this._setItemColor(item); - }); - } - - private getItemLabelTextTransform(tabStripItem: TabStripItem): TextTransform { - const nestedLabel = tabStripItem.label; - let textTransform: TextTransform = null; - if (nestedLabel && nestedLabel.style.textTransform !== 'initial') { - textTransform = nestedLabel.style.textTransform; - } else if (tabStripItem.style.textTransform !== 'initial') { - textTransform = tabStripItem.style.textTransform; - } - - return textTransform || this._textTransform; - } - - private createTabItemSpec(tabStripItem: TabStripItem): org.nativescript.widgets.TabItemSpec { - const tabItemSpec = new org.nativescript.widgets.TabItemSpec(); - - if (tabStripItem.isLoaded) { - const nestedLabel = tabStripItem.label; - let title = nestedLabel.text; - - // TEXT-TRANSFORM - const textTransform = this.getItemLabelTextTransform(tabStripItem); - title = getTransformedText(title, textTransform); - tabItemSpec.title = title; - - // BACKGROUND-COLOR - const backgroundColor = tabStripItem.style.backgroundColor; - tabItemSpec.backgroundColor = backgroundColor ? backgroundColor.android : this.getTabBarBackgroundArgbColor(); - - // COLOR - let itemColor = this.selectedIndex === tabStripItem._index ? this._selectedItemColor : this._unSelectedItemColor; - const color = itemColor || nestedLabel.style.color; - tabItemSpec.color = color && color.android; - - // FONT - const fontInternal = nestedLabel.style.fontInternal; - if (fontInternal) { - tabItemSpec.fontSize = fontInternal.fontSize; - tabItemSpec.typeFace = fontInternal.getAndroidTypeface(); - } - - // ICON - const iconSource = tabStripItem.image && tabStripItem.image.src; - if (iconSource) { - const icon = this.getIcon(tabStripItem, itemColor); - - if (icon) { - // TODO: Make this native call that accepts string so that we don't load Bitmap in JS. - // tslint:disable-next-line:deprecation - tabItemSpec.iconDrawable = icon; - } else { - // TODO: - // traceMissingIcon(iconSource); - } - } - } - - return tabItemSpec; - } - - private getIcon(tabStripItem: TabStripItem, color?: Color): android.graphics.drawable.BitmapDrawable { - const iconSource = tabStripItem.image && tabStripItem.image.src; - if (!iconSource) { - return null; - } - - let is: ImageSource; - if (isFontIconURI(iconSource)) { - const fontIconCode = iconSource.split('//')[1]; - const target = tabStripItem.image ? tabStripItem.image : tabStripItem; - const font = target.style.fontInternal; - if (!color) { - color = target.style.color; - } - is = ImageSource.fromFontIconCodeSync(fontIconCode, font, color); - } else { - is = ImageSource.fromFileOrResourceSync(iconSource); - } - - let imageDrawable: android.graphics.drawable.BitmapDrawable; - if (is && is.android) { - let image = is.android; - - if (this.tabStrip && this.tabStrip.isIconSizeFixed) { - image = this.getFixedSizeIcon(image); - } - - imageDrawable = new android.graphics.drawable.BitmapDrawable(appResources, image); - } else { - // TODO - // traceMissingIcon(iconSource); - } - - return imageDrawable; - } - - private getFixedSizeIcon(image: android.graphics.Bitmap): android.graphics.Bitmap { - const inWidth = image.getWidth(); - const inHeight = image.getHeight(); - - const iconSpecSize = getIconSpecSize({ width: inWidth, height: inHeight }); - - const widthPixels = iconSpecSize.width * layout.getDisplayDensity(); - const heightPixels = iconSpecSize.height * layout.getDisplayDensity(); - - const scaledImage = android.graphics.Bitmap.createScaledBitmap(image, widthPixels, heightPixels, true); - - return scaledImage; - } - - // private setAdapterItems(items: Array) { - // if (this.shouldUpdateAdapter(items)) { - // (this._pagerAdapter).items = items; - - // const length = items ? items.length : 0; - // if (length === 0) { - // this._tabLayout.setItems(null, null); - // this._pagerAdapter.notifyDataSetChanged(); - // return; - // } - - // const tabItems = new Array(); - // items.forEach((item: TabStripItem, i, arr) => { - // const tabItemSpec = createTabItemSpec(item); - // (item).index = i; - // (item).tabItemSpec = tabItemSpec; - // tabItems.push(tabItemSpec); - // }); - - // const tabLayout = this._tabLayout; - // tabLayout.setItems(tabItems, this._viewPager); - // items.forEach((item, i, arr) => { - // const tv = tabLayout.getTextViewForItemAt(i); - // item.setNativeView(tv); - // }); - - // this._pagerAdapter.notifyDataSetChanged(); - // } - // } - - public updateAndroidItemAt(index: number, spec: org.nativescript.widgets.TabItemSpec) { - this._tabsBar.updateItemAt(index, spec); - } - - public getTabBarBackgroundColor(): android.graphics.drawable.Drawable { - return this._tabsBar.getBackground(); - } - - public setTabBarBackgroundColor(value: android.graphics.drawable.Drawable | Color): void { - if (value instanceof Color) { - this._tabsBar.setBackgroundColor(value.android); - } else { - this._tabsBar.setBackground(tryCloneDrawable(value, this.nativeViewProtected.getResources())); - } - - this.updateTabStripItems(); - } - - private updateTabStripItems(): void { - this.tabStrip.items.forEach((tabStripItem: TabStripItem) => { - if (tabStripItem.nativeView) { - const tabItemSpec = this.createTabItemSpec(tabStripItem); - this.updateAndroidItemAt(tabStripItem._index, tabItemSpec); - } - }); - } - - public getTabBarHighlightColor(): number { - return getDefaultAccentColor(this._context); - } - - public setTabBarHighlightColor(value: number | Color) { - const color = value instanceof Color ? value.android : value; - this._tabsBar.setSelectedIndicatorColors([color]); - } - - private setItemsColors(items: Array): void { - items.forEach((item) => { - if (item.nativeView) { - this._setItemColor(item); - } - }); - } - - public getTabBarSelectedItemColor(): Color { - return this._selectedItemColor; - } - - public setTabBarSelectedItemColor(value: Color) { - this._selectedItemColor = value; - this.setItemsColors(this.tabStrip.items); - } - - public getTabBarUnSelectedItemColor(): Color { - return this._unSelectedItemColor; - } - - public setTabBarUnSelectedItemColor(value: Color) { - this._unSelectedItemColor = value; - this.setItemsColors(this.tabStrip.items); - } - - private updateItem(tabStripItem: TabStripItem): void { - // TODO: Should figure out a way to do it directly with the the nativeView - const tabStripItemIndex = this.tabStrip.items.indexOf(tabStripItem); - const tabItemSpec = this.createTabItemSpec(tabStripItem); - this.updateAndroidItemAt(tabStripItemIndex, tabItemSpec); - } - - public setTabBarItemTitle(tabStripItem: TabStripItem, value: string): void { - this.updateItem(tabStripItem); - } - - public setTabBarItemBackgroundColor(tabStripItem: TabStripItem, value: android.graphics.drawable.Drawable | Color): void { - this.updateItem(tabStripItem); - } - - public _setItemColor(tabStripItem: TabStripItem) { - const itemColor = tabStripItem._index === this.selectedIndex ? this._selectedItemColor : this._unSelectedItemColor; - if (!itemColor) { - return; - } - - // set label color - tabStripItem.nativeViewProtected.setTextColor(itemColor.android); - - // set icon color - this.setIconColor(tabStripItem, itemColor); - } - - private setIconColor(tabStripItem: TabStripItem, color?: Color) { - const tabBarItem = this._tabsBar.getViewForItemAt(tabStripItem._index); - - const drawable = this.getIcon(tabStripItem, color); - const imgView = tabBarItem.getChildAt(0); - imgView.setImageDrawable(drawable); - if (color) { - imgView.setColorFilter(color.android); - } - } - - public setTabBarItemColor(tabStripItem: TabStripItem, value: number | Color): void { - const itemColor = tabStripItem._index === this.selectedIndex ? this._selectedItemColor : this._unSelectedItemColor; - if (itemColor) { - // the itemColor is set through the selectedItemColor and unSelectedItemColor properties - // so it does not respect the css color - return; - } - - const androidColor = value instanceof Color ? value.android : value; - tabStripItem.nativeViewProtected.setTextColor(androidColor); - } - - public setTabBarIconColor(tabStripItem: TabStripItem, value: number | Color): void { - const itemColor = tabStripItem._index === this.selectedIndex ? this._selectedItemColor : this._unSelectedItemColor; - if (itemColor) { - // the itemColor is set through the selectedItemColor and unSelectedItemColor properties - // so it does not respect the css color - return; - } - - this.setIconColor(tabStripItem); - } - - public setTabBarIconSource(tabStripItem: TabStripItem, value: number | Color): void { - this.updateItem(tabStripItem); - } - - public setTabBarItemFontInternal(tabStripItem: TabStripItem, value: Font): void { - if (value.fontSize) { - tabStripItem.nativeViewProtected.setTextSize(value.fontSize); - } - tabStripItem.nativeViewProtected.setTypeface(value.getAndroidTypeface()); - } - - public getTabBarItemTextTransform(tabStripItem: TabStripItem): TextTransform { - return this.getItemLabelTextTransform(tabStripItem); - } - - public setTabBarItemTextTransform(tabStripItem: TabStripItem, value: TextTransform): void { - const nestedLabel = tabStripItem.label; - const title = getTransformedText(nestedLabel.text, value); - tabStripItem.nativeViewProtected.setText(title); - } - - public getTabBarTextTransform(): TextTransform { - return this._textTransform; - } - - public setTabBarTextTransform(value: TextTransform): void { - let items = this.tabStrip && this.tabStrip.items; - if (items) { - items.forEach((tabStripItem) => { - if (tabStripItem.label && tabStripItem.nativeViewProtected) { - const nestedLabel = tabStripItem.label; - const title = getTransformedText(nestedLabel.text, value); - tabStripItem.nativeViewProtected.setText(title); - } - }); - } - this._textTransform = value; - } - - [selectedIndexProperty.setNative](value: number) { - // TODO - // if (Trace.isEnabled()) { - // Trace.write("TabView this._viewPager.setCurrentItem(" + value + ", " + smoothScroll + ");", traceCategory); - // } - this._viewPager.setCurrentItem(value, this.animationEnabled); - } - - [itemsProperty.getDefault](): TabContentItem[] { - return null; - } - [itemsProperty.setNative](value: TabContentItem[]) { - this.setItems(value); - selectedIndexProperty.coerce(this); - } - - [tabStripProperty.getDefault](): TabStrip { - return null; - } - [tabStripProperty.setNative](value: TabStrip) { - this.setTabStripItems(value.items); - } - - [swipeEnabledProperty.getDefault](): boolean { - // TODO: create native method and get native? - return true; - } - [swipeEnabledProperty.setNative](value: boolean) { - (this._viewPager).setSwipePageEnabled(value); - } - - [offscreenTabLimitProperty.getDefault](): number { - return this._viewPager.getOffscreenPageLimit(); - } - [offscreenTabLimitProperty.setNative](value: number) { - this._viewPager.setOffscreenPageLimit(value); - } - - [animationEnabledProperty.setNative](value: number) { - (this._viewPager).setAnimationEnabled(value); - } -} - -function tryCloneDrawable(value: android.graphics.drawable.Drawable, resources: android.content.res.Resources): android.graphics.drawable.Drawable { - if (value) { - const constantState = value.getConstantState(); - if (constantState) { - return constantState.newDrawable(resources); - } - } - - return value; -} diff --git a/packages/core/ui/tabs/index.d.ts b/packages/core/ui/tabs/index.d.ts deleted file mode 100644 index e2f4a83e7..000000000 --- a/packages/core/ui/tabs/index.d.ts +++ /dev/null @@ -1,100 +0,0 @@ -/** - * Contains the Tabs class, which represents a tab navigation component. - */ - -import { Property } from '../core/properties'; -import { EventData } from '../../data/observable'; -import { TabContentItem } from '../tab-navigation-base/tab-content-item'; -import { SelectedIndexChangedEventData, TabNavigationBase } from '../tab-navigation-base/tab-navigation-base'; -import { TabStrip } from '../tab-navigation-base/tab-strip'; - -export * from '../tab-navigation-base/tab-content-item'; -export * from '../tab-navigation-base/tab-navigation-base'; -export * from '../tab-navigation-base/tab-strip'; -export * from '../tab-navigation-base/tab-strip-item'; - -/** - * Represents a swipeable tabs view. - */ -export class Tabs extends TabNavigationBase { - /** - * Gets or sets the items of the Tabs. - */ - items: Array; - - /** - * Gets or sets the tab strip of the Tabs. - */ - tabStrip: TabStrip; - - /** - * Gets or sets the selectedIndex of the Tabs. - */ - selectedIndex: number; - - /** - * Gets or sets the swipe enabled state of the Tabs. - */ - swipeEnabled: boolean; - - /** - * Gets or sets the number of offscreen preloaded tabs of the Tabs. - */ - offscreenTabLimit: number; - - /** - * Gets or sets the position state of the Tabs. - */ - tabsPosition: 'top' | 'bottom'; - - /** - * Gets or set the MDCTabBarAlignment of the tab bar icons in iOS. Defaults to "justified" - * Valid values are: - * - leading - * - justified - * - center - * - centerSelected - */ - iOSTabBarItemsAlignment: IOSTabBarItemsAlignment; - - /** - * Gets the native [android widget](http://developer.android.com/reference/android/support/v4/view/ViewPager.html) 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 [UITabBarController](https://developer.apple.com/library/ios/documentation/UIKit/Reference/UITabBarController_Class/) 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. - */ - 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. - */ - on(eventNames: string, callback: (data: EventData) => void, thisArg?: any); - - /** - * Raised when the selected index changes. - */ - on(event: 'selectedIndexChanged', callback: (args: SelectedIndexChangedEventData) => void, thisArg?: any); -} - -export const itemsProperty: Property; -export const tabStripProperty: Property; -export const selectedIndexProperty: Property; - -/** - * IOS Alignment of the Tabs TabStrip to use. - * - `leading` - tab items are aligned to the left - * - `justified` - tab strip is split equally to all the tab items - * - `center` - tabs items are aligned in the center - * - `centerSelected` - tab items move to make the selected tab in the center - */ -export type IOSTabBarItemsAlignment = 'leading' | 'justified' | 'center' | 'centerSelected'; diff --git a/packages/core/ui/tabs/index.ios.ts b/packages/core/ui/tabs/index.ios.ts deleted file mode 100644 index 9213b803b..000000000 --- a/packages/core/ui/tabs/index.ios.ts +++ /dev/null @@ -1,1236 +0,0 @@ -// Types -import { TabContentItem } from '../tab-navigation-base/tab-content-item'; -import { TabStrip } from '../tab-navigation-base/tab-strip'; -import { TabStripItem } from '../tab-navigation-base/tab-strip-item'; -import { TextTransform } from '../text-base'; - -// Requires -import { Color } from '../../color'; -import { ImageSource } from '../../image-source'; -import { Device } from '../../platform'; -import { iOSNativeHelper, isFontIconURI, layout } from '../../utils'; -import { IOSHelper, View } from '../core/view'; -import { ViewBase } from '../core/view-base'; -import { Frame } from '../frame'; -import { Font } from '../styling/font'; -import { getIconSpecSize, itemsProperty, selectedIndexProperty, tabStripProperty } from '../tab-navigation-base/tab-navigation-base'; -import { swipeEnabledProperty, TabsBase, IOSTabBarItemsAlignment, iOSTabBarItemsAlignmentProperty } from './tabs-common'; - -// TODO -// import { profile } from "../../profiling"; - -export * from './tabs-common'; - -const majorVersion = iOSNativeHelper.MajorVersion; -const isPhone = Device.deviceType === 'Phone'; - -// Equivalent to dispatch_async(dispatch_get_main_queue(...)) call -const invokeOnRunLoop = (function () { - const runloop = CFRunLoopGetMain(); - - return (action: () => any) => { - CFRunLoopPerformBlock(runloop, kCFRunLoopDefaultMode, action); - CFRunLoopWakeUp(runloop); - }; -})(); - -@NativeClass -class MDCTabBarDelegateImpl extends NSObject implements MDCTabBarDelegate { - public static ObjCProtocols = [MDCTabBarDelegate]; - - private _owner: WeakRef; - - public static initWithOwner(owner: WeakRef): MDCTabBarDelegateImpl { - let delegate = MDCTabBarDelegateImpl.new(); - delegate._owner = owner; - - return delegate; - } - - public tabBarShouldSelectItem(tabBar: MDCTabBar, item: UITabBarItem): boolean { - const owner = this._owner.get(); - const shouldSelectItem = owner._canSelectItem; - const selectedIndex = owner.tabBarItems.indexOf(item); - - if (owner.selectedIndex !== selectedIndex) { - owner._canSelectItem = false; - } - - const tabStrip = owner.tabStrip; - const tabStripItems = tabStrip && tabStrip.items; - - if (tabStripItems && tabStripItems[selectedIndex]) { - tabStripItems[selectedIndex]._emit(TabStripItem.tapEvent); - tabStrip.notify({ - eventName: TabStrip.itemTapEvent, - object: tabStrip, - index: selectedIndex, - }); - } - - return shouldSelectItem; - } - - public tabBarDidSelectItem(tabBar: MDCTabBar, selectedItem: UITabBarItem): void { - const owner = this._owner.get(); - const tabBarItems = owner.tabBarItems; - const selectedIndex = tabBarItems.indexOf(selectedItem); - - owner.selectedIndex = selectedIndex; - } -} - -@NativeClass -class BackgroundIndicatorTemplate extends NSObject implements MDCTabBarIndicatorTemplate { - public static ObjCProtocols = [MDCTabBarIndicatorTemplate]; - - public indicatorAttributesForContext(context: MDCTabBarIndicatorContext): MDCTabBarIndicatorAttributes { - let attributes = new MDCTabBarIndicatorAttributes(); - attributes.path = UIBezierPath.bezierPathWithRect(context.bounds); - - return attributes; - } -} - -@NativeClass -class UIPageViewControllerImpl extends UIPageViewController { - tabBar: MDCTabBar; - scrollView: UIScrollView; - tabBarDelegate: MDCTabBarDelegateImpl; - - private _owner: WeakRef; - - public static initWithOwner(owner: WeakRef): UIPageViewControllerImpl { - const handler = UIPageViewControllerImpl.alloc().initWithTransitionStyleNavigationOrientationOptions(UIPageViewControllerTransitionStyle.Scroll, UIPageViewControllerNavigationOrientation.Horizontal, null); - handler._owner = owner; - - return handler; - } - - public viewDidLoad(): void { - const owner = this._owner.get(); - - const tabBarItems = owner.tabBarItems; - const tabBar = MDCTabBar.alloc().initWithFrame(this.view.bounds); - - if (tabBarItems && tabBarItems.length) { - tabBar.items = NSArray.arrayWithArray(tabBarItems); - } - - tabBar.delegate = this.tabBarDelegate = MDCTabBarDelegateImpl.initWithOwner(new WeakRef(owner)); - - if (majorVersion <= 12 || !UIColor.labelColor) { - tabBar.tintColor = UIColor.blueColor; - tabBar.barTintColor = UIColor.whiteColor; - tabBar.setTitleColorForState(UIColor.blackColor, MDCTabBarItemState.Normal); - tabBar.setTitleColorForState(UIColor.blackColor, MDCTabBarItemState.Selected); - } else { - tabBar.tintColor = UIColor.systemBlueColor; - tabBar.barTintColor = UIColor.systemBackgroundColor; - tabBar.setTitleColorForState(UIColor.labelColor, MDCTabBarItemState.Normal); - tabBar.setTitleColorForState(UIColor.labelColor, MDCTabBarItemState.Selected); - tabBar.inkColor = UIColor.clearColor; - } - - tabBar.autoresizingMask = UIViewAutoresizing.FlexibleWidth | UIViewAutoresizing.FlexibleBottomMargin; - tabBar.alignment = MDCTabBarAlignment.Justified; - tabBar.sizeToFit(); - - this.tabBar = tabBar; - this.view.addSubview(tabBar); - } - - public viewWillAppear(animated: boolean): void { - super.viewWillAppear(animated); - const owner = this._owner.get(); - if (!owner) { - return; - } - - IOSHelper.updateAutoAdjustScrollInsets(this, owner); - - // Tabs can be reset as a root view. Call loaded here in this scenario. - if (!owner.isLoaded) { - owner.callLoaded(); - } - } - - public viewDidLayoutSubviews(): void { - super.viewDidLayoutSubviews(); - const owner = this._owner.get(); - if (!owner) { - return; - } - - let safeAreaInsetsBottom = 0; - let safeAreaInsetsTop = 0; - - if (majorVersion > 10) { - safeAreaInsetsBottom = this.view.safeAreaInsets.bottom; - safeAreaInsetsTop = this.view.safeAreaInsets.top; - } else { - safeAreaInsetsTop = this.topLayoutGuide.length; - } - - let scrollViewTop = 0; - let scrollViewHeight = this.view.bounds.size.height + safeAreaInsetsBottom; - - if (owner.tabStrip) { - scrollViewTop = this.tabBar.frame.size.height; - scrollViewHeight = this.view.bounds.size.height - this.tabBar.frame.size.height + safeAreaInsetsBottom; - let tabBarTop = safeAreaInsetsTop; - let tabBarHeight = this.tabBar.frame.size.height; - - const tabsPosition = owner.tabsPosition; - if (tabsPosition === 'bottom') { - tabBarTop = this.view.frame.size.height - this.tabBar.frame.size.height - safeAreaInsetsBottom; - scrollViewTop = this.view.frame.origin.y; - scrollViewHeight = this.view.frame.size.height - safeAreaInsetsBottom; - } - - let parent = owner.parent; - - // Handle Angular scenario where Tabs is in a ProxyViewContainer - // It is possible to wrap components in ProxyViewContainers indefinitely - while (parent && !parent.nativeViewProtected) { - parent = parent.parent; - } - - if (parent && majorVersion > 10) { - // TODO: Figure out a better way to handle ViewController nesting/Safe Area nesting - tabBarTop = Math.max(tabBarTop, parent.nativeView.safeAreaInsets.top); - } - - this.tabBar.frame = CGRectMake(0, tabBarTop, this.tabBar.frame.size.width, tabBarHeight); - } else { - this.tabBar.hidden = true; - } - - const subViews: NSArray = this.view.subviews; - let scrollView: UIScrollView = null; - - for (let i = 0; i < subViews.count; i++) { - const view: UIView = subViews[i]; - if (view instanceof UIScrollView) { - scrollView = view; - } - } - - if (scrollView) { - // The part of the UIPageViewController that is changing the pages is a UIScrollView - // We want to expand it to the size of the UIPageViewController as it is not so by default - this.scrollView = scrollView; - - if (!owner.swipeEnabled) { - scrollView.scrollEnabled = false; - } - - scrollView.frame = CGRectMake(0, scrollViewTop, this.view.bounds.size.width, scrollViewHeight); //this.view.bounds; - } - } - - // Mind implementation for other controllers - public traitCollectionDidChange(previousTraitCollection: UITraitCollection): void { - super.traitCollectionDidChange(previousTraitCollection); - - if (majorVersion >= 13) { - const owner = this._owner.get(); - if (owner && this.traitCollection.hasDifferentColorAppearanceComparedToTraitCollection && this.traitCollection.hasDifferentColorAppearanceComparedToTraitCollection(previousTraitCollection)) { - owner.notify({ - eventName: IOSHelper.traitCollectionColorAppearanceChangedEvent, - object: owner, - }); - } - } - } - - public viewWillTransitionToSizeWithTransitionCoordinator(size: CGSize, coordinator: UIViewControllerTransitionCoordinator): void { - super.viewWillTransitionToSizeWithTransitionCoordinator(size, coordinator); - coordinator.animateAlongsideTransitionCompletion(() => { - const owner = this._owner.get(); - if (owner && owner.tabStrip && owner.tabStrip.items) { - const tabStrip = owner.tabStrip; - tabStrip.items.forEach((tabStripItem) => { - updateBackgroundPositions(tabStrip, tabStripItem, this.tabBar.alignment !== MDCTabBarAlignment.Justified || owner.selectedIndex !== tabStripItem._index ? owner._defaultItemBackgroundColor : null); - - const index = tabStripItem._index; - const tabBarItemController = owner.viewControllers[index]; - updateTitleAndIconPositions(tabStripItem, tabBarItemController.tabBarItem, tabBarItemController); - }); - } - }, null); - } -} - -@NativeClass -class UIPageViewControllerDataSourceImpl extends NSObject implements UIPageViewControllerDataSource { - public static ObjCProtocols = [UIPageViewControllerDataSource]; - - private _owner: WeakRef; - - public static initWithOwner(owner: WeakRef): UIPageViewControllerDataSourceImpl { - let dataSource = UIPageViewControllerDataSourceImpl.new(); - dataSource._owner = owner; - - return dataSource; - } - - public pageViewControllerViewControllerBeforeViewController(pageViewController: UIPageViewController, viewController: UIViewController): UIViewController { - // TODO - // if (Trace.isEnabled()) { - // Trace.write("TabView.delegate.SHOULD_select(" + tabBarController + ", " + viewController + ");", Trace.categories.Debug); - // } - - const owner = this._owner.get(); - let selectedIndex = owner.selectedIndex; - - if (selectedIndex === 0) { - return null; - } - - selectedIndex--; - const prevItem = owner.items[selectedIndex]; - let prevViewController = (prevItem).__controller; - - // if (!prevViewController) { - // prevViewController = owner.getViewController(prevItem); - // } - - owner._setCanBeLoaded(selectedIndex); - owner._loadUnloadTabItems(selectedIndex); - - return prevViewController; - } - - public pageViewControllerViewControllerAfterViewController(pageViewController: UIPageViewController, viewController: UIViewController): UIViewController { - // TODO - // if (Trace.isEnabled()) { - // Trace.write("TabView.delegate.SHOULD_select(" + tabBarController + ", " + viewController + ");", Trace.categories.Debug); - // } - - const owner = this._owner.get(); - let selectedIndex = owner.selectedIndex; - - if (selectedIndex === owner.items.length - 1) { - return null; - } - - selectedIndex++; - const nextItem = owner.items[selectedIndex]; - let nextViewController = (nextItem).__controller; - - // if (!nextViewController) { - // nextViewController = owner.getViewController(nextItem); - // } - - owner._setCanBeLoaded(selectedIndex); - owner._loadUnloadTabItems(selectedIndex); - // nextItem.loadView(nextItem.view); - - return nextViewController; - } - - public presentationCountForPageViewController(pageViewController: UIPageViewController): number { - // TODO - // if (Trace.isEnabled()) { - // Trace.write("TabView.delegate.SHOULD_select(" + tabBarController + ", " + viewController + ");", Trace.categories.Debug); - // } - - return 0; - } - - public presentationIndexForPageViewController(pageViewController: UIPageViewController): number { - // TODO - // if (Trace.isEnabled()) { - // Trace.write("TabView.delegate.SHOULD_select(" + tabBarController + ", " + viewController + ");", Trace.categories.Debug); - // } - - return 0; - } -} - -@NativeClass -class UIPageViewControllerDelegateImpl extends NSObject implements UIPageViewControllerDelegate { - public static ObjCProtocols = [UIPageViewControllerDelegate]; - - private _owner: WeakRef; - - public static initWithOwner(owner: WeakRef): UIPageViewControllerDelegateImpl { - let delegate = UIPageViewControllerDelegateImpl.new(); - delegate._owner = owner; - - return delegate; - } - - public pageViewControllerWillTransitionToViewControllers(pageViewController: UIPageViewController, viewControllers: NSArray): void { - // const owner = this._owner.get(); - // const ownerViewControllers = owner.viewControllers; - // const selectedIndex = owner.selectedIndex; - // const nextViewController = viewControllers[0]; - // const nextViewControllerIndex = ownerViewControllers.indexOf(nextViewController); - // if (selectedIndex > nextViewControllerIndex) { - // owner.selectedIndex--; - // } else { - // owner.selectedIndex++; - // } - } - - public pageViewControllerDidFinishAnimatingPreviousViewControllersTransitionCompleted(pageViewController: UIPageViewController, didFinishAnimating: boolean, previousViewControllers: NSArray, transitionCompleted: boolean): void { - if (!transitionCompleted) { - return; - } - - const owner = this._owner.get(); - const ownerViewControllers = owner.viewControllers; - const selectedIndex = owner.selectedIndex; - const nextViewController = pageViewController.viewControllers[0]; - const nextViewControllerIndex = ownerViewControllers.indexOf(nextViewController); - - if (selectedIndex !== nextViewControllerIndex) { - owner.selectedIndex = nextViewControllerIndex; - owner._canSelectItem = true; - } - } -} - -function iterateIndexRange(index: number, eps: number, lastIndex: number, callback: (i) => void) { - const rangeStart = Math.max(0, index - eps); - const rangeEnd = Math.min(index + eps, lastIndex); - for (let i = rangeStart; i <= rangeEnd; i++) { - callback(i); - } -} - -function updateBackgroundPositions(tabStrip: TabStrip, tabStripItem: TabStripItem, color: UIColor = null) { - let bgView = (tabStripItem).bgView; - const index = tabStripItem._index; - let width = tabStrip.nativeView.frame.size.width / tabStrip.items.length; - const frame = CGRectMake(width * index, 0, width, tabStrip.nativeView.frame.size.width); - if (!bgView) { - bgView = UIView.alloc().initWithFrame(frame); - tabStrip.nativeView.insertSubviewAtIndex(bgView, 0); - (tabStripItem).bgView = bgView; - } else { - bgView.frame = frame; - } - - const backgroundColor = tabStripItem.style.backgroundColor; - bgView.backgroundColor = color || (backgroundColor instanceof Color ? backgroundColor.ios : backgroundColor); -} - -function updateTitleAndIconPositions(tabStripItem: TabStripItem, tabBarItem: UITabBarItem, controller: UIViewController) { - if (!tabStripItem || !tabBarItem) { - return; - } - - // For iOS <11 icon is *always* above the text. - // For iOS 11 icon is above the text *only* on phones in portrait mode. - const orientation = controller.interfaceOrientation; - const isPortrait = orientation !== UIInterfaceOrientation.LandscapeLeft && orientation !== UIInterfaceOrientation.LandscapeRight; - const isIconAboveTitle = majorVersion < 11 || (isPhone && isPortrait); - - if (!tabStripItem.iconSource) { - if (isIconAboveTitle) { - tabBarItem.titlePositionAdjustment = { - horizontal: 0, - vertical: -20, - }; - } else { - tabBarItem.titlePositionAdjustment = { horizontal: 0, vertical: 0 }; - } - } - - if (!tabStripItem.title) { - if (isIconAboveTitle) { - tabBarItem.imageInsets = new UIEdgeInsets({ - top: 6, - left: 0, - bottom: -6, - right: 0, - }); - } else { - tabBarItem.imageInsets = new UIEdgeInsets({ - top: 0, - left: 0, - bottom: 0, - right: 0, - }); - } - } -} - -export class Tabs extends TabsBase { - public nativeViewProtected: UIView; - public selectedIndex: number; - // public swipeEnabled: boolean; - // public offscreenTabLimit: number; - // public tabsPosition: "top" | "bottom"; - public _canSelectItem: boolean; - public isLoaded: boolean; - public viewController: UIPageViewControllerImpl; - public items: TabContentItem[]; - public _ios: UIPageViewControllerImpl; - public viewControllers: UIViewController[]; - public tabBarItems: UITabBarItem[]; - private _currentNativeSelectedIndex: number; - private _dataSource: UIPageViewControllerDataSourceImpl; - private _delegate: UIPageViewControllerDelegateImpl; - // private _moreNavigationControllerDelegate: UINavigationControllerDelegateImpl; - private _iconsCache = {}; - private _backgroundIndicatorColor: UIColor; - public _defaultItemBackgroundColor: UIColor; - private _selectedItemColor: Color; - private _unSelectedItemColor: Color; - public animationEnabled: boolean; - - constructor() { - super(); - - this.viewController = this._ios = UIPageViewControllerImpl.initWithOwner(new WeakRef(this)); //alloc().initWithTransitionStyleNavigationOrientationOptions(UIPageViewControllerTransitionStyle.Scroll, UIPageViewControllerNavigationOrientation.Horizontal, null);; - } - - createNativeView() { - return this._ios.view; - } - - initNativeView() { - super.initNativeView(); - this._dataSource = UIPageViewControllerDataSourceImpl.initWithOwner(new WeakRef(this)); - this._delegate = UIPageViewControllerDelegateImpl.initWithOwner(new WeakRef(this)); - } - - disposeNativeView() { - this._dataSource = null; - this._delegate = null; - this._ios.tabBarDelegate = null; - this._ios.tabBar = null; - super.disposeNativeView(); - } - - // TODO - // @profile() - public onLoaded() { - super.onLoaded(); - - this.setViewControllers(this.items); - - const selectedIndex = this.selectedIndex; - const selectedView = this.items && this.items[selectedIndex] && this.items[selectedIndex].content; - if (selectedView instanceof Frame) { - selectedView._pushInFrameStackRecursive(); - } - - this._ios.dataSource = this._dataSource; - this._ios.delegate = this._delegate; - } - - public onUnloaded() { - this._ios.dataSource = null; - this._ios.delegate = null; - super.onUnloaded(); - } - - get ios(): UIPageViewController { - return this._ios; - } - - public layoutNativeView(left: number, top: number, right: number, bottom: number): void { - // - } - - public _setNativeViewFrame(nativeView: UIView, frame: CGRect) { - // - } - - public onSelectedIndexChanged(oldIndex: number, newIndex: number): void { - const items = this.items; - if (!items) { - return; - } - - const oldItem = items[oldIndex]; - if (oldItem) { - oldItem.canBeLoaded = false; - oldItem.unloadView(oldItem.content); - } - - const newItem = items[newIndex]; - if (newItem && this.isLoaded) { - const selectedView = items[newIndex].content; - if (selectedView instanceof Frame) { - selectedView._pushInFrameStackRecursive(); - } - - newItem.canBeLoaded = true; - newItem.loadView(newItem.content); - } - - const tabStripItems = this.tabStrip && this.tabStrip.items; - if (tabStripItems) { - if (tabStripItems[newIndex]) { - tabStripItems[newIndex]._emit(TabStripItem.selectEvent); - this.updateItemColors(tabStripItems[newIndex]); - } - - if (tabStripItems[oldIndex]) { - tabStripItems[oldIndex]._emit(TabStripItem.unselectEvent); - this.updateItemColors(tabStripItems[oldIndex]); - } - } - - this._loadUnloadTabItems(newIndex); - - super.onSelectedIndexChanged(oldIndex, newIndex); - } - - public _loadUnloadTabItems(newIndex: number) { - const items = this.items; - if (!items) { - return; - } - - const lastIndex = items.length - 1; - const offsideItems = this.offscreenTabLimit; - - let toUnload = []; - let toLoad = []; - - 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); - } - }); - - const newItem = items[newIndex]; - const selectedView = newItem && newItem.content; - if (selectedView instanceof Frame) { - selectedView._pushInFrameStackRecursive(); - } - - toLoad.forEach((index) => { - const item = items[index]; - if (this.isLoaded && items[index]) { - item.loadView(item.content); - } - }); - } - - public onMeasure(widthMeasureSpec: number, heightMeasureSpec: number): void { - const width = layout.getMeasureSpecSize(widthMeasureSpec); - const widthMode = layout.getMeasureSpecMode(widthMeasureSpec); - - const height = layout.getMeasureSpecSize(heightMeasureSpec); - const heightMode = layout.getMeasureSpecMode(heightMeasureSpec); - - const widthAndState = View.resolveSizeAndState(width, width, widthMode, 0); - const heightAndState = View.resolveSizeAndState(height, height, heightMode, 0); - - this.setMeasuredDimension(widthAndState, heightAndState); - } - - public _onViewControllerShown(viewController: UIViewController) { - // This method could be called with the moreNavigationController or its list controller, so we have to check. - // TODO - // if (Trace.isEnabled()) { - // Trace.write("TabView._onViewControllerShown(" + viewController + ");", Trace.categories.Debug); - // } - if (this._ios.viewControllers && this._ios.viewControllers.containsObject(viewController)) { - this.selectedIndex = this._ios.viewControllers.indexOfObject(viewController); - } else { - // TODO - // if (Trace.isEnabled()) { - // Trace.write("TabView._onViewControllerShown: viewController is not one of our viewControllers", Trace.categories.Debug); - // } - } - } - - private getViewController(item: TabContentItem): UIViewController { - let newController: UIViewController = item.content ? item.content.viewController : null; - - if (newController) { - (item).setViewController(newController, newController.view); - - return newController; - } - - if (item.content.ios instanceof UIViewController) { - newController = item.content.ios; - (item).setViewController(newController, newController.view); - } else if (item.content.ios && item.content.ios.controller instanceof UIViewController) { - newController = item.content.ios.controller; - (item).setViewController(newController, newController.view); - } else { - newController = IOSHelper.UILayoutViewController.initWithOwner(new WeakRef(item.content)) as UIViewController; - newController.view.addSubview(item.content.nativeViewProtected); - item.content.viewController = newController; - (item).setViewController(newController, item.content.nativeViewProtected); - } - - return newController; - } - - public _setCanBeLoaded(index: number) { - const items = this.items; - if (!this.items) { - return; - } - - const lastIndex = items.length - 1; - const offsideItems = this.offscreenTabLimit; - - iterateIndexRange(index, offsideItems, lastIndex, (i) => { - if (items[i]) { - (items[i]).canBeLoaded = true; - } - }); - } - - private setViewControllers(items: TabContentItem[]) { - const length = items ? items.length : 0; - if (length === 0) { - this.viewControllers = null; - - return; - } - - const viewControllers = []; - const tabBarItems = []; - - if (this.tabStrip) { - this.tabStrip.setNativeView(this._ios.tabBar); - } - - const tabStripItems = this.tabStrip && this.tabStrip.items; - if (tabStripItems) { - if (tabStripItems[this.selectedIndex]) { - tabStripItems[this.selectedIndex]._emit(TabStripItem.selectEvent); - } - } - - items.forEach((item, i) => { - const controller = this.getViewController(item); - - if (this.tabStrip && this.tabStrip.items && this.tabStrip.items[i]) { - const tabStripItem = this.tabStrip.items[i]; - const tabBarItem = this.createTabBarItem(tabStripItem, i); - updateTitleAndIconPositions(tabStripItem, tabBarItem, controller); - - this.setViewTextAttributes(tabStripItem.label, i === this.selectedIndex); - - controller.tabBarItem = tabBarItem; - tabStripItem._index = i; - tabBarItems.push(tabBarItem); - tabStripItem.setNativeView(tabBarItem); - } - - item.canBeLoaded = true; - viewControllers.push(controller); - }); - - this.setItemImages(); - - this.viewControllers = viewControllers; - this.tabBarItems = tabBarItems; - - if (this.viewController && this.viewController.tabBar) { - this.viewController.tabBar.itemAppearance = this.getTabBarItemAppearance(); - this.viewController.tabBar.items = NSArray.arrayWithArray(this.tabBarItems); - // TODO: investigate why this call is necessary to actually toggle item appearance - this.viewController.tabBar.sizeToFit(); - if (this.selectedIndex) { - this.viewController.tabBar.setSelectedItemAnimated(this.tabBarItems[this.selectedIndex], false); - } - } - } - - private setItemImages() { - if (this._selectedItemColor || this._unSelectedItemColor) { - if (this.tabStrip && this.tabStrip.items) { - this.tabStrip.items.forEach((item) => { - if (this._unSelectedItemColor && item.nativeView) { - item.nativeView.image = this.getIcon(item, this._unSelectedItemColor); - } - if (this._selectedItemColor && item.nativeView) { - if (this.selectedIndex === item._index) { - item.nativeView.image = this.getIcon(item, this._selectedItemColor); - } - } - }); - } - } - } - - private updateAllItemsColors() { - this._defaultItemBackgroundColor = null; - this.setItemColors(); - if (this.tabStrip && this.tabStrip.items) { - this.tabStrip.items.forEach((tabStripItem) => { - this.updateItemColors(tabStripItem); - }); - } - } - - private updateItemColors(tabStripItem: TabStripItem): void { - updateBackgroundPositions(this.tabStrip, tabStripItem); - this.setIconColor(tabStripItem, true); - } - - private createTabBarItem(item: TabStripItem, index: number): UITabBarItem { - let image: UIImage; - let title: string; - - if (item.isLoaded) { - image = this.getIcon(item); - title = item.label.text; - - if (!this.tabStrip._hasImage) { - this.tabStrip._hasImage = !!image; - } - - if (!this.tabStrip._hasTitle) { - this.tabStrip._hasTitle = !!title; - } - } - - const tabBarItem = UITabBarItem.alloc().initWithTitleImageTag(title, image, index); - - return tabBarItem; - } - - private getTabBarItemAppearance(): MDCTabBarItemAppearance { - let itemAppearance; - if (this.tabStrip && this.tabStrip._hasImage && this.tabStrip._hasTitle) { - itemAppearance = MDCTabBarItemAppearance.TitledImages; - } else if (this.tabStrip && this.tabStrip._hasImage) { - itemAppearance = MDCTabBarItemAppearance.Images; - } else { - itemAppearance = MDCTabBarItemAppearance.Titles; - } - - return itemAppearance; - } - - private getIconRenderingMode(): UIImageRenderingMode { - switch (this.tabStrip && this.tabStrip.iosIconRenderingMode) { - case 'alwaysOriginal': - return UIImageRenderingMode.AlwaysOriginal; - case 'alwaysTemplate': - return UIImageRenderingMode.AlwaysTemplate; - case 'automatic': - default: - const hasItemColor = this._selectedItemColor || this._unSelectedItemColor; - - return hasItemColor ? UIImageRenderingMode.AlwaysTemplate : UIImageRenderingMode.AlwaysOriginal; - } - } - - private getIcon(tabStripItem: TabStripItem, color?: Color): UIImage { - // Image and Label children of TabStripItem - // take priority over its `iconSource` and `title` properties - const iconSource = tabStripItem.image && tabStripItem.image.src; - if (!iconSource) { - return null; - } - - const target = tabStripItem.image; - const font = target.style.fontInternal || Font.default; - if (!color) { - color = target.style.color; - } - const iconTag = [iconSource, font.fontStyle, font.fontWeight, font.fontSize, font.fontFamily, color].join(';'); - - let isFontIcon = false; - let image: UIImage = this._iconsCache[iconTag]; - if (!image) { - let is = new ImageSource(); - if (isFontIconURI(iconSource)) { - isFontIcon = true; - const fontIconCode = iconSource.split('//')[1]; - is = ImageSource.fromFontIconCodeSync(fontIconCode, font, color); - } else { - is = ImageSource.fromFileOrResourceSync(iconSource); - } - - if (is && is.ios) { - image = is.ios; - - if (this.tabStrip && this.tabStrip.isIconSizeFixed) { - image = this.getFixedSizeIcon(image); - } - - let renderingMode: UIImageRenderingMode = UIImageRenderingMode.Automatic; - if (!isFontIcon) { - renderingMode = this.getIconRenderingMode(); - } - const originalRenderedImage = image.imageWithRenderingMode(renderingMode); - this._iconsCache[iconTag] = originalRenderedImage; - image = originalRenderedImage; - } - } - - return image; - } - - private getFixedSizeIcon(image: UIImage): UIImage { - const inWidth = image.size.width; - const inHeight = image.size.height; - - const iconSpecSize = getIconSpecSize({ width: inWidth, height: inHeight }); - - const widthPts = iconSpecSize.width; - const heightPts = iconSpecSize.height; - - UIGraphicsBeginImageContextWithOptions({ width: widthPts, height: heightPts }, false, layout.getDisplayDensity()); - image.drawInRect(CGRectMake(0, 0, widthPts, heightPts)); - let resultImage = UIGraphicsGetImageFromCurrentImageContext(); - UIGraphicsEndImageContext(); - - return resultImage; - } - - public getTabBarBackgroundColor(): UIColor { - return this._ios.tabBar.barTintColor; - } - - public setTabBarBackgroundColor(value: UIColor | Color): void { - this._ios.tabBar.barTintColor = value instanceof Color ? value.ios : value; - this.updateAllItemsColors(); - } - - public setTabBarItemTitle(tabStripItem: TabStripItem, value: string): void { - tabStripItem.nativeView.title = value; - } - - private equalUIColor(first: UIColor, second: UIColor): boolean { - if (!first && !second) { - return true; - } - if (!first || !second) { - return false; - } - const firstComponents = CGColorGetComponents(first.CGColor); - const secondComponents = CGColorGetComponents(second.CGColor); - - return firstComponents[0] === secondComponents[0] && firstComponents[1] === secondComponents[1] && firstComponents[2] === secondComponents[2] && firstComponents[3] === secondComponents[3]; - } - - private isSelectedAndHightlightedItem(tabStripItem: TabStripItem): boolean { - // to find out whether the current tab strip item is active (has style with :active selector applied) - // we need to check whether its _visualState is equal to "highlighted" as when changing tabs - // we first go through setTabBarItemBackgroundColor thice, once before setting the "highlighted" state - // and once after that, but if the "highlighted" state is not set we cannot get the backgroundColor - // set using :active selector - return tabStripItem._index === this.selectedIndex && tabStripItem['_visualState'] === 'highlighted'; - } - - public setTabBarItemBackgroundColor(tabStripItem: TabStripItem, value: UIColor | Color): void { - if (!this.tabStrip || !tabStripItem) { - return; - } - - let newColor = value instanceof Color ? value.ios : value; - const itemSelectedAndHighlighted = this.isSelectedAndHightlightedItem(tabStripItem); - - // As we cannot implement selected item background color in Tabs we are using the Indicator for this - // To be able to detect that there are two different background colors (one for selected and one for not selected item) - // we are checking whether the current item is not selected and higlighted and we store the value of its - // background color to _defaultItemBackgroundColor and later if we need to process a selected and highlighted item - // we are comparing it's backgroun color to the default one and if there's a difference - // we are changing the selectionIndicatorTemplate from underline to the whole item - // in that mode we are not able to show the indicator as it is used for the background of the selected item - - if (!this._defaultItemBackgroundColor && !itemSelectedAndHighlighted) { - this._defaultItemBackgroundColor = newColor; - } - - if (this.viewController.tabBar.alignment !== MDCTabBarAlignment.Justified && itemSelectedAndHighlighted && !this.equalUIColor(this._defaultItemBackgroundColor, newColor)) { - if (!this._backgroundIndicatorColor) { - this._backgroundIndicatorColor = newColor; - this._ios.tabBar.selectionIndicatorTemplate = new BackgroundIndicatorTemplate(); - this._ios.tabBar.tintColor = newColor; - } - } else { - updateBackgroundPositions(this.tabStrip, tabStripItem, newColor); - } - } - - public setTabBarItemColor(tabStripItem: TabStripItem, value: UIColor | Color): void { - this.setViewTextAttributes(tabStripItem.label); - } - - private setItemColors(): void { - if (this._selectedItemColor) { - this.viewController.tabBar.selectedItemTintColor = this._selectedItemColor.ios; - } - if (this._unSelectedItemColor) { - this.viewController.tabBar.unselectedItemTintColor = this._unSelectedItemColor.ios; - } - } - - private setIconColor(tabStripItem: TabStripItem, forceReload: boolean = false): void { - // if there is no change in the css color and there is no item color set - // we don't need to reload the icon - if (!forceReload && !this._selectedItemColor && !this._unSelectedItemColor) { - return; - } - - let image: UIImage; - - // if selectedItemColor or unSelectedItemColor is set we don't respect the color from the style - const tabStripColor = this.selectedIndex === tabStripItem._index ? this._selectedItemColor : this._unSelectedItemColor; - image = this.getIcon(tabStripItem, tabStripColor); - - tabStripItem.nativeView.image = image; - } - - public setTabBarIconColor(tabStripItem: TabStripItem, value: UIColor | Color): void { - this.setIconColor(tabStripItem, true); - } - - public setTabBarIconSource(tabStripItem: TabStripItem, value: UIColor | Color): void { - this.updateItemColors(tabStripItem); - } - - public setTabBarItemFontInternal(tabStripItem: TabStripItem, value: Font): void { - this.setViewTextAttributes(tabStripItem.label); - } - - public getTabBarFontInternal(): UIFont { - return this._ios.tabBar.unselectedItemTitleFont; - } - - public setTabBarFontInternal(value: Font): void { - const defaultTabItemFontSize = 10; - const tabItemFontSize = this.tabStrip.style.fontSize || defaultTabItemFontSize; - const font: UIFont = (this.tabStrip.style.fontInternal || Font.default).getUIFont(UIFont.systemFontOfSize(tabItemFontSize)); - - this._ios.tabBar.unselectedItemTitleFont = font; - this._ios.tabBar.selectedItemTitleFont = font; - } - - public getTabBarTextTransform(): TextTransform { - switch (this._ios.tabBar.titleTextTransform) { - case MDCTabBarTextTransform.None: - return 'none'; - case MDCTabBarTextTransform.Automatic: - return 'initial'; - case MDCTabBarTextTransform.Uppercase: - default: - return 'uppercase'; - } - } - - public setTabBarTextTransform(value: TextTransform): void { - if (value === 'none') { - this._ios.tabBar.titleTextTransform = MDCTabBarTextTransform.None; - } else if (value === 'uppercase') { - this._ios.tabBar.titleTextTransform = MDCTabBarTextTransform.Uppercase; - } else if (value === 'initial') { - this._ios.tabBar.titleTextTransform = MDCTabBarTextTransform.Automatic; - } - } - - public getTabBarColor(): UIColor { - return this._ios.tabBar.titleColorForState(MDCTabBarItemState.Normal); - } - - public setTabBarColor(value: UIColor | Color): void { - const nativeColor = value instanceof Color ? value.ios : value; - this._ios.tabBar.setTitleColorForState(nativeColor, MDCTabBarItemState.Normal); - this._ios.tabBar.setTitleColorForState(nativeColor, MDCTabBarItemState.Selected); - } - - public getTabBarHighlightColor(): UIColor { - return this._ios.tabBar.tintColor; - } - - public setTabBarHighlightColor(value: UIColor | Color) { - const nativeColor = value instanceof Color ? value.ios : value; - this._ios.tabBar.tintColor = nativeColor; - } - - public getTabBarSelectedItemColor(): Color { - return this._selectedItemColor; - } - - public setTabBarSelectedItemColor(value: Color) { - this._selectedItemColor = value; - this.updateAllItemsColors(); - } - - public getTabBarUnSelectedItemColor(): Color { - return this._unSelectedItemColor; - } - - public setTabBarUnSelectedItemColor(value: Color) { - this._unSelectedItemColor = value; - this.updateAllItemsColors(); - } - - private visitFrames(view: ViewBase, operation: (frame: Frame) => {}) { - if (view instanceof Frame) { - operation(view); - } - view.eachChild((child) => { - this.visitFrames(child, operation); - - return true; - }); - } - - [selectedIndexProperty.setNative](value: number) { - // TODO - // if (Trace.isEnabled()) { - // Trace.write("TabView._onSelectedIndexPropertyChangedSetNativeValue(" + value + ")", Trace.categories.Debug); - // } - - if (value > -1) { - const item = this.items[value]; - const controllers = NSMutableArray.alloc().initWithCapacity(1); - - let itemController = (item).__controller; - - // if (!itemController) { - // itemController = this.getViewController(item); - // } - - controllers.addObject(itemController); - - let navigationDirection = UIPageViewControllerNavigationDirection.Forward; - - if (this._currentNativeSelectedIndex && this._currentNativeSelectedIndex > value) { - navigationDirection = UIPageViewControllerNavigationDirection.Reverse; - } - - this._currentNativeSelectedIndex = value; - - // do not make layout changes while the animation is in progress https://stackoverflow.com/a/47031524/613113 - this.visitFrames(item, (frame) => (frame._animationInProgress = true)); - - invokeOnRunLoop(() => - this.viewController.setViewControllersDirectionAnimatedCompletion(controllers, navigationDirection, this.animationEnabled, (finished: boolean) => { - this.visitFrames(item, (frame) => (frame._animationInProgress = false)); - if (finished) { - // HACK: UIPageViewController fix; see https://stackoverflow.com/a/17330606 - invokeOnRunLoop(() => this.viewController.setViewControllersDirectionAnimatedCompletion(controllers, navigationDirection, false, null)); - - this._canSelectItem = true; - this._setCanBeLoaded(value); - this._loadUnloadTabItems(value); - } - }) - ); - - if (this.tabBarItems && this.tabBarItems.length && this.viewController && this.viewController.tabBar) { - this.viewController.tabBar.setSelectedItemAnimated(this.tabBarItems[value], this.animationEnabled); - } - // TODO: - // (this._ios)._willSelectViewController = this._ios.viewControllers[value]; - // this._ios.selectedIndex = value; - } - } - - [itemsProperty.getDefault](): TabContentItem[] { - return null; - } - [itemsProperty.setNative](value: TabContentItem[]) { - if (value) { - value.forEach((item: TabContentItem, i) => { - (item).index = i; - }); - } - - this.setViewControllers(value); - selectedIndexProperty.coerce(this); - } - - [tabStripProperty.getDefault](): TabStrip { - return null; - } - [tabStripProperty.setNative](value: TabStrip) { - this.setViewControllers(this.items); - selectedIndexProperty.coerce(this); - } - - [swipeEnabledProperty.getDefault](): boolean { - return true; - } - [swipeEnabledProperty.setNative](value: boolean) { - if (this.viewController && this.viewController.scrollView) { - this.viewController.scrollView.scrollEnabled = value; - } - } - - [iOSTabBarItemsAlignmentProperty.getDefault](): IOSTabBarItemsAlignment { - if (!this.viewController || !this.viewController.tabBar) { - return 'justified'; - } - - let alignment = this.viewController.tabBar.alignment.toString(); - - return (alignment.charAt(0).toLowerCase() + alignment.substring(1)); - } - [iOSTabBarItemsAlignmentProperty.setNative](value: IOSTabBarItemsAlignment) { - if (!this.viewController || !this.viewController.tabBar) { - return; - } - - let alignment = MDCTabBarAlignment.Justified; - switch (value) { - case 'leading': - alignment = MDCTabBarAlignment.Leading; - break; - case 'center': - alignment = MDCTabBarAlignment.Center; - break; - case 'centerSelected': - alignment = MDCTabBarAlignment.CenterSelected; - break; - } - - this.viewController.tabBar.alignment = alignment; - } - - private setViewTextAttributes(view: View, setSelected: boolean = false): any { - if (!view) { - return null; - } - - const defaultTabItemFontSize = 10; - const tabItemFontSize = view.style.fontSize || defaultTabItemFontSize; - const font: UIFont = (view.style.fontInternal || Font.default).getUIFont(UIFont.systemFontOfSize(tabItemFontSize)); - - this.viewController.tabBar.unselectedItemTitleFont = font; - this.viewController.tabBar.selectedItemTitleFont = font; - - const tabItemTextColor = view.style.color; - const textColor = tabItemTextColor instanceof Color ? tabItemTextColor.ios : null; - - if (textColor) { - this.viewController.tabBar.setTitleColorForState(textColor, MDCTabBarItemState.Normal); - this.viewController.tabBar.setImageTintColorForState(textColor, MDCTabBarItemState.Normal); - - if (setSelected) { - this.viewController.tabBar.setTitleColorForState(textColor, MDCTabBarItemState.Selected); - this.viewController.tabBar.setImageTintColorForState(textColor, MDCTabBarItemState.Selected); - } - } - - if (this._selectedItemColor) { - this.viewController.tabBar.selectedItemTintColor = this._selectedItemColor.ios; - } - if (this._unSelectedItemColor) { - this.viewController.tabBar.unselectedItemTintColor = this._unSelectedItemColor.ios; - } - } -} diff --git a/packages/core/ui/tabs/tabs-common.ts b/packages/core/ui/tabs/tabs-common.ts deleted file mode 100644 index f4a4b9933..000000000 --- a/packages/core/ui/tabs/tabs-common.ts +++ /dev/null @@ -1,53 +0,0 @@ -// Types -import { Tabs as TabsDefinition } from '.'; - -// Requires -import { TabNavigationBase } from '../tab-navigation-base/tab-navigation-base'; -import { CSSType } from '../core/view'; -import { booleanConverter } from '../core/view-base'; -import { Property } from '../core/properties'; - -export * from '../tab-navigation-base/tab-content-item'; -export * from '../tab-navigation-base/tab-navigation-base'; -export * from '../tab-navigation-base/tab-strip'; -export * from '../tab-navigation-base/tab-strip-item'; - -export const traceCategory = 'TabView'; - -@CSSType('Tabs') -export class TabsBase extends TabNavigationBase implements TabsDefinition { - public swipeEnabled: boolean; - public offscreenTabLimit: number; - public tabsPosition: 'top' | 'bottom'; - public iOSTabBarItemsAlignment: IOSTabBarItemsAlignment; -} - -// TODO: Add Unit tests -export const swipeEnabledProperty = new Property({ - 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), -}); -offscreenTabLimitProperty.register(TabsBase); - -export const tabsPositionProperty = new Property({ - name: 'tabsPosition', - defaultValue: 'top', -}); -tabsPositionProperty.register(TabsBase); - -export type IOSTabBarItemsAlignment = 'leading' | 'justified' | 'center' | 'centerSelected'; -export const iOSTabBarItemsAlignmentProperty = new Property({ name: 'iOSTabBarItemsAlignment', defaultValue: 'justified' }); -iOSTabBarItemsAlignmentProperty.register(TabsBase); - -export const animationEnabledProperty = new Property({ name: 'animationEnabled', defaultValue: true, valueConverter: booleanConverter }); -animationEnabledProperty.register(TabsBase);