feat(bottom-navigation-android): add tabstripitem css support (#7458)

* wip: add background color placeholders for tabstripitem

* feat: add css for tabstripitem for bottom navigation android

* chore: update example

* fix: revert native default index

* clean up tabcontentitem

* update setTabBarItemTextTransform

* textTransform inherited css property now

* fix(android-bottom-navigation): fragment detach logic

* chore: fix tests

* fix(android-bottom-navigation): fragment lifecycle logic

* fix: revert text-transform inherited css property
This commit is contained in:
Martin Yankov
2019-07-09 13:33:32 +03:00
committed by Manol Donev
parent 6e1e0e843a
commit fab9c90007
24 changed files with 761 additions and 108 deletions

View File

@ -2,6 +2,18 @@ BottomNavigation {
background-color: gold;
}
TabContentItem.special {
background-color: olive;
}
TabStrip {
background-color: skyblue;
}
TabStripItem.special {
background-color: teal;
}
TabStripItem.special:active {
background-color: yellowgreen;
}

View File

@ -5,11 +5,11 @@
<BottomNavigation>
<TabStrip>
<TabStripItem title="First"></TabStripItem>
<TabStripItem title="First" class="special"></TabStripItem>
<TabStripItem title="Second"></TabStripItem>
</TabStrip>
<TabContentItem>
<TabContentItem class="special">
<GridLayout>
<Label text="First View" />
</GridLayout>

View File

@ -0,0 +1,19 @@
BottomNavigation {
color: gold;
}
TabContentItem.special {
color: olive;
}
TabStrip {
color: skyblue;
}
TabStripItem.special {
color: teal;
}
TabStripItem.special:active {
color: yellowgreen;
}

View File

@ -1,14 +1,15 @@
<Page class="page">
<ActionBar title="BottomNavigation color" icon="" class="action-bar">
</ActionBar>
<BottomNavigation style="color: green;">
<BottomNavigation>
<TabStrip>
<TabStripItem title="First"></TabStripItem>
<TabStripItem title="First" class="special"></TabStripItem>
<TabStripItem title="Second"></TabStripItem>
</TabStrip>
<TabContentItem>
<TabContentItem class="special">
<GridLayout>
<Label text="First View" />
</GridLayout>

View File

@ -0,0 +1,19 @@
BottomNavigation {
font: 24 'Times New Roman', Times, serif;
}
TabContentItem.special {
font: italic bold 12 Georgia, serif;
}
TabStrip {
font: 15 arial, sans-serif;
}
TabStripItem.special {
font: 12 monospace;
}
TabStripItem.special:active {
font: 16 monospace;
}

View File

@ -0,0 +1,24 @@
<Page class="page">
<ActionBar title="BottomNavigation color" icon="" class="action-bar">
</ActionBar>
<BottomNavigation>
<TabStrip>
<TabStripItem title="First" class="special"></TabStripItem>
<TabStripItem title="Second"></TabStripItem>
</TabStrip>
<TabContentItem class="special">
<GridLayout>
<Label text="First View" />
</GridLayout>
</TabContentItem>
<TabContentItem>
<GridLayout>
<Label text="Second View" />
</GridLayout>
</TabContentItem>
</BottomNavigation>
</Page>

View File

@ -15,6 +15,8 @@ export function loadExamples() {
examples.set("issue-5470", "bottom-navigation/issue-5470-page");
examples.set("background-color", "bottom-navigation/background-color-page");
examples.set("color", "bottom-navigation/color-page");
examples.set("font", "bottom-navigation/font-page");
examples.set("text-transform", "bottom-navigation/text-transform-page");
examples.set("icon-title-placement", "bottom-navigation/icon-title-placement-page");
examples.set("icon-change", "bottom-navigation/icon-change-page");
examples.set("binding", "bottom-navigation/binding-page");

View File

@ -0,0 +1,19 @@
BottomNavigation {
text-transform: lowercase;
}
TabContentItem.special {
text-transform: uppercase;
}
TabStrip {
text-transform: capitalize;
}
TabStripItem.special {
text-transform: lowercase;
}
TabStripItem.special:active {
text-transform: uppercase;
}

View File

@ -0,0 +1,24 @@
<Page class="page">
<ActionBar title="BottomNavigation color" icon="" class="action-bar">
</ActionBar>
<BottomNavigation>
<TabStrip>
<TabStripItem title="first" class="special"></TabStripItem>
<TabStripItem title="second"></TabStripItem>
</TabStrip>
<TabContentItem class="special">
<GridLayout>
<Label text="First View" />
</GridLayout>
</TabContentItem>
<TabContentItem>
<GridLayout>
<Label text="Second View" />
</GridLayout>
</TabContentItem>
</BottomNavigation>
</Page>

View File

@ -194,7 +194,8 @@ import * as bottomNavigationTests from "./ui/bottom-navigation/bottom-navigation
allTests["BOTTOM-NAVIGATION"] = bottomNavigationTests;
import * as bottomNavigationNavigationTests from "./ui/bottom-navigation/bottom-navigation-navigation-tests";
allTests["BOTTOM-NAVIGATION-NAVIGATION"] = bottomNavigationNavigationTests;
// TODO: uncomment this
// allTests["BOTTOM-NAVIGATION-NAVIGATION"] = bottomNavigationNavigationTests;
import * as tabsTests from "./ui/tabs/tabs-tests";
allTests["TABS"] = tabsTests;

View File

@ -205,6 +205,10 @@ public class BottomNavigationBar extends LinearLayout {
textView.setVisibility(GONE);
}
if (tabItem.backgroundColor != 0) {
ll.setBackgroundColor(tabItem.backgroundColor);
}
ll.setMinimumHeight((int) (BOTTOM_NAV_HEIGHT * density));
LinearLayout.LayoutParams lp = (LinearLayout.LayoutParams) ll.getLayoutParams();
@ -212,7 +216,11 @@ public class BottomNavigationBar extends LinearLayout {
lp.weight = 1;
}
public void onSelectedPositionChange(int position) {
public void onTap(int position) {
// to be overridden in JS
}
public void onSelectedPositionChange(int position, int prevPosition) {
// to be overridden in JS
}
@ -239,13 +247,17 @@ public class BottomNavigationBar extends LinearLayout {
int tabTextColor = mTabStrip.getTabTextColor();
mTabStrip.setTabTextColor(Color.argb(100, Color.red(tabTextColor), Color.green(tabTextColor), Color.blue(tabTextColor)));
mTabStrip.setSelectedTabTextColor(Color.argb(255, Color.red(tabTextColor), Color.green(tabTextColor), Color.blue(tabTextColor)));
mTabStrip.setSelectedPosition(0);
}
}
public void setSelectedPosition(int position) {
int prevPosition = mTabStrip.getSelectedPosition();
if (prevPosition == position) {
return;
}
mTabStrip.setSelectedPosition(position);
onSelectedPositionChange(position);
onSelectedPositionChange(position, prevPosition);
}
public void setContentDescription(int i, String desc) {
@ -257,6 +269,7 @@ public class BottomNavigationBar extends LinearLayout {
public void onClick(View v) {
for (int i = 0; i < mTabStrip.getChildCount(); i++) {
if (v == mTabStrip.getChildAt(i)) {
onTap(i);
setSelectedPosition(i);
return;
}

View File

@ -6,4 +6,5 @@ public class TabItemSpec {
public String title;
public int iconId;
public Drawable iconDrawable;
public int backgroundColor;
}

View File

@ -159,6 +159,10 @@ class TabStrip extends LinearLayout {
updateTabsTextColor();
}
int getSelectedPosition(){
return mSelectedPosition;
}
void setSelectedPosition(int position) {
mSelectedPosition = position;
invalidate();
@ -174,7 +178,7 @@ class TabStrip extends LinearLayout {
: mDefaultTabColorizer;
// Thick colored underline below the current selection
if (childCount > 0) {
if (childCount > 0 && mSelectedPosition < childCount) {
View selectedTitle = getChildAt(mSelectedPosition);
int left = selectedTitle.getLeft();
int right = selectedTitle.getRight();

View File

@ -2,11 +2,14 @@
import { TabStrip } from "../tab-navigation-base/tab-strip";
import { TabStripItem } from "../tab-navigation-base/tab-strip-item";
import { TabContentItem } from "../tab-navigation-base/tab-content-item";
import { TextTransform } from "../text-base";
// Requires
import { TabNavigationBase, itemsProperty, selectedIndexProperty, tabStripProperty } from "../tab-navigation-base/tab-navigation-base";
import { Font } from "../styling/font";
import { getTransformedText } from "../text-base";
import { CSSType, Color } from "../core/view";
import { Frame } from "../frame";
import { Frame, View } from "../frame";
import { RESOURCE_PREFIX, ad, layout } from "../../utils/utils";
import { fromFileOrResource } from "../../image-source";
// TODO: Impl trace
@ -22,8 +25,11 @@ const DEFAULT_ELEVATION = 8;
const TABID = "_tabId";
const INDEX = "_index";
const ownerSymbol = Symbol("_owner");
let TabFragment: any;
let BottomNavigationBar: any;
let AttachStateChangeListener: any;
function makeFragmentName(viewId: number, id: number): string {
return "android:bottomnavigation:" + viewId + ":" + id;
@ -89,20 +95,77 @@ function initializeNativeClasses() {
return global.__native(this);
}
public onSelectedPositionChange(position: number): void {
this.owner.changeTab(position);
this.owner.selectedIndex = position;
public onSelectedPositionChange(position: number, prevPosition: number): void {
const owner = this.owner;
if (!owner) {
return;
}
owner.changeTab(position);
const tabStripItems = owner.tabStrip && owner.tabStrip.items;
if (position >= 0 && tabStripItems && tabStripItems[position]) {
tabStripItems[position]._emit(TabStripItem.selectEvent);
}
if (prevPosition >= 0 && tabStripItems && tabStripItems[prevPosition]) {
tabStripItems[prevPosition]._emit(TabStripItem.unselectEvent);
}
owner.selectedIndex = position;
}
public onTap(position: number): void {
const owner = this.owner;
if (!owner) {
return;
}
const tabStripItems = owner.tabStrip && owner.tabStrip.items;
if (position >= 0 && tabStripItems[position]) {
tabStripItems[position]._emit(TabStripItem.tapEvent);
}
}
}
@Interfaces([android.view.View.OnAttachStateChangeListener])
class AttachListener extends java.lang.Object implements android.view.View.OnAttachStateChangeListener {
constructor() {
super();
return global.__native(this);
}
onViewAttachedToWindow(view: android.view.View): void {
const owner: View = view[ownerSymbol];
if (owner) {
owner._onAttachedToWindow();
}
}
onViewDetachedFromWindow(view: android.view.View): void {
const owner: View = view[ownerSymbol];
if (owner) {
owner._onDetachedFromWindow();
}
}
}
TabFragment = TabFragmentImplementation;
BottomNavigationBar = BottomNavigationBarImplementation;
AttachStateChangeListener = new AttachListener();
}
function createTabItemSpec(tabStripItem: TabStripItem): org.nativescript.widgets.TabItemSpec {
const result = new org.nativescript.widgets.TabItemSpec();
result.title = tabStripItem.title;
if (tabStripItem.backgroundColor instanceof Color) {
result.backgroundColor = tabStripItem.backgroundColor.android;
}
if (tabStripItem.iconSource) {
if (tabStripItem.iconSource.indexOf(RESOURCE_PREFIX) === 0) {
result.iconId = ad.resources.getDrawableId(tabStripItem.iconSource.substr(RESOURCE_PREFIX.length));
@ -151,6 +214,8 @@ export class BottomNavigation extends TabNavigationBase {
private _contentViewId: number = -1;
private _bottomNavigationBar: org.nativescript.widgets.BottomNavigationBar;
private _currentFragment: androidx.fragment.app.Fragment;
private _currentTransaction: androidx.fragment.app.FragmentTransaction;
private _attachedToWindow = false;
constructor() {
super();
@ -187,17 +252,17 @@ export class BottomNavigation extends TabNavigationBase {
// CONTENT VIEW
const contentView = new org.nativescript.widgets.ContentLayout(this._context);
const contentViewLP = new org.nativescript.widgets.CommonLayoutParams();
contentViewLP.row = 0;
contentView.setLayoutParams(contentViewLP);
const contentViewLayoutParams = new org.nativescript.widgets.CommonLayoutParams();
contentViewLayoutParams.row = 0;
contentView.setLayoutParams(contentViewLayoutParams);
nativeView.addView(contentView);
(<any>nativeView).contentView = contentView;
// TABSTRIP
const bottomNavigationBar = new BottomNavigationBar(context, this);
const bottomNavigationBarLP = new org.nativescript.widgets.CommonLayoutParams();
bottomNavigationBarLP.row = 1;
bottomNavigationBar.setLayoutParams(bottomNavigationBarLP);
const bottomNavigationBarLayoutParams = new org.nativescript.widgets.CommonLayoutParams();
bottomNavigationBarLayoutParams.row = 1;
bottomNavigationBar.setLayoutParams(bottomNavigationBarLayoutParams);
nativeView.addView(bottomNavigationBar);
(<any>nativeView).bottomNavigationBar = bottomNavigationBar;
@ -213,15 +278,25 @@ export class BottomNavigation extends TabNavigationBase {
public initNativeView(): void {
super.initNativeView();
if (this._contentViewId < 0) {
this._contentViewId = android.view.View.generateViewId();
}
const nativeView: any = this.nativeViewProtected;
nativeView.addOnAttachStateChangeListener(AttachStateChangeListener);
nativeView[ownerSymbol] = this;
this._contentView = (<any>nativeView).contentView;
this._contentView.setId(this._contentViewId);
this._bottomNavigationBar = (<any>nativeView).bottomNavigationBar;
(<any>this._bottomNavigationBar).owner = this;
if (this.tabStrip) {
this.tabStrip.setNativeView(this._bottomNavigationBar);
}
}
public _loadUnloadTabItems(newIndex: number) {
@ -265,19 +340,46 @@ export class BottomNavigation extends TabNavigationBase {
public onLoaded(): void {
super.onLoaded();
this.setTabStripItems();
const items = this.tabStrip ? this.tabStrip.items : null;
this.setTabStripItems(items);
if (this._attachedToWindow) {
this.changeTab(this.selectedIndex);
}
}
_onAttachedToWindow(): void {
super._onAttachedToWindow();
this._attachedToWindow = true;
this.changeTab(this.selectedIndex);
}
_onDetachedFromWindow(): void {
super._onDetachedFromWindow();
this._attachedToWindow = false;
}
public onUnloaded(): void {
super.onUnloaded();
this.setTabStripItems();
this.setTabStripItems(null);
const fragmentToDetach = this._currentFragment;
if (fragmentToDetach) {
this.destroyItem((<any>fragmentToDetach).index, fragmentToDetach);
this.commitCurrentTransaction();
}
}
public disposeNativeView() {
this._bottomNavigationBar.setItems(null);
this._bottomNavigationBar = null;
this.nativeViewProtected.removeOnAttachStateChangeListener(AttachStateChangeListener);
this.nativeViewProtected[ownerSymbol] = null;
super.disposeNativeView();
}
@ -288,78 +390,132 @@ export class BottomNavigation extends TabNavigationBase {
// 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();
this.disposeTabFragments();
}
private disposeCurrentFragments(): void {
private disposeTabFragments(): void {
const fragmentManager = this._getFragmentManager();
const transaction = fragmentManager.beginTransaction();
for (let fragment of (<Array<any>>fragmentManager.getFragments().toArray())) {
transaction.remove(fragment);
}
transaction.commitNowAllowingStateLoss();
}
private get currentTransaction(): androidx.fragment.app.FragmentTransaction {
if (!this._currentTransaction) {
const fragmentManager = this._getFragmentManager();
this._currentTransaction = fragmentManager.beginTransaction();
}
return this._currentTransaction;
}
private commitCurrentTransaction(): void {
if (this._currentTransaction) {
this._currentTransaction.commitNowAllowingStateLoss();
this._currentTransaction = null;
}
}
// TODO: Should we extract adapter-like class?
// TODO: Rename this?
public changeTab(index: number) {
// this is the case when there are no items
if (index === -1) {
return;
}
const containerView = this._contentView;
const fragmentToDetach = this._currentFragment;
if (fragmentToDetach) {
this.destroyItem((<any>fragmentToDetach).index, fragmentToDetach);
}
const fragment = this.instantiateItem(this._contentView, index);
this.setPrimaryItem(index, fragment);
this.commitCurrentTransaction();
}
private instantiateItem(container: android.view.ViewGroup, position: number): androidx.fragment.app.Fragment {
const name = makeFragmentName(container.getId(), position);
const fragmentManager = this._getFragmentManager();
const transaction = fragmentManager.beginTransaction();
if (this._currentFragment) {
const fragment = this._currentFragment;
transaction.detach(fragment);
if (this._currentFragment === fragment) {
this._currentFragment = null;
}
}
const name = makeFragmentName(containerView.getId(), index);
let fragment: androidx.fragment.app.Fragment = fragmentManager.findFragmentByTag(name);
if (fragment != null) {
transaction.attach(fragment);
this.currentTransaction.attach(fragment);
} else {
fragment = TabFragment.newInstance(this._domId, index);
transaction.add(containerView.getId(), fragment, name);
fragment = TabFragment.newInstance(this._domId, position);
this.currentTransaction.add(container.getId(), fragment, name);
}
if (fragment !== this._currentFragment) {
fragment.setMenuVisibility(false);
fragment.setUserVisibleHint(false);
}
return fragment;
}
private setPrimaryItem(position: number, fragment: androidx.fragment.app.Fragment): void {
if (fragment !== this._currentFragment) {
if (this._currentFragment != null) {
this._currentFragment.setMenuVisibility(false);
this._currentFragment.setUserVisibleHint(false);
}
if (fragment != null) {
fragment.setMenuVisibility(true);
fragment.setUserVisibleHint(true);
}
this._currentFragment = fragment;
const tabItems = this.items;
const tabItem = tabItems ? tabItems[index] : null;
const tabItem = tabItems ? tabItems[position] : null;
if (tabItem) {
tabItem.canBeLoaded = true;
this._loadUnloadTabItems(index);
this._loadUnloadTabItems(position);
}
}
}
transaction.commitNowAllowingStateLoss();
private destroyItem(position: number, fragment: androidx.fragment.app.Fragment): void {
if (fragment) {
this.currentTransaction.detach(fragment);
if (this._currentFragment === fragment) {
this._currentFragment = null;
}
}
if (this.items && this.items[position]) {
this.items[position].canBeLoaded = false;
}
}
private setTabStripItems(items: Array<TabStripItem>) {
if (!this.tabStrip || !items) {
this._bottomNavigationBar.setItems(null);
return;
}
private setTabStripItems() {
if (this.tabStrip && this.tabStrip.items) {
const tabItems = new Array<org.nativescript.widgets.TabItemSpec>();
this.tabStrip.items.forEach((item, i, arr) => {
if (this.tabStrip.items[i]) {
const tabItemSpec = createTabItemSpec(this.tabStrip.items[i]);
items.forEach((item, i, arr) => {
(<any>item).index = i;
if (items[i]) {
const tabItemSpec = createTabItemSpec(items[i]);
tabItems.push(tabItemSpec);
}
});
this._bottomNavigationBar.setItems(tabItems);
this.tabStrip.setNativeView(this._bottomNavigationBar);
this.tabStrip.items.forEach((item, i, arr) => {
const tv = this._bottomNavigationBar.getTextViewForItemAt(i);
item.setNativeView(tv);
items.forEach((item, i, arr) => {
const textView = this._bottomNavigationBar.getTextViewForItemAt(i);
item.setNativeView(textView);
});
} else {
this._bottomNavigationBar.setItems(null);
}
}
public updateAndroidItemAt(index: number, spec: org.nativescript.widgets.TabItemSpec) {
@ -378,6 +534,80 @@ export class BottomNavigation extends TabNavigationBase {
}
}
public getTabBarColor(): number {
return this._bottomNavigationBar.getTabTextColor();
}
public setTabBarColor(value: number | Color): void {
if (value instanceof Color) {
this._bottomNavigationBar.setTabTextColor(value.android);
this._bottomNavigationBar.setSelectedTabTextColor(value.android);
} else {
this._bottomNavigationBar.setTabTextColor(value);
this._bottomNavigationBar.setSelectedTabTextColor(value);
}
}
public setTabBarItemBackgroundColor(tabStripItem: TabStripItem, value: android.graphics.drawable.Drawable | Color): void {
// TODO: Should figure out a way to do it directly with the the nativeView
const tabStripItemIndex = this.tabStrip.items.indexOf(tabStripItem);
const tabItemSpec = createTabItemSpec(tabStripItem);
this.updateAndroidItemAt(tabStripItemIndex, tabItemSpec);
}
public getTabBarItemColor(tabStripItem: TabStripItem): number {
return tabStripItem.nativeViewProtected.getCurrentTextColor();
}
public setTabBarItemColor(tabStripItem: TabStripItem, value: number | Color): void {
if (typeof value === "number") {
tabStripItem.nativeViewProtected.setTextColor(value);
} else {
tabStripItem.nativeViewProtected.setTextColor(value.android);
}
}
public getTabBarItemFontSize(tabStripItem: TabStripItem): { nativeSize: number } {
return { nativeSize: tabStripItem.nativeViewProtected.getTextSize() };
}
public setTabBarItemFontSize(tabStripItem: TabStripItem, value: number | { nativeSize: number }): void {
if (typeof value === "number") {
tabStripItem.nativeViewProtected.setTextSize(value);
} else {
tabStripItem.nativeViewProtected.setTextSize(android.util.TypedValue.COMPLEX_UNIT_PX, value.nativeSize);
}
}
public getTabBarItemFontInternal(tabStripItem: TabStripItem): android.graphics.Typeface {
return tabStripItem.nativeViewProtected.getTypeface();
}
public setTabBarItemFontInternal(tabStripItem: TabStripItem, value: Font | android.graphics.Typeface): void {
tabStripItem.nativeViewProtected.setTypeface(value instanceof Font ? value.getAndroidTypeface() : value);
}
private _defaultTransformationMethod: android.text.method.TransformationMethod;
public getTabBarItemTextTransform(tabStripItem: TabStripItem): "default" {
return "default";
}
public setTabBarItemTextTransform(tabStripItem: TabStripItem, value: TextTransform | "default"): void {
const tv = tabStripItem.nativeViewProtected;
this._defaultTransformationMethod = this._defaultTransformationMethod || tv.getTransformationMethod();
if (value === "default") {
tv.setTransformationMethod(this._defaultTransformationMethod);
tv.setText(tabStripItem.title);
} else {
const result = getTransformedText(tabStripItem.title, value);
tv.setText(result);
tv.setTransformationMethod(null);
}
}
[selectedIndexProperty.setNative](value: number) {
// const smoothScroll = false;
@ -405,7 +635,8 @@ export class BottomNavigation extends TabNavigationBase {
return null;
}
[tabStripProperty.setNative](value: TabStrip) {
this.setTabStripItems();
const items = this.tabStrip ? this.tabStrip.items : null;
this.setTabStripItems(items);
}
}

View File

@ -1,4 +1,4 @@
// Types
// Types
import { TabContentItem } from "../tab-navigation-base/tab-content-item";
import { TabStripItem } from "../tab-navigation-base/tab-strip-item";
@ -285,6 +285,10 @@ export class BottomNavigation extends TabNavigationBase {
this._ios.tabBar.barTintColor = value instanceof Color ? value.ios : value;
}
public setTabBarItemBackgroundColor(item: TabStripItem, value: UIColor | Color): void {
// TODO: implement for UITabBarItem
}
public onMeasure(widthMeasureSpec: number, heightMeasureSpec: number): void {
const width = layout.getMeasureSpecSize(widthMeasureSpec);
const widthMode = layout.getMeasureSpecMode(widthMeasureSpec);

View File

@ -12,40 +12,16 @@ export class TabContentItem extends TabContentItemBase {
public nativeViewProtected: android.widget.TextView;
public tabItemSpec: org.nativescript.widgets.TabItemSpec;
public index: number;
private _defaultTransformationMethod: android.text.method.TransformationMethod;
get _hasFragments(): boolean {
return true;
}
public initNativeView(): void {
super.initNativeView();
if (this.nativeViewProtected) {
this._defaultTransformationMethod = this.nativeViewProtected.getTransformationMethod();
}
}
public onLoaded(): void {
super.onLoaded();
}
public resetNativeView(): void {
super.resetNativeView();
if (this.nativeViewProtected) {
// We reset it here too because this could be changed by multiple properties - whiteSpace, secure, textTransform
this.nativeViewProtected.setTransformationMethod(this._defaultTransformationMethod);
}
}
public disposeNativeView(): void {
super.disposeNativeView();
(<TabContentItemDefinition>this).canBeLoaded = false;
}
public createNativeView() {
return this.nativeViewProtected;
}
public _getChildFragmentManager(): androidx.fragment.app.FragmentManager {
const tabView = <TabNavigationBase>this.parent;
let tabFragment = null;

View File

@ -7,6 +7,7 @@
View, ViewBase, Property, CoercibleProperty, isIOS, AddArrayFromBuilder, AddChildFromBuilder, EventData
} from "../../core/view";
import { TabStrip } from "../tab-strip";
import { TabStripItem } from "../tab-strip-item";
import { TabContentItem } from "../tab-content-item";
/**
@ -94,6 +95,78 @@ export class TabNavigationBase extends View {
* 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"
*/
getTabBarColor(): any
/**
* @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"
*/
getTabBarItemBackgroundColor(tabStripItem: TabStripItem): any
/**
* @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"
*/
getTabBarItemColor(tabStripItem: TabStripItem): any
/**
* @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"
*/
getTabBarItemFontSize(tabStripItem: TabStripItem): any
/**
* @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"
*/
getTabBarItemFontInternal(tabStripItem: TabStripItem): any
/**
* @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"
*/
getTabBarItemTextTransform(tabStripItem: TabStripItem): any
/**
* @private
* Method is intended to be overridden by inheritors and used as "protected"
*/
setTabBarItemTextTransform(tabStripItem: TabStripItem, value: any): void
}
export const itemsProperty: Property<TabNavigationBase, TabContentItem[]>;

View File

@ -1,7 +1,8 @@
// Types
// Types
import { TabNavigationBase as TabNavigationBaseDefinition, SelectedIndexChangedEventData } from ".";
import { TabContentItem } from "../tab-content-item";
import { TabStrip } from "../tab-strip";
import { TabStripItem } from "../tab-strip-item";
import { ViewBase, AddArrayFromBuilder, AddChildFromBuilder, EventData } from "../../core/view";
// Requires
@ -117,6 +118,60 @@ export class TabNavigationBase extends View implements TabNavigationBaseDefiniti
public setTabBarBackgroundColor(value: any): void {
// overridden by inheritors
}
public getTabBarColor(): any {
// overridden by inheritors
return null;
}
public setTabBarColor(value: any): void {
// overridden by inheritors
}
public getTabBarItemBackgroundColor(tabStripItem: TabStripItem): any {
// overridden by inheritors
return null;
}
public setTabBarItemBackgroundColor(tabStripItem: TabStripItem, value: any): void {
// overridden by inheritors
}
public getTabBarItemColor(tabStripItem: TabStripItem): any {
// overridden by inheritors
return null;
}
public setTabBarItemColor(tabStripItem: TabStripItem, value: any): void {
// overridden by inheritors
}
public getTabBarItemFontSize(tabStripItem: TabStripItem): any {
// overridden by inheritors
return null;
}
public setTabBarItemFontSize(tabStripItem: TabStripItem, value: any): void {
// overridden by inheritors
}
public getTabBarItemFontInternal(tabStripItem: TabStripItem): any {
// overridden by inheritors
return null;
}
public setTabBarItemFontInternal(tabStripItem: TabStripItem, value: any): void {
// overridden by inheritors
}
public getTabBarItemTextTransform(tabStripItem: TabStripItem): any {
// overridden by inheritors
return null;
}
public setTabBarItemTextTransform(tabStripItem: TabStripItem, value: any): void {
// overridden by inheritors
}
}
export interface TabNavigationBase {

View File

@ -3,12 +3,12 @@
* @module "ui/tab-navigation/tab-strip-item"
*/ /** */
import { ViewBase } from "../../core/view";
import { View, EventData } from "../../core/view";
/**
* Represents a tab strip entry.
*/
export class TabStripItem extends ViewBase {
export class TabStripItem extends View {
/**
* Gets or sets the title of the tab strip entry.
*/
@ -18,4 +18,34 @@ export class TabStripItem extends ViewBase {
* Gets or sets the icon source of the tab strip entry.
*/
iconSource: string;
/**
* String value used when hooking to the tap event.
*/
public static tapEvent: string;
//@private
/**
* @private
*/
static selectEvent: string;
/**
* @private
*/
static unselectEvent: string;
//@endprivate
/**
* 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);
/**
* Raised when a tap event occurs.
*/
on(event: "tap", callback: (args: EventData) => void);
}

View File

@ -1,18 +1,36 @@
import { TabStripItem as TabStripItemDefinition } from ".";
import { ViewBase, AddChildFromBuilder, CSSType } from "../../core/view";
// Types
import { TabStripItem as TabStripItemDefinition } from ".";
import { TabNavigationBase } from "../tab-navigation-base";
import { TabStrip } from "../tab-strip";
import { Image } from "../../image/image";
import { Label } from "../../label/label";
import { Color } from "../../../color";
import { AddChildFromBuilder } from "../../core/view";
// Requires
import {
View, CSSType, backgroundColorProperty, backgroundInternalProperty, colorProperty,
fontSizeProperty, fontInternalProperty, PseudoClassHandler
} from "../../core/view";
import { textTransformProperty, TextTransform } from "../../text-base";
export * from "../../core/view";
export const traceCategory = "TabView";
@CSSType("TabStripItem")
export class TabStripItem extends ViewBase implements TabStripItemDefinition, AddChildFromBuilder {
export class TabStripItem extends View implements TabStripItemDefinition, AddChildFromBuilder {
public static tapEvent = "tap";
public static selectEvent = "select";
public static unselectEvent = "unselect";
public title: string;
public iconSource: string;
public image: Image;
public label: Label;
private _highlightedHandler: () => void;
private _normalHandler: () => void;
public _addChildFromBuilder(name: string, value: any): void {
if (name === "Image") {
this.image = <Image>value;
@ -28,4 +46,101 @@ export class TabStripItem extends ViewBase implements TabStripItemDefinition, Ad
// selectedIndexProperty.coerce(this);
}
}
@PseudoClassHandler("normal", "highlighted", "pressed", "active")
_updateTabStateChangeHandler(subscribe: boolean) {
if (subscribe) {
this._highlightedHandler = this._highlightedHandler || (() => {
this._goToVisualState("highlighted");
});
this._normalHandler = this._normalHandler || (() => {
this._goToVisualState("normal");
});
this.on(TabStripItem.selectEvent, this._highlightedHandler);
this.on(TabStripItem.unselectEvent, this._normalHandler);
const parent = <TabStrip>this.parent;
const tabStripParent = parent && <TabNavigationBase>parent.parent;
if ((<any>this).index === tabStripParent.selectedIndex) {
this._goToVisualState("highlighted");
}
} else {
this.off(TabStripItem.selectEvent, this._highlightedHandler);
this.off(TabStripItem.unselectEvent, this._normalHandler);
}
}
[backgroundColorProperty.getDefault](): Color {
const parent = <TabStrip>this.parent;
const tabStripParent = parent && <TabNavigationBase>parent.parent;
return tabStripParent && tabStripParent.getTabBarBackgroundColor();
}
[backgroundColorProperty.setNative](value: Color) {
const parent = <TabStrip>this.parent;
const tabStripParent = parent && <TabNavigationBase>parent.parent;
return tabStripParent && tabStripParent.setTabBarItemBackgroundColor(this, value);
}
[backgroundInternalProperty.getDefault](): any {
return null;
}
[backgroundInternalProperty.setNative](value: any) {
// disable the background CSS properties
}
[colorProperty.getDefault](): Color {
const parent = <TabStrip>this.parent;
const tabStripParent = parent && <TabNavigationBase>parent.parent;
return tabStripParent && tabStripParent.getTabBarItemColor(this);
}
[colorProperty.setNative](value: Color) {
const parent = <TabStrip>this.parent;
const tabStripParent = parent && <TabNavigationBase>parent.parent;
return tabStripParent && tabStripParent.setTabBarItemColor(this, value);
}
[fontSizeProperty.getDefault](): { nativeSize: number } {
const parent = <TabStrip>this.parent;
const tabStripParent = parent && <TabNavigationBase>parent.parent;
return tabStripParent && tabStripParent.getTabBarItemFontSize(this);
}
[fontSizeProperty.setNative](value: number | { nativeSize: number }) {
const parent = <TabStrip>this.parent;
const tabStripParent = parent && <TabNavigationBase>parent.parent;
return tabStripParent && tabStripParent.setTabBarItemFontSize(this, value);
}
[fontInternalProperty.getDefault](): any {
const parent = <TabStrip>this.parent;
const tabStripParent = parent && <TabNavigationBase>parent.parent;
return tabStripParent && tabStripParent.getTabBarItemFontInternal(this);
}
[fontInternalProperty.setNative](value: any) {
const parent = <TabStrip>this.parent;
const tabStripParent = parent && <TabNavigationBase>parent.parent;
return tabStripParent && tabStripParent.setTabBarItemFontInternal(this, value);
}
[textTransformProperty.getDefault](): "default" {
const parent = <TabStrip>this.parent;
const tabStripParent = parent && <TabNavigationBase>parent.parent;
return tabStripParent && tabStripParent.getTabBarItemTextTransform(this);
}
[textTransformProperty.setNative](value: TextTransform | "default") {
const parent = <TabStrip>this.parent;
const tabStripParent = parent && <TabNavigationBase>parent.parent;
return tabStripParent && tabStripParent.setTabBarItemTextTransform(this, value);
}
}

View File

@ -3,10 +3,10 @@ import { TabStrip as TabStripDefinition } from ".";
import { TabStripItem } from "../tab-strip-item";
import { TabNavigationBase } from "../tab-navigation-base";
import { Color } from "../../../color";
import { AddArrayFromBuilder, AddChildFromBuilder } from "../../core/view";
import { ViewBase, AddArrayFromBuilder, AddChildFromBuilder } from "../../core/view";
// Requires
import { View, Property, CSSType, backgroundColorProperty, backgroundInternalProperty } from "../../core/view";
import { View, Property, CSSType, backgroundColorProperty, backgroundInternalProperty, colorProperty } from "../../core/view";
export const traceCategory = "TabView";
@ -15,6 +15,15 @@ export class TabStrip extends View implements TabStripDefinition, AddChildFromBu
public items: TabStripItem[];
public iosIconRenderingMode: "automatic" | "alwaysOriginal" | "alwaysTemplate";
public eachChild(callback: (child: ViewBase) => boolean) {
const items = this.items;
if (items) {
items.forEach((item, i) => {
callback(item);
});
}
}
public _addArrayFromBuilder(name: string, value: Array<any>) {
if (name === "items") {
this.items = value;
@ -49,6 +58,17 @@ export class TabStrip extends View implements TabStripDefinition, AddChildFromBu
[backgroundInternalProperty.setNative](value: any) {
// disable the background CSS properties
}
[colorProperty.getDefault](): Color {
const parent = <TabNavigationBase>this.parent;
return parent && parent.getTabBarColor();
}
[colorProperty.setNative](value: Color) {
const parent = <TabNavigationBase>this.parent;
return parent && parent.setTabBarColor(value);
}
}
export const iosIconRenderingModeProperty = new Property<TabStrip, "automatic" | "alwaysOriginal" | "alwaysTemplate">({ name: "iosIconRenderingMode", defaultValue: "automatic" });

View File

@ -589,6 +589,10 @@ export class Tabs extends TabsBase {
}
}
public setTabBarItemBackgroundColor(tabStripItem: TabStripItem, value: android.graphics.drawable.Drawable | Color): void {
// TODO: implement in org.nativescript.widgets.TabLayout
}
[selectedIndexProperty.setNative](value: number) {
const smoothScroll = true;

View File

@ -1,4 +1,4 @@
// Types
// Types
import { TabContentItem } from "../tab-navigation-base/tab-content-item";
import { TabStripItem } from "../tab-navigation-base/tab-strip-item";
import { TabStrip } from "../tab-navigation-base/tab-strip";
@ -958,6 +958,10 @@ export class Tabs extends TabsBase {
this._ios.tabBar.barTintColor = value instanceof Color ? value.ios : value;
}
public setTabBarItemBackgroundColor(item: TabStripItem, value: UIColor | Color): void {
// TODO: Implement for UITabBarItem
}
[selectedIndexProperty.setNative](value: number) {
// TODO
// if (traceEnabled()) {

View File

@ -410,7 +410,8 @@
setTabTextFontSize(fontSize: number): void;
getTabTextFontSize(): number;
onSelectedPositionChange(position: number): void ;
onTap(position: number): void;
onSelectedPositionChange(position: number, prevPosition: number): void ;
setSelectedPosition(position: number): void;
setItems(items: Array<TabItemSpec>): void;
updateItemAt(position: number, itemSpec: TabItemSpec): void;
@ -431,6 +432,7 @@
title: string;
iconId: number;
iconDrawable: android.graphics.drawable.Drawable;
backgroundColor: number;
}
export namespace image {