Skip to content

Commit 4952ca6

Browse files
authored
Merge branch 'master' into doubleTap-location
2 parents 46628ff + 4589431 commit 4952ca6

File tree

20 files changed

+560
-475
lines changed

20 files changed

+560
-475
lines changed

api-reports/NativeScript.api.md

Lines changed: 5 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -1239,6 +1239,9 @@ export class iOSApplication {
12391239
window: any /* UIWindow */;
12401240
}
12411241

1242+
// @public
1243+
export type IOSTabBarItemsAlignment = "leading" | "justified" | "center" | "centerSelected";
1244+
12421245
// @public
12431246
export const isAndroid: boolean;
12441247

@@ -2274,6 +2277,8 @@ export class Tabs extends TabNavigationBase {
22742277

22752278
ios: any /* UITabBarController */;
22762279

2280+
iOSTabBarItemsAlignment: IOSTabBarItemsAlignment;
2281+
22772282
items: Array<TabContentItem>;
22782283

22792284
offscreenTabLimit: number;

e2e/ui-tests-app/app/tabs/main-page.ts

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -32,6 +32,7 @@ export function loadExamples() {
3232
examples.set("nested-layout", "tabs/nested-layout-page");
3333
examples.set("nested-bottom-navigation", "tabs/nested-bottom-navigation-page");
3434
examples.set("custom-tabstrip", "tabs/custom-tabstrip-page");
35+
examples.set("frame-in-tabs", "tabs/frame-in-tabs");
3536

3637
return examples;
3738
}

e2e/ui-tests-app/app/tabs/tab-strip-items-page.xml

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -1,5 +1,5 @@
11
<Page>
2-
<Tabs id="tabs" automationText="tabNavigation" >
2+
<Tabs id="tabs" automationText="tabNavigation" iOSTabBarItemsAlignment="leading">
33

44
<TabStrip>
55

nativescript-core/platforms/ios/native-api-usage.json

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -14,6 +14,7 @@
1414
"Foundation.*:*",
1515

1616
"MaterialComponents.MDCTabBar:*",
17+
"MaterialComponents.MDCTabBarIndicatorTemplate:*",
1718

1819
"NativeScriptEmbedder:*",
1920

nativescript-core/platforms/ios/typings/objc!MaterialComponents.d.ts

Lines changed: 8 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -442,13 +442,17 @@ declare class MDCTabBar extends UIView implements UIBarPositioning {
442442

443443
delegate: MDCTabBarDelegate;
444444

445-
displaysUppercaseTitles: boolean;
445+
displaysUppercaseTitles: boolean;
446446

447-
inkColor: UIColor;
447+
enableRippleBehavior: boolean;
448+
449+
inkColor: UIColor;
450+
451+
itemAppearance: MDCTabBarItemAppearance;
448452

449-
itemAppearance: MDCTabBarItemAppearance;
453+
items: NSArray<UITabBarItem>;
450454

451-
items: NSArray<UITabBarItem>;
455+
rippleColor: UIColor;
452456

453457
selectedItem: UITabBarItem;
454458

nativescript-core/ui/bottom-navigation/bottom-navigation.android.ts

Lines changed: 62 additions & 18 deletions
Original file line numberDiff line numberDiff line change
@@ -36,6 +36,11 @@ let BottomNavigationBar: any;
3636
let AttachStateChangeListener: any;
3737
let appResources: android.content.res.Resources;
3838

39+
class IconInfo {
40+
drawable: android.graphics.drawable.BitmapDrawable;
41+
height: number;
42+
}
43+
3944
function makeFragmentName(viewId: number, id: number): string {
4045
return "android:bottomnavigation:" + viewId + ":" + id;
4146
}
@@ -243,6 +248,7 @@ export class BottomNavigation extends TabNavigationBase {
243248
private _currentTransaction: androidx.fragment.app.FragmentTransaction;
244249
private _attachedToWindow = false;
245250
public _originalBackground: any;
251+
private _textTransform: TextTransform = "none";
246252

247253
constructor() {
248254
super();
@@ -562,6 +568,18 @@ export class BottomNavigation extends TabNavigationBase {
562568
});
563569
}
564570

571+
private getItemLabelTextTransform(tabStripItem: TabStripItem): TextTransform {
572+
const nestedLabel = tabStripItem.label;
573+
let textTransform: TextTransform = null;
574+
if (nestedLabel && nestedLabel.style.textTransform !== "initial") {
575+
textTransform = nestedLabel.style.textTransform;
576+
} else if (tabStripItem.style.textTransform !== "initial") {
577+
textTransform = tabStripItem.style.textTransform;
578+
}
579+
580+
return textTransform || this._textTransform;
581+
}
582+
565583
private createTabItemSpec(tabStripItem: TabStripItem): org.nativescript.widgets.TabItemSpec {
566584
const tabItemSpec = new org.nativescript.widgets.TabItemSpec();
567585

@@ -570,10 +588,8 @@ export class BottomNavigation extends TabNavigationBase {
570588
let title = titleLabel.text;
571589

572590
// TEXT-TRANSFORM
573-
const textTransform = titleLabel.style.textTransform;
574-
if (textTransform) {
575-
title = getTransformedText(title, textTransform);
576-
}
591+
const textTransform = this.getItemLabelTextTransform(tabStripItem);
592+
title = getTransformedText(title, textTransform);
577593
tabItemSpec.title = title;
578594

579595
// BACKGROUND-COLOR
@@ -596,12 +612,13 @@ export class BottomNavigation extends TabNavigationBase {
596612
// ICON
597613
const iconSource = tabStripItem.image && tabStripItem.image.src;
598614
if (iconSource) {
599-
const icon = this.getIcon(tabStripItem);
615+
const iconInfo = this.getIconInfo(tabStripItem);
600616

601-
if (icon) {
617+
if (iconInfo) {
602618
// TODO: Make this native call that accepts string so that we don't load Bitmap in JS.
603619
// tslint:disable-next-line:deprecation
604-
tabItemSpec.iconDrawable = icon;
620+
tabItemSpec.iconDrawable = iconInfo.drawable;
621+
tabItemSpec.imageHeight = iconInfo.height;
605622
} else {
606623
// TODO:
607624
// traceMissingIcon(iconSource);
@@ -612,7 +629,7 @@ export class BottomNavigation extends TabNavigationBase {
612629
return tabItemSpec;
613630
}
614631

615-
private getIcon(tabStripItem: TabStripItem): android.graphics.drawable.BitmapDrawable {
632+
private getOriginalIcon(tabStripItem: TabStripItem): android.graphics.Bitmap {
616633
const iconSource = tabStripItem.image && tabStripItem.image.src;
617634
if (!iconSource) {
618635
return null;
@@ -629,21 +646,30 @@ export class BottomNavigation extends TabNavigationBase {
629646
is = ImageSource.fromFileOrResourceSync(iconSource);
630647
}
631648

632-
let imageDrawable: android.graphics.drawable.BitmapDrawable;
633-
if (is && is.android) {
634-
let image = is.android;
649+
return is && is.android;
650+
}
635651

652+
private getDrawableInfo(image: android.graphics.Bitmap): IconInfo {
653+
if (image) {
636654
if (this.tabStrip && this.tabStrip.isIconSizeFixed) {
637655
image = this.getFixedSizeIcon(image);
638656
}
639657

640-
imageDrawable = new android.graphics.drawable.BitmapDrawable(application.android.context.getResources(), image);
641-
} else {
642-
// TODO
643-
// traceMissingIcon(iconSource);
658+
let imageDrawable = new android.graphics.drawable.BitmapDrawable(application.android.context.getResources(), image);
659+
660+
return {
661+
drawable: imageDrawable,
662+
height: image.getHeight()
663+
};
644664
}
645665

646-
return imageDrawable;
666+
return new IconInfo();
667+
}
668+
669+
private getIconInfo(tabStripItem: TabStripItem): IconInfo {
670+
let originalIcon = this.getOriginalIcon(tabStripItem);
671+
672+
return this.getDrawableInfo(originalIcon);
647673
}
648674

649675
private getFixedSizeIcon(image: android.graphics.Bitmap): android.graphics.Bitmap {
@@ -702,9 +728,9 @@ export class BottomNavigation extends TabNavigationBase {
702728
const index = tabStripItem._index;
703729
const tabBarItem = this._bottomNavigationBar.getViewForItemAt(index);
704730
const imgView = <android.widget.ImageView>tabBarItem.getChildAt(0);
705-
const drawable = this.getIcon(tabStripItem);
731+
const drawableInfo = this.getIconInfo(tabStripItem);
706732

707-
imgView.setImageDrawable(drawable);
733+
imgView.setImageDrawable(drawableInfo.drawable);
708734
}
709735

710736
public setTabBarItemFontInternal(tabStripItem: TabStripItem, value: Font): void {
@@ -721,6 +747,24 @@ export class BottomNavigation extends TabNavigationBase {
721747
tabStripItem.nativeViewProtected.setText(title);
722748
}
723749

750+
public getTabBarTextTransform(): TextTransform {
751+
return this._textTransform;
752+
}
753+
754+
public setTabBarTextTransform(value: TextTransform): void {
755+
let items = this.tabStrip && this.tabStrip.items;
756+
if (items) {
757+
items.forEach((tabStripItem) => {
758+
if (tabStripItem.label && tabStripItem.nativeViewProtected) {
759+
const nestedLabel = tabStripItem.label;
760+
const title = getTransformedText(nestedLabel.text, value);
761+
tabStripItem.nativeViewProtected.setText(title);
762+
}
763+
});
764+
}
765+
this._textTransform = value;
766+
}
767+
724768
[selectedIndexProperty.setNative](value: number) {
725769
// const smoothScroll = false;
726770

nativescript-core/ui/bottom-navigation/bottom-navigation.ios.ts

Lines changed: 37 additions & 55 deletions
Original file line numberDiff line numberDiff line change
@@ -71,20 +71,19 @@ class UITabBarControllerImpl extends UITabBarController {
7171

7272
public viewWillTransitionToSizeWithTransitionCoordinator(size: CGSize, coordinator: UIViewControllerTransitionCoordinator): void {
7373
super.viewWillTransitionToSizeWithTransitionCoordinator(size, coordinator);
74-
UIViewControllerTransitionCoordinator.prototype.animateAlongsideTransitionCompletion
75-
.call(coordinator, () => {
76-
const owner = this._owner.get();
77-
if (owner && owner.tabStrip && owner.tabStrip.items) {
78-
const tabStrip = owner.tabStrip;
79-
tabStrip.items.forEach(tabStripItem => {
80-
updateBackgroundPositions(tabStrip, tabStripItem);
81-
82-
const index = tabStripItem._index;
83-
const tabBarItemController = this.viewControllers[index];
84-
updateTitleAndIconPositions(tabStripItem, tabBarItemController.tabBarItem, tabBarItemController);
85-
});
86-
}
87-
}, null);
74+
coordinator.animateAlongsideTransitionCompletion(() => {
75+
const owner = this._owner.get();
76+
if (owner && owner.tabStrip && owner.tabStrip.items) {
77+
const tabStrip = owner.tabStrip;
78+
tabStrip.items.forEach(tabStripItem => {
79+
updateBackgroundPositions(tabStrip, tabStripItem);
80+
81+
const index = tabStripItem._index;
82+
const tabBarItemController = this.viewControllers[index];
83+
updateTitleAndIconPositions(tabStripItem, tabBarItemController.tabBarItem, tabBarItemController);
84+
});
85+
}
86+
}, null);
8887
}
8988

9089
// Mind implementation for other controllers
@@ -207,17 +206,14 @@ class UINavigationControllerDelegateImpl extends NSObject implements UINavigatio
207206

208207
function updateBackgroundPositions(tabStrip: TabStrip, tabStripItem: TabStripItem) {
209208
let bgView = (<any>tabStripItem).bgView;
209+
const index = tabStripItem._index;
210+
const width = tabStrip.nativeView.frame.size.width / tabStrip.items.length;
211+
const frame = CGRectMake(width * index, 0, width, tabStrip.nativeView.frame.size.width);
210212
if (!bgView) {
211-
const index = tabStripItem._index;
212-
const width = tabStrip.nativeView.frame.size.width / tabStrip.items.length;
213-
const frame = CGRectMake(width * index, 0, width, tabStrip.nativeView.frame.size.width);
214213
bgView = UIView.alloc().initWithFrame(frame);
215214
tabStrip.nativeView.insertSubviewAtIndex(bgView, 0);
216215
(<any>tabStripItem).bgView = bgView;
217216
} else {
218-
const index = tabStripItem._index;
219-
const width = tabStrip.nativeView.frame.size.width / tabStrip.items.length;
220-
const frame = CGRectMake(width * index, 0, width, tabStrip.nativeView.frame.size.width);
221217
bgView.frame = frame;
222218
}
223219

@@ -376,8 +372,7 @@ export class BottomNavigation extends TabNavigationBase {
376372
}
377373

378374
public setTabBarItemColor(tabStripItem: TabStripItem, value: UIColor | Color): void {
379-
const states = getTitleAttributesForStates(tabStripItem.label);
380-
applyStatesToItem(tabStripItem.nativeView, states, this.viewController.tabBar);
375+
setViewTextAttributes(tabStripItem.nativeView, tabStripItem.label, this.viewController.tabBar);
381376
}
382377

383378
public setTabBarIconColor(tabStripItem: TabStripItem, value: UIColor | Color): void {
@@ -388,15 +383,23 @@ export class BottomNavigation extends TabNavigationBase {
388383
}
389384

390385
public setTabBarItemFontInternal(tabStripItem: TabStripItem, value: Font): void {
391-
const states = getTitleAttributesForStates(tabStripItem.label);
392-
applyStatesToItem(tabStripItem.nativeView, states, this.viewController.tabBar);
386+
setViewTextAttributes(tabStripItem.nativeView, tabStripItem.label, this.viewController.tabBar);
393387
}
394388

395389
public setTabBarItemTextTransform(tabStripItem: TabStripItem, value: TextTransform): void {
396390
const title = getTransformedText(tabStripItem.label.text, value);
397391
tabStripItem.nativeView.title = title;
398392
}
399393

394+
public getTabBarHighlightColor(): UIColor {
395+
return this._ios.tabBar.tintColor;
396+
}
397+
398+
public setTabBarHighlightColor(value: UIColor | Color) {
399+
const nativeColor = value instanceof Color ? value.ios : value;
400+
this._ios.tabBar.tintColor = nativeColor;
401+
}
402+
400403
public onMeasure(widthMeasureSpec: number, heightMeasureSpec: number): void {
401404
const width = layout.getMeasureSpecSize(widthMeasureSpec);
402405
const widthMode = layout.getMeasureSpecMode(widthMeasureSpec);
@@ -518,8 +521,7 @@ export class BottomNavigation extends TabNavigationBase {
518521
const tabBarItem = this.createTabBarItem(tabStripItem, i);
519522
updateTitleAndIconPositions(tabStripItem, tabBarItem, controller);
520523

521-
const states = getTitleAttributesForStates(tabStripItem.label);
522-
applyStatesToItem(tabBarItem, states, this.viewController.tabBar);
524+
setViewTextAttributes(tabBarItem, tabStripItem.label, this.viewController.tabBar);
523525

524526
controller.tabBarItem = tabBarItem;
525527
tabStripItem._index = i;
@@ -688,51 +690,31 @@ export class BottomNavigation extends TabNavigationBase {
688690
}
689691
}
690692

691-
interface TabStates {
692-
normalState?: any;
693-
selectedState?: any;
694-
}
695-
696-
function getTitleAttributesForStates(view: View): TabStates {
693+
function setViewTextAttributes(item: UITabBarItem, view: View, tabBar: UITabBar): any {
697694
if (!view) {
698695
return null;
699696
}
700697

701-
const result: TabStates = {};
702698
const defaultTabItemFontSize = 10;
703699
const tabItemFontSize = view.style.fontSize || defaultTabItemFontSize;
704700
const font: UIFont = view.style.fontInternal.getUIFont(UIFont.systemFontOfSize(tabItemFontSize));
705701
const tabItemTextColor = view.style.color;
706702
const textColor = tabItemTextColor instanceof Color ? tabItemTextColor.ios : null;
707-
result.normalState = { [NSFontAttributeName]: font };
703+
let attributes: any = { [NSFontAttributeName]: font };
708704
if (textColor) {
709-
result.normalState[UITextAttributeTextColor] = textColor;
705+
attributes[UITextAttributeTextColor] = textColor;
706+
attributes[NSForegroundColorAttributeName] = textColor;
710707
}
711708

712-
const tabSelectedItemTextColor = view.style.color;
713-
const selectedTextColor = tabSelectedItemTextColor instanceof Color ? tabSelectedItemTextColor.ios : null;
714-
result.selectedState = { [NSFontAttributeName]: font };
715-
if (selectedTextColor) {
716-
result.selectedState[UITextAttributeTextColor] = selectedTextColor;
717-
}
718-
719-
return result;
720-
}
721-
722-
function applyStatesToItem(item: UITabBarItem, states: TabStates, tabBar: UITabBar) {
723-
if (!states) {
724-
return;
725-
}
726-
727-
item.setTitleTextAttributesForState(states.normalState, UIControlState.Normal);
728-
item.setTitleTextAttributesForState(states.selectedState, UIControlState.Selected);
709+
item.setTitleTextAttributesForState(attributes, UIControlState.Selected);
710+
item.setTitleTextAttributesForState(attributes, UIControlState.Normal);
729711

730712
// there's a bug when setting the item color on ios 13 if there's no background set to the tabstrip
731713
// https://books.google.bg/books?id=99_BDwAAQBAJ&q=tabBar.unselectedItemTintColor
732714
// to fix the above issue we are applying the selected fix only for the case, when there is no background set
733715
// in that case we have the following known issue:
734716
// we will set the color to all unselected items, so you won't be able to set different colors for the different not selected items
735-
if (!tabBar.barTintColor && states.normalState[UITextAttributeTextColor] && (majorVersion > 9)) {
736-
tabBar.unselectedItemTintColor = states.normalState[UITextAttributeTextColor];
717+
if (!tabBar.barTintColor && attributes[UITextAttributeTextColor] && (majorVersion > 9)) {
718+
tabBar.unselectedItemTintColor = attributes[UITextAttributeTextColor];
737719
}
738-
}
720+
}

0 commit comments

Comments
 (0)