Skip to content

Commit 66d8aff

Browse files
wSedlacekwSedlacek
authored andcommitted
feat(android): tab view icon rendering mode (#9605)
Co-authored-by: wSedlacek <wsedlacekc@gmail.com>
1 parent 08028dd commit 66d8aff

File tree

9 files changed

+104
-11
lines changed

9 files changed

+104
-11
lines changed
Lines changed: 9 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -1,21 +1,27 @@
1+
import { isIOS } from '@nativescript/core';
12
import { EventData } from '@nativescript/core/data/observable';
23
import { Button } from '@nativescript/core/ui/button';
34
import { TabView } from '@nativescript/core/ui/tab-view';
45

5-
let iconModes = ['automatic', 'alwaysOriginal', 'alwaysTemplate', undefined];
6+
let iconModes = isIOS ? ['automatic', 'alwaysOriginal', 'alwaysTemplate', undefined] : ['alwaysOriginal', 'alwaysTemplate', undefined];
67

78
export const onNavigate = updateButtons;
89

910
export function onChangeRenderingMode(args: EventData) {
1011
let tabView = (<Button>args.object).page.getViewById<TabView>('tab-view');
11-
tabView.iosIconRenderingMode = <'automatic' | 'alwaysOriginal' | 'alwaysTemplate'>iconModes[(iconModes.indexOf(tabView.iosIconRenderingMode) + 1) % iconModes.length];
12+
if (isIOS) {
13+
tabView.iosIconRenderingMode = <'automatic' | 'alwaysOriginal' | 'alwaysTemplate'>iconModes[(iconModes.indexOf(tabView.iosIconRenderingMode) + 1) % iconModes.length];
14+
} else {
15+
tabView.androidIconRenderingMode = <'alwaysOriginal' | 'alwaysTemplate'>iconModes[(iconModes.indexOf(tabView.androidIconRenderingMode) + 1) % iconModes.length];
16+
}
1217
updateButtons(args);
1318
}
1419

1520
function updateButtons(args) {
1621
let button = <Button>args.object;
1722
let tabView = button.page.getViewById<TabView>('tab-view');
1823
for (let i = 0, length = tabView.items.length; i < length; i++) {
19-
(<Button>tabView.items[i].view).text = '' + tabView.iosIconRenderingMode;
24+
const value = isIOS ? tabView.iosIconRenderingMode : tabView.androidIconRenderingMode;
25+
(<Button>tabView.items[i].view).text = '' + value;
2026
}
2127
}
Lines changed: 9 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -1,21 +1,27 @@
1+
import { isIOS } from '@nativescript/core';
12
import { EventData } from '@nativescript/core/data/observable';
23
import { Button } from '@nativescript/core/ui/button';
34
import { TabView } from '@nativescript/core/ui/tab-view';
45

5-
let iconModes = ['automatic', 'alwaysOriginal', 'alwaysTemplate', undefined];
6+
let iconModes = isIOS ? ['automatic', 'alwaysOriginal', 'alwaysTemplate', undefined] : ['alwaysOriginal', 'alwaysTemplate', undefined];
67

78
export const onNavigate = updateButtons;
89

910
export function onChangeRenderingMode(args: EventData) {
1011
let tabView = (<Button>args.object).page.getViewById<TabView>('tab-view');
11-
tabView.iosIconRenderingMode = <'automatic' | 'alwaysOriginal' | 'alwaysTemplate'>iconModes[(iconModes.indexOf(tabView.iosIconRenderingMode) + 1) % iconModes.length];
12+
if (isIOS) {
13+
tabView.iosIconRenderingMode = <'automatic' | 'alwaysOriginal' | 'alwaysTemplate'>iconModes[(iconModes.indexOf(tabView.iosIconRenderingMode) + 1) % iconModes.length];
14+
} else {
15+
tabView.androidIconRenderingMode = <'alwaysOriginal' | 'alwaysTemplate'>iconModes[(iconModes.indexOf(tabView.androidIconRenderingMode) + 1) % iconModes.length];
16+
}
1217
updateButtons(args);
1318
}
1419

1520
function updateButtons(args) {
1621
let button = <Button>args.object;
1722
let tabView = button.page.getViewById<TabView>('tab-view');
1823
for (let i = 0, length = tabView.items.length; i < length; i++) {
19-
(<Button>tabView.items[i].view).text = '' + tabView.iosIconRenderingMode;
24+
const value = isIOS ? tabView.iosIconRenderingMode : tabView.androidIconRenderingMode;
25+
(<Button>tabView.items[i].view).text = '' + value;
2026
}
2127
}

packages/core/ui/tab-view/index.android.ts

Lines changed: 18 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -1,7 +1,7 @@
11
import { TabViewItem as TabViewItemDefinition } from '.';
22
import { Font } from '../styling/font';
33

4-
import { TabViewBase, TabViewItemBase, itemsProperty, selectedIndexProperty, tabTextColorProperty, tabBackgroundColorProperty, tabTextFontSizeProperty, selectedTabTextColorProperty, androidSelectedTabHighlightColorProperty, androidOffscreenTabLimitProperty, traceCategory, traceMissingIcon } from './tab-view-common';
4+
import { TabViewBase, TabViewItemBase, itemsProperty, selectedIndexProperty, tabTextColorProperty, tabBackgroundColorProperty, tabTextFontSizeProperty, selectedTabTextColorProperty, androidSelectedTabHighlightColorProperty, androidOffscreenTabLimitProperty, traceCategory, traceMissingIcon, androidIconRenderingModeProperty } from './tab-view-common';
55
import { textTransformProperty, getTransformedText } from '../text-base';
66
import { CoreTypes } from '../../core-types';
77
import { ImageSource } from '../../image-source';
@@ -699,6 +699,16 @@ export class TabView extends TabViewBase {
699699
}
700700
}
701701

702+
private getNativeRenderingMode(mode: 'alwaysOriginal' | 'alwaysTemplate'): number {
703+
switch (mode) {
704+
case 'alwaysTemplate':
705+
return org.nativescript.widgets.TabIconRenderingMode.template;
706+
default:
707+
case 'alwaysOriginal':
708+
return org.nativescript.widgets.TabIconRenderingMode.original;
709+
}
710+
}
711+
702712
public updateAndroidItemAt(index: number, spec: org.nativescript.widgets.TabItemSpec) {
703713
this._tabLayout.updateItemAt(index, spec);
704714
}
@@ -710,6 +720,13 @@ export class TabView extends TabViewBase {
710720
this._viewPager.setOffscreenPageLimit(value);
711721
}
712722

723+
[androidIconRenderingModeProperty.getDefault](): 'alwaysOriginal' | 'alwaysTemplate' {
724+
return 'alwaysOriginal';
725+
}
726+
[androidIconRenderingModeProperty.setNative](value: 'alwaysOriginal' | 'alwaysTemplate') {
727+
this._tabLayout.setIconRenderingMode(this.getNativeRenderingMode(value));
728+
}
729+
713730
[selectedIndexProperty.setNative](value: number) {
714731
const smoothScroll = this.androidTabsPosition === 'top';
715732

packages/core/ui/tab-view/index.d.ts

Lines changed: 9 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -112,6 +112,14 @@ export class TabView extends View {
112112
*/
113113
iosIconRenderingMode: 'automatic' | 'alwaysOriginal' | 'alwaysTemplate';
114114

115+
/**
116+
* Gets or sets the rendering mode of tab icons on Android. Defaults to "original"
117+
* Valid values are:
118+
* - alwaysOriginal
119+
* - alwaysTemplate
120+
*/
121+
androidIconRenderingMode: 'alwaysOriginal' | 'alwaysTemplate';
122+
115123
/**
116124
* Gets or sets the number of tabs that should be retained to either side of the current tab in the view hierarchy in an idle state.
117125
* Tabs beyond this limit will be recreated from the TabView when needed.
@@ -160,3 +168,4 @@ export const selectedTabTextColorProperty: CssProperty<Style, Color>;
160168
export const androidSelectedTabHighlightColorProperty: CssProperty<Style, Color>;
161169
export const androidOffscreenTabLimitProperty: Property<TabView, number>;
162170
export const iosIconRenderingModeProperty: Property<TabView, 'automatic' | 'alwaysOriginal' | 'alwaysTemplate'>;
171+
export const androidIconRenderingModeProperty: Property<TabView, 'alwaysOriginal' | 'alwaysTemplate'>;

packages/core/ui/tab-view/tab-view-common.ts

Lines changed: 4 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -93,6 +93,7 @@ export class TabViewBase extends View implements TabViewDefinition, AddChildFrom
9393
public androidTabsPosition: 'top' | 'bottom';
9494
public androidSwipeEnabled: boolean;
9595
public iosIconRenderingMode: 'automatic' | 'alwaysOriginal' | 'alwaysTemplate';
96+
public androidIconRenderingMode: 'alwaysOriginal' | 'alwaysTemplate';
9697

9798
get androidSelectedTabHighlightColor(): Color {
9899
return this.style.androidSelectedTabHighlightColor;
@@ -250,6 +251,9 @@ itemsProperty.register(TabViewBase);
250251
export const iosIconRenderingModeProperty = new Property<TabViewBase, 'automatic' | 'alwaysOriginal' | 'alwaysTemplate'>({ name: 'iosIconRenderingMode', defaultValue: 'automatic' });
251252
iosIconRenderingModeProperty.register(TabViewBase);
252253

254+
export const androidIconRenderingModeProperty = new Property<TabViewBase, 'alwaysOriginal' | 'alwaysTemplate'>({ name: 'androidIconRenderingMode', defaultValue: 'alwaysOriginal' });
255+
androidIconRenderingModeProperty.register(TabViewBase);
256+
253257
export const androidOffscreenTabLimitProperty = new Property<TabViewBase, number>({
254258
name: 'androidOffscreenTabLimit',
255259
defaultValue: 1,

packages/types-android/src/lib/android/org.nativescript.widgets.d.ts

Lines changed: 7 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -394,13 +394,20 @@
394394
setImageLoadedListener(listener: image.Worker.OnImageLoadedListener): void;
395395
}
396396

397+
export enum TabIconRenderingMode {
398+
original,
399+
template
400+
}
401+
397402
export class TabLayout extends android.widget.HorizontalScrollView {
398403
constructor(context: android.content.Context);
399404
constructor(context: android.content.Context, attrs: android.util.AttributeSet);
400405
constructor(context: android.content.Context, attrs: android.util.AttributeSet, defStyle: number);
401406

402407
setSelectedIndicatorColors(color: Array<number>): void;
403408
getSelectedIndicatorColors(): Array<number>;
409+
setIconRenderingMode(mode: TabIconRenderingMode): void;
410+
getIconRenderingMode(): TabIconRenderingMode;
404411
setTabTextColor(color: number): void;
405412
getTabTextColor(): number;
406413
setSelectedTabTextColor(color: number): void;
Lines changed: 6 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,6 @@
1+
package org.nativescript.widgets;
2+
3+
public enum TabIconRenderingMode {
4+
template,
5+
original
6+
}

packages/ui-mobile-base/android/widgets/src/main/java/org/nativescript/widgets/TabLayout.java

Lines changed: 8 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -131,6 +131,14 @@ public int[] getSelectedIndicatorColors() {
131131
return this.mSelectedIndicatorColors;
132132
}
133133

134+
public void setIconRenderingMode(TabIconRenderingMode mode) {
135+
mTabStrip.setIconRenderingMode(mode);
136+
}
137+
138+
public TabIconRenderingMode getIconRenderingMode() {
139+
return mTabStrip.getIconRenderingMode();
140+
}
141+
134142
public void setTabTextColor(int color){
135143
mTabStrip.setTabTextColor(color);
136144
}

packages/ui-mobile-base/android/widgets/src/main/java/org/nativescript/widgets/TabStrip.java

Lines changed: 34 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -18,6 +18,7 @@
1818

1919

2020
import android.content.Context;
21+
import android.content.res.ColorStateList;
2122
import android.graphics.Canvas;
2223
import android.graphics.Color;
2324
import android.graphics.Paint;
@@ -26,6 +27,9 @@
2627
import android.view.View;
2728
import android.widget.LinearLayout;
2829
import android.widget.TextView;
30+
import android.widget.ImageView;
31+
32+
import androidx.core.widget.ImageViewCompat;
2933

3034
class TabStrip extends LinearLayout {
3135

@@ -51,6 +55,7 @@ class TabStrip extends LinearLayout {
5155
private int mTabTextColor;
5256
private int mSelectedTabTextColor;
5357
private float mTabTextFontSize;
58+
private TabIconRenderingMode mIconRenderingMode;
5459

5560
private boolean mShouldUpdateTabsTextColor;
5661

@@ -88,6 +93,7 @@ class TabStrip extends LinearLayout {
8893

8994
// Default selected color is the same as mTabTextColor
9095
mSelectedTabTextColor = mTabTextColor;
96+
mIconRenderingMode = TabIconRenderingMode.original;
9197

9298
mShouldUpdateTabsTextColor = true;
9399

@@ -106,6 +112,15 @@ void setSelectedIndicatorColors(int... colors) {
106112
invalidate();
107113
}
108114

115+
void setIconRenderingMode(TabIconRenderingMode mode) {
116+
mIconRenderingMode = mode;
117+
updateTabsTextColor();
118+
}
119+
120+
TabIconRenderingMode getIconRenderingMode() {
121+
return mIconRenderingMode;
122+
}
123+
109124
void setTabTextColor(int color){
110125
mTabTextColor = color;
111126
updateTabsTextColor();
@@ -128,16 +143,31 @@ void setShouldUpdateTabsTextColor(boolean value) {
128143
mShouldUpdateTabsTextColor = value;
129144
}
130145

131-
private void updateTabsTextColor(){
146+
private void updateTabsTextColor() {
132147
if (mShouldUpdateTabsTextColor) {
133148
final int childCount = getChildCount();
149+
int greyColor = Color.parseColor("#A2A2A2");
134150
for (int i = 0; i < childCount; i++){
135151
LinearLayout linearLayout = (LinearLayout)getChildAt(i);
152+
ImageView imageView = (ImageView)linearLayout.getChildAt(0);
136153
TextView textView = (TextView)linearLayout.getChildAt(1);
137-
if (i == mSelectedPosition){
138-
textView.setTextColor(mSelectedTabTextColor);
154+
155+
if (mIconRenderingMode == TabIconRenderingMode.template) {
156+
ColorStateList tint;
157+
if (i == mSelectedPosition) {
158+
tint = ColorStateList.valueOf(mSelectedTabTextColor);
159+
} else {
160+
tint = ColorStateList.valueOf(greyColor);
161+
}
162+
163+
ImageViewCompat.setImageTintList(imageView, tint);
164+
} else {
165+
ImageViewCompat.setImageTintList(imageView, null);
139166
}
140-
else {
167+
168+
if (i == mSelectedPosition) {
169+
textView.setTextColor(mSelectedTabTextColor);
170+
} else {
141171
textView.setTextColor(mTabTextColor);
142172
}
143173
}

0 commit comments

Comments
 (0)