mirror of
https://github.com/NativeScript/NativeScript.git
synced 2025-08-15 11:01:21 +08:00
refactor(tabs): strip item appearance and creation (#7466)
* test(e2e): add tab strip items pages * fix(ios-tabs): a crash on swiping a content item Fixes https://github.com/NativeScript/NativeScript/issues/7459. * feat(android-tabs): create tab item spec from image and label Implements https://github.com/NativeScript/nativescript-angular/issues/1884 for Android. * feat(ios-tabs): tab bar item appearance Implements https://github.com/NativeScript/NativeScript/issues/7436 and https://github.com/NativeScript/nativescript-angular/issues/1884. * refactor(ios-tabs): move _hasImage and _hasTitle properties
This commit is contained in:

committed by
Alexander Djenkov

parent
c42bf0a6d0
commit
c34a48ac77
@ -1,8 +1,9 @@
|
||||
import { EventData } from "tns-core-modules/data/observable";
|
||||
import { SubMainPageViewModel } from "../sub-main-page-view-model";
|
||||
import { WrapLayout } from "tns-core-modules/ui/layouts/wrap-layout";
|
||||
import { Page } from "tns-core-modules/ui/page";
|
||||
|
||||
import { SubMainPageViewModel } from "../sub-main-page-view-model";
|
||||
|
||||
export function pageLoaded(args: EventData) {
|
||||
const page = <Page>args.object;
|
||||
const wrapLayout = <WrapLayout>page.getViewById("wrapLayoutWithExamples");
|
||||
@ -18,6 +19,8 @@ export function loadExamples() {
|
||||
examples.set("icon-title-placement", "tabs/icon-title-placement");
|
||||
examples.set("icon-change", "tabs/icon-change");
|
||||
examples.set("swipe-enabled", "tabs/swipe-enabled");
|
||||
examples.set("strip-item", "tabs/tab-strip-item-page");
|
||||
examples.set("strip-items", "tabs/tab-strip-items-page");
|
||||
examples.set("tabs-position", "tabs/tabs-position-page");
|
||||
examples.set("tabs-binding", "tabs/tabs-binding-page");
|
||||
|
||||
|
16
e2e/ui-tests-app/app/tabs/tab-strip-item-page.xml
Normal file
16
e2e/ui-tests-app/app/tabs/tab-strip-item-page.xml
Normal file
@ -0,0 +1,16 @@
|
||||
<Page>
|
||||
<Tabs id="tabs">
|
||||
|
||||
<TabStrip>
|
||||
|
||||
<TabStripItem title="TabStripItem 1" iconSource="res://icon">
|
||||
</TabStripItem>
|
||||
|
||||
</TabStrip>
|
||||
|
||||
<TabContentItem>
|
||||
<Label text="TabContentItem 1"></Label>
|
||||
</TabContentItem>
|
||||
|
||||
</Tabs>
|
||||
</Page>
|
88
e2e/ui-tests-app/app/tabs/tab-strip-items-page.xml
Normal file
88
e2e/ui-tests-app/app/tabs/tab-strip-items-page.xml
Normal file
@ -0,0 +1,88 @@
|
||||
<Page>
|
||||
<Tabs id="tabs">
|
||||
|
||||
<TabStrip>
|
||||
|
||||
<TabStripItem title="TabStripItem 1" iconSource="res://icon">
|
||||
</TabStripItem>
|
||||
|
||||
<TabStripItem>
|
||||
<Label text="TabStripItem 2">
|
||||
</Label>
|
||||
<Image src="res://icon">
|
||||
</Image>
|
||||
</TabStripItem>
|
||||
|
||||
<TabStripItem title="TabStripItem X" iconSource="res://icon">
|
||||
<Label text="TabStripItem 3">
|
||||
</Label>
|
||||
<Image src="res://icon">
|
||||
</Image>
|
||||
</TabStripItem>
|
||||
|
||||
<TabStripItem>
|
||||
<Label text="TabStripItem 4">
|
||||
</Label>
|
||||
</TabStripItem>
|
||||
|
||||
<TabStripItem>
|
||||
<Image src="res://icon">
|
||||
</Image>
|
||||
</TabStripItem>
|
||||
|
||||
<TabStripItem title="TabStripItem 6">
|
||||
</TabStripItem>
|
||||
|
||||
<TabStripItem iconSource="res://icon">
|
||||
</TabStripItem>
|
||||
|
||||
<TabStripItem title="TabStripItem X" iconSource="res://icon">
|
||||
<Label text="TabStripItem 8">
|
||||
</Label>
|
||||
</TabStripItem>
|
||||
|
||||
<TabStripItem title="TabStripItem 9" iconSource="res://icon">
|
||||
<Image src="res://icon">
|
||||
</Image>
|
||||
</TabStripItem>
|
||||
|
||||
</TabStrip>
|
||||
|
||||
<TabContentItem>
|
||||
<Label text="TabContentItem 1"></Label>
|
||||
</TabContentItem>
|
||||
|
||||
<TabContentItem>
|
||||
<Label text="TabContentItem 2"></Label>
|
||||
</TabContentItem>
|
||||
|
||||
<TabContentItem>
|
||||
<Label text="TabContentItem 3"></Label>
|
||||
</TabContentItem>
|
||||
|
||||
<TabContentItem>
|
||||
<Label text="TabContentItem 4"></Label>
|
||||
</TabContentItem>
|
||||
|
||||
<TabContentItem>
|
||||
<Label text="TabContentItem 5"></Label>
|
||||
</TabContentItem>
|
||||
|
||||
<TabContentItem>
|
||||
<Label text="TabContentItem 6"></Label>
|
||||
</TabContentItem>
|
||||
|
||||
<TabContentItem>
|
||||
<Label text="TabContentItem 7"></Label>
|
||||
</TabContentItem>
|
||||
|
||||
<TabContentItem>
|
||||
<Label text="TabContentItem 8"></Label>
|
||||
</TabContentItem>
|
||||
|
||||
<TabContentItem>
|
||||
<Label text="TabContentItem 9"></Label>
|
||||
</TabContentItem>
|
||||
|
||||
</Tabs>
|
||||
</Page>
|
@ -4,6 +4,8 @@
|
||||
*/ /** */
|
||||
|
||||
import { View, EventData } from "../../core/view";
|
||||
import { Image } from "../../image/image";
|
||||
import { Label } from "../../label/label";
|
||||
|
||||
/**
|
||||
* Represents a tab strip entry.
|
||||
@ -19,6 +21,16 @@ export class TabStripItem extends View {
|
||||
*/
|
||||
iconSource: string;
|
||||
|
||||
/**
|
||||
* Gets or sets the label of the tab strip entry.
|
||||
*/
|
||||
label: Label;
|
||||
|
||||
/**
|
||||
* Gets or sets the image of the tab strip entry.
|
||||
*/
|
||||
image: Image;
|
||||
|
||||
/**
|
||||
* String value used when hooking to the tap event.
|
||||
*/
|
||||
|
@ -21,6 +21,16 @@ export class TabStrip extends View {
|
||||
* Gets or sets the icon rendering mode on iOS
|
||||
*/
|
||||
iosIconRenderingMode: "automatic" | "alwaysOriginal" | "alwaysTemplate";
|
||||
|
||||
/**
|
||||
* @private
|
||||
*/
|
||||
_hasImage: boolean;
|
||||
|
||||
/**
|
||||
* @private
|
||||
*/
|
||||
_hasTitle: boolean;
|
||||
}
|
||||
|
||||
export const iosIconRenderingModeProperty: Property<TabStrip, "automatic" | "alwaysOriginal" | "alwaysTemplate">;
|
||||
|
@ -14,6 +14,8 @@ export const traceCategory = "TabView";
|
||||
export class TabStrip extends View implements TabStripDefinition, AddChildFromBuilder, AddArrayFromBuilder {
|
||||
public items: TabStripItem[];
|
||||
public iosIconRenderingMode: "automatic" | "alwaysOriginal" | "alwaysTemplate";
|
||||
public _hasImage: boolean;
|
||||
public _hasTitle: boolean;
|
||||
|
||||
public eachChild(callback: (child: ViewBase) => boolean) {
|
||||
const items = this.items;
|
||||
|
@ -234,29 +234,34 @@ function initializeNativeClasses() {
|
||||
}
|
||||
|
||||
function createTabItemSpec(item: TabStripItem): org.nativescript.widgets.TabItemSpec {
|
||||
const result = new org.nativescript.widgets.TabItemSpec();
|
||||
result.title = item.title;
|
||||
let iconSource;
|
||||
const tabItemSpec = new org.nativescript.widgets.TabItemSpec();
|
||||
|
||||
if (item.iconSource) {
|
||||
if (item.iconSource.indexOf(RESOURCE_PREFIX) === 0) {
|
||||
result.iconId = ad.resources.getDrawableId(item.iconSource.substr(RESOURCE_PREFIX.length));
|
||||
if (result.iconId === 0) {
|
||||
// Image and Label children of TabStripItem
|
||||
// take priority over its `iconSource` and `title` properties
|
||||
iconSource = item.image ? item.image.src : item.iconSource;
|
||||
tabItemSpec.title = item.label ? item.label.text : item.title;
|
||||
|
||||
if (iconSource) {
|
||||
if (iconSource.indexOf(RESOURCE_PREFIX) === 0) {
|
||||
tabItemSpec.iconId = ad.resources.getDrawableId(iconSource.substr(RESOURCE_PREFIX.length));
|
||||
if (tabItemSpec.iconId === 0) {
|
||||
// TODO
|
||||
// traceMissingIcon(item.iconSource);
|
||||
// traceMissingIcon(iconSource);
|
||||
}
|
||||
} else {
|
||||
const is = fromFileOrResource(item.iconSource);
|
||||
const is = fromFileOrResource(iconSource);
|
||||
if (is) {
|
||||
// TODO: Make this native call that accepts string so that we don't load Bitmap in JS.
|
||||
result.iconDrawable = new android.graphics.drawable.BitmapDrawable(application.android.context.getResources(), is.android);
|
||||
tabItemSpec.iconDrawable = new android.graphics.drawable.BitmapDrawable(application.android.context.getResources(), is.android);
|
||||
} else {
|
||||
// TODO
|
||||
// traceMissingIcon(item.iconSource);
|
||||
// traceMissingIcon(iconSource);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
return result;
|
||||
return tabItemSpec;
|
||||
}
|
||||
|
||||
let defaultAccentColor: number = undefined;
|
||||
|
34
tns-core-modules/ui/tabs/tabs.d.ts
vendored
34
tns-core-modules/ui/tabs/tabs.d.ts
vendored
@ -1,22 +1,24 @@
|
||||
/**
|
||||
* Contains the TabView class, which represents a standard content component with tabs.
|
||||
* @module "ui/tab-view"
|
||||
* Contains the Tabs class, which represents a tab navigation component.
|
||||
* @module "ui/tabs"
|
||||
*/ /** */
|
||||
|
||||
import { Property, EventData } from "../core/view";
|
||||
import { TabNavigationBase, SelectedIndexChangedEventData } from "../tab-navigation-base/tab-navigation-base";
|
||||
import { TabContentItem } from "../tab-navigation-base/tab-content-item";
|
||||
import { TabStrip } from "../tab-navigation-base/tab-strip";
|
||||
import { EventData, Property } from "../core/view";
|
||||
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";
|
||||
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 {
|
||||
export class Tabs extends TabNavigationBase {
|
||||
/**
|
||||
* Gets or sets the items of the Tabs.
|
||||
*/
|
||||
@ -74,8 +76,8 @@
|
||||
* Raised when the selected index changes.
|
||||
*/
|
||||
on(event: "selectedIndexChanged", callback: (args: SelectedIndexChangedEventData) => void, thisArg?: any);
|
||||
}
|
||||
}
|
||||
|
||||
export const itemsProperty: Property<Tabs, TabContentItem[]>;
|
||||
export const tabStripProperty: Property<Tabs, TabStrip>
|
||||
export const selectedIndexProperty: Property<Tabs, number>;
|
||||
export const itemsProperty: Property<Tabs, TabContentItem[]>;
|
||||
export const tabStripProperty: Property<Tabs, TabStrip>
|
||||
export const selectedIndexProperty: Property<Tabs, number>;
|
||||
|
@ -81,23 +81,11 @@ class UIPageViewControllerImpl extends UIPageViewController {
|
||||
tabBar.items = NSArray.arrayWithArray(tabBarItems);
|
||||
}
|
||||
|
||||
// tabBar.items = <NSArray<UITabBarItem>>NSArray.alloc().initWithArray([
|
||||
// UITabBarItem.alloc().initWithTitleImageTag("Test", null, 0),
|
||||
// UITabBarItem.alloc().initWithTitleImageTag("Test", null, 0),
|
||||
// UITabBarItem.alloc().initWithTitleImageTag("Test", null, 0),
|
||||
// UITabBarItem.alloc().initWithTitleImageTag("Test", null, 0),
|
||||
// UITabBarItem.alloc().initWithTitleImageTag("Test", null, 0),
|
||||
// UITabBarItem.alloc().initWithTitleImageTag("Test", null, 0),
|
||||
// UITabBarItem.alloc().initWithTitleImageTag("Test", null, 0),
|
||||
// UITabBarItem.alloc().initWithTitleImageTag("Test", null, 0),
|
||||
// UITabBarItem.alloc().initWithTitleImageTag("Test", null, 0),
|
||||
// UITabBarItem.alloc().initWithTitleImageTag("Test", null, 0),
|
||||
// UITabBarItem.alloc().initWithTitleImageTag("Test", null, 0),
|
||||
// UITabBarItem.alloc().initWithTitleImageTag("Test", null, 0),
|
||||
// ]);
|
||||
|
||||
tabBar.delegate = this.tabBarDelegate = MDCTabBarDelegateImpl.initWithOwner(new WeakRef(owner));
|
||||
tabBar.itemAppearance = MDCTabBarItemAppearance.Titles;
|
||||
// Initially set `itemAppearance` to TitledImages.
|
||||
// Reassign if needed when items available.
|
||||
// Other combinations do not work.
|
||||
tabBar.itemAppearance = MDCTabBarItemAppearance.TitledImages;
|
||||
tabBar.tintColor = UIColor.blueColor;
|
||||
tabBar.barTintColor = UIColor.whiteColor;
|
||||
tabBar.setTitleColorForState(UIColor.blackColor, MDCTabBarItemState.Normal);
|
||||
@ -856,33 +844,20 @@ export class Tabs extends TabsBase {
|
||||
public setTabStripItems(items: Array<TabStripItem>) {
|
||||
const tabBarItems = [];
|
||||
|
||||
items.forEach((item: TabStripItem, i, arr) => {
|
||||
const tabBarItem = UITabBarItem.alloc().initWithTitleImageTag(item.title, null, 0);
|
||||
items.forEach((item: TabStripItem, i) => {
|
||||
const tabBarItem = this.createTabBarItem(item, i);
|
||||
tabBarItems.push(tabBarItem);
|
||||
item.setNativeView(tabBarItem);
|
||||
});
|
||||
|
||||
this.tabBarItems = tabBarItems;
|
||||
|
||||
if (this.viewController && this.viewController.tabBar) {
|
||||
this.viewController.tabBar.itemAppearance = this._getTabBarItemAppearance();
|
||||
this.viewController.tabBar.items = NSArray.arrayWithArray(tabBarItems);
|
||||
this.tabStrip.setNativeView(this.viewController.tabBar);
|
||||
}
|
||||
|
||||
// tabBar.items = <NSArray<UITabBarItem>>NSArray.alloc().initWithArray([
|
||||
// UITabBarItem.alloc().initWithTitleImageTag("Test", null, 0),
|
||||
// UITabBarItem.alloc().initWithTitleImageTag("Test", null, 0),
|
||||
// UITabBarItem.alloc().initWithTitleImageTag("Test", null, 0),
|
||||
// UITabBarItem.alloc().initWithTitleImageTag("Test", null, 0),
|
||||
// UITabBarItem.alloc().initWithTitleImageTag("Test", null, 0),
|
||||
// UITabBarItem.alloc().initWithTitleImageTag("Test", null, 0),
|
||||
// UITabBarItem.alloc().initWithTitleImageTag("Test", null, 0),
|
||||
// UITabBarItem.alloc().initWithTitleImageTag("Test", null, 0),
|
||||
// UITabBarItem.alloc().initWithTitleImageTag("Test", null, 0),
|
||||
// UITabBarItem.alloc().initWithTitleImageTag("Test", null, 0),
|
||||
// UITabBarItem.alloc().initWithTitleImageTag("Test", null, 0),
|
||||
// UITabBarItem.alloc().initWithTitleImageTag("Test", null, 0),
|
||||
// ]);
|
||||
|
||||
// const length = items ? items.length : 0;
|
||||
// if (length === 0) {
|
||||
// this._tabLayout.setItems(null, null);
|
||||
@ -905,6 +880,41 @@ export class Tabs extends TabsBase {
|
||||
// });
|
||||
}
|
||||
|
||||
private createTabBarItem(item: TabStripItem, index: number): UITabBarItem {
|
||||
let image: UIImage;
|
||||
let title: string;
|
||||
|
||||
// Image and Label children of TabStripItem
|
||||
// take priority over its `iconSource` and `title` properties
|
||||
image = item.image ? this._getIcon(item.image.src) : this._getIcon(item.iconSource);
|
||||
title = item.label ? item.label.text : item.title;
|
||||
|
||||
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._hasImage && this.tabStrip._hasTitle) {
|
||||
itemAppearance = MDCTabBarItemAppearance.TitledImages;
|
||||
} else if (this.tabStrip._hasImage) {
|
||||
itemAppearance = MDCTabBarItemAppearance.Images;
|
||||
} else {
|
||||
itemAppearance = MDCTabBarItemAppearance.Titles;
|
||||
}
|
||||
|
||||
return itemAppearance;
|
||||
}
|
||||
|
||||
private _getIconRenderingMode(): UIImageRenderingMode {
|
||||
return UIImageRenderingMode.AlwaysOriginal;
|
||||
}
|
||||
|
Reference in New Issue
Block a user