Skip to content

Commit 3a0afdb

Browse files
authored
feat(SegmentedBar): selectedTextColor added and selectedBackgroundColor improvements (#10474)
1 parent 135d37b commit 3a0afdb

10 files changed

Lines changed: 197 additions & 11 deletions

File tree

apps/automated/src/ui/segmented-bar/segmented-bar-tests-native.android.ts

Lines changed: 56 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -1,4 +1,9 @@
11
import * as segmentedBarModule from '@nativescript/core/ui/segmented-bar';
2+
import { Color } from '@nativescript/core';
3+
4+
export function getNativeTabWidget(bar: segmentedBarModule.SegmentedBar): android.widget.TabWidget {
5+
return (<android.widget.TabHost>bar.android).getTabWidget();
6+
}
27

38
export function getNativeItemsCount(bar: segmentedBarModule.SegmentedBar): number {
49
return (<android.widget.TabHost>bar.android).getTabWidget().getTabCount();
@@ -25,3 +30,54 @@ export function checkNativeItemsTextColor(bar: segmentedBarModule.SegmentedBar):
2530
export function setNativeSelectedIndex(bar: segmentedBarModule.SegmentedBar, index: number): void {
2631
(<android.widget.TabHost>bar.android).setCurrentTab(index);
2732
}
33+
34+
export var checkBackgroundColorUpdatedAfterItemSelected = function (bar: segmentedBarModule.SegmentedBar): boolean {
35+
let isValid = 0;
36+
bar.selectedIndex = 0;
37+
bar.selectedTextColor = new Color('green');
38+
bar.selectedBackgroundColor = new Color('red');
39+
40+
const tabWidget = getNativeTabWidget(bar);
41+
if (tabWidget) {
42+
for (let i = 0; i < tabWidget.getTabCount(); i++) {
43+
const view = tabWidget.getChildTabViewAt(i);
44+
const item = bar.items[i];
45+
const textView = item?.nativeViewProtected;
46+
47+
const newDrawable = tryCloneDrawable(view.getBackground(), view.getResources());
48+
newDrawable.setColorFilter(new android.graphics.Paint(bar.selectedBackgroundColor.android).getColorFilter());
49+
50+
if (bar.selectedIndex == i) {
51+
if (view.getBackground() !== newDrawable) {
52+
console.log('>>>>>>>>>>>>>>>>>>>>>> newDrawable', view.getBackground());
53+
console.log('>>>>>>>>>>>>>>>>>>>>>> bar.selectedBackgroundColor.android', newDrawable);
54+
console.log('>>>>>>>>>>>>>>>>>>>>>> selectedBackgroundColor', newDrawable.getColorFilter(), view.getBackground().getColorFilter());
55+
console.log('>>>>>>>>>>>>>>>>>>>>>> selectedBackgroundColor', newDrawable.hashCode(), view.hashCode());
56+
57+
isValid++;
58+
break;
59+
} else if (textView.getCurrentTextColor() !== bar.selectedTextColor) {
60+
console.log('>>>>>>>>>>>>>>>>>>>>>>');
61+
console.log('>>>>>>>>>>>>>>>>>>>>>>');
62+
console.log('>>>>>>>>>>>>>>>>>>>>>> selectedTextColor');
63+
64+
isValid++;
65+
break;
66+
}
67+
}
68+
}
69+
}
70+
71+
function tryCloneDrawable(value: android.graphics.drawable.Drawable, resources: android.content.res.Resources): android.graphics.drawable.Drawable {
72+
if (value) {
73+
const constantState = value.getConstantState();
74+
if (constantState) {
75+
return constantState.newDrawable(resources);
76+
}
77+
}
78+
79+
return value;
80+
}
81+
82+
return isValid === 0;
83+
};

apps/automated/src/ui/segmented-bar/segmented-bar-tests-native.d.ts

Lines changed: 2 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -5,3 +5,5 @@ export declare function getNativeItemsCount(bar: segmentedBarModule.SegmentedBar
55
export declare function setNativeSelectedIndex(bar: segmentedBarModule.SegmentedBar, index: number): void;
66

77
export declare function checkNativeItemsTextColor(bar: segmentedBarModule.SegmentedBar): boolean;
8+
9+
export declare function checkBackgroundColorUpdatedAfterItemSelected(bar: segmentedBarModule.SegmentedBar): boolean;

apps/automated/src/ui/segmented-bar/segmented-bar-tests.ts

Lines changed: 18 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -276,3 +276,21 @@ export function test_SettingNumberAsTitleFromXML_DoesNotThrow() {
276276
TKUnit.assertEqual(item.title, '1');
277277
});
278278
}
279+
280+
/*export function testBackgroundColorUpdatedAfterItemSelected() {
281+
let segmentedBar = new segmentedBarModule.SegmentedBar();
282+
let item1 = new segmentedBarModule.SegmentedBarItem();
283+
(<any>item1).title = 1;
284+
let item2 = new segmentedBarModule.SegmentedBarItem();
285+
(<any>item2).title = 2;
286+
let item3 = new segmentedBarModule.SegmentedBarItem();
287+
(<any>item3).title = 3;
288+
let item4 = new segmentedBarModule.SegmentedBarItem();
289+
(<any>item4).title = 4;
290+
291+
segmentedBar.items = [item1, item2, item3, item4];
292+
293+
buildUIAndRunTest(segmentedBar, function (views: Array<View>) {
294+
TKUnit.assertTrue(segmentedBarTestsNative.checkBackgroundColorUpdatedAfterItemSelected(segmentedBar));
295+
});
296+
}*/

apps/ui/src/segmented-bar/all-page.xml

Lines changed: 14 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -7,7 +7,20 @@
77
<SegmentedBarItem title="Item 3" />
88
</SegmentedBar.items>
99
</SegmentedBar>
10-
<SegmentedBar selectedIndex="2" style="margin: 5; color: blue; background-color: yellow; font-weight: bold; font-size: 20; font-style: italic; font-family: monospace; height: 72; border-width: 2; border-radius: 7; border-color:green; selected-background-color: red;">
10+
<SegmentedBar selectedIndex="2" style="margin: 5; color: blue; background-color: yellow; font-weight: bold; font-size: 20; font-style: italic; font-family: monospace; height: 72; border-width: 2; border-radius: 7; border-color:green; selected-background-color: red;selected-text-color: green">
11+
<SegmentedBar.items>
12+
<SegmentedBarItem title="Item 1" />
13+
<SegmentedBarItem title="Item 2" />
14+
<SegmentedBarItem title="Item 3" />
15+
</SegmentedBar.items>
16+
</SegmentedBar>
17+
<SegmentedBar selectedIndex="2"
18+
selectedTextColor="#00ffd9"
19+
color="red"
20+
android:backgroundColor="#A8A8A8"
21+
selectedBackgroundColor="blue"
22+
android:borderRadius="6"
23+
>
1124
<SegmentedBar.items>
1225
<SegmentedBarItem title="Item 1" />
1326
<SegmentedBarItem title="Item 2" />

packages/core/ui/segmented-bar/index.android.ts

Lines changed: 48 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -1,10 +1,11 @@
11
import { Font } from '../styling/font';
2-
import { SegmentedBarItemBase, SegmentedBarBase, selectedIndexProperty, itemsProperty, selectedBackgroundColorProperty } from './segmented-bar-common';
2+
import { SegmentedBarItemBase, SegmentedBarBase, selectedIndexProperty, itemsProperty, selectedBackgroundColorProperty, selectedTextColorProperty } from './segmented-bar-common';
33
import { isEnabledProperty } from '../core/view';
44
import { colorProperty, fontInternalProperty, fontSizeProperty } from '../styling/style-properties';
55
import { Color } from '../../color';
66
import { layout } from '../../utils';
77
import { SDK_VERSION } from '../../utils/constants';
8+
import { Trace } from '../../trace';
89

910
export * from './segmented-bar-common';
1011

@@ -51,8 +52,13 @@ function initializeNativeClasses(): void {
5152

5253
onTabChanged(id: string): void {
5354
const owner = this.owner;
54-
if (owner.shouldChangeSelectedIndex()) {
55-
owner.selectedIndex = parseInt(id);
55+
if (owner) {
56+
setTimeout(() => {
57+
owner.setTabColor(id);
58+
});
59+
if (owner.shouldChangeSelectedIndex()) {
60+
owner.selectedIndex = parseInt(id);
61+
}
5662
}
5763
}
5864
}
@@ -165,7 +171,7 @@ export class SegmentedBarItem extends SegmentedBarItemBase {
165171
const backgroundDrawable = viewGroup.getBackground();
166172
if (SDK_VERSION > 21 && backgroundDrawable) {
167173
const newDrawable = tryCloneDrawable(backgroundDrawable, nativeView.getResources());
168-
newDrawable.setColorFilter(color, android.graphics.PorterDuff.Mode.SRC_IN);
174+
newDrawable.setColorFilter(new android.graphics.Paint(color).getColorFilter());
169175
viewGroup.setBackground(newDrawable);
170176
} else {
171177
const stateDrawable = new android.graphics.drawable.StateListDrawable();
@@ -292,4 +298,42 @@ export class SegmentedBar extends SegmentedBarBase {
292298
tabWidget.setEnabled(value);
293299
}
294300
}
301+
public setTabColor(index) {
302+
try {
303+
const tabWidget = this.nativeViewProtected?.getTabWidget();
304+
if (tabWidget) {
305+
const unselectedTextColor = this.getColorForAndroid(this.color ?? '#6e6e6e');
306+
const selectedTextColor = this.getColorForAndroid(this?.selectedTextColor ?? '#000000');
307+
const unselectedBackgroundColor = this.getColorForAndroid(this?.backgroundColor ?? '#dbdbdb');
308+
const selectedBackgroundColor = this.getColorForAndroid(this?.selectedBackgroundColor ?? this?.backgroundColor ?? 'blue');
309+
if (tabWidget) {
310+
for (let i = 0; i < tabWidget.getTabCount(); i++) {
311+
const view = tabWidget.getChildTabViewAt(i);
312+
const item = this.items[i];
313+
const textView = item?.nativeViewProtected;
314+
view.setBackgroundColor(unselectedBackgroundColor);
315+
if (textView) {
316+
textView.setTextColor(unselectedTextColor);
317+
}
318+
if (index == i) {
319+
view.setBackgroundColor(selectedBackgroundColor);
320+
if (textView) {
321+
textView.setTextColor(selectedTextColor);
322+
}
323+
continue;
324+
}
325+
}
326+
}
327+
}
328+
} catch (e) {
329+
Trace.error(e);
330+
}
331+
}
332+
private getColorForAndroid(color: string | Color): number {
333+
if (typeof color === 'string') {
334+
return new Color(color).android;
335+
} else if (color instanceof Color) {
336+
return color.android;
337+
}
338+
}
295339
}

packages/core/ui/segmented-bar/index.d.ts

Lines changed: 10 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -44,6 +44,11 @@ export class SegmentedBar extends View implements AddChildFromBuilder, AddArrayF
4444
*/
4545
selectedBackgroundColor: Color;
4646

47+
/**
48+
* Gets or sets the selected text color of the SegmentedBar component.
49+
*/
50+
selectedTextColor: Color;
51+
4752
/**
4853
* Gets or sets the items of the SegmentedBar.
4954
*/
@@ -90,3 +95,8 @@ export const selectedBackgroundColorProperty: CssProperty<Style, Color>;
9095
* Gets or sets the items dependency property of the SegmentedBar.
9196
*/
9297
export const itemsProperty: Property<SegmentedBar, SegmentedBarItem[]>;
98+
99+
/**
100+
* Gets or sets the selected text color property of the SegmentedBar.
101+
*/
102+
export const selectedTextColorProperty: CssProperty<Style, Color>;

packages/core/ui/segmented-bar/index.ios.ts

Lines changed: 28 additions & 6 deletions
Original file line numberDiff line numberDiff line change
@@ -2,7 +2,8 @@ import { Font } from '../styling/font';
22
import { SegmentedBarItemBase, SegmentedBarBase, selectedIndexProperty, itemsProperty, selectedBackgroundColorProperty } from './segmented-bar-common';
33
import { colorProperty, fontInternalProperty } from '../styling/style-properties';
44
import { Color } from '../../color';
5-
import { iOSNativeHelper } from '../../utils';
5+
import { Trace } from '../../trace';
6+
import { SDK_VERSION } from '../../utils';
67
export * from './segmented-bar-common';
78

89
export class SegmentedBarItem extends SegmentedBarItemBase {
@@ -68,14 +69,11 @@ export class SegmentedBar extends SegmentedBarBase {
6869
}
6970

7071
[selectedBackgroundColorProperty.getDefault](): UIColor {
71-
const currentOsVersion = iOSNativeHelper.MajorVersion;
72-
73-
return currentOsVersion < 13 ? this.ios.tintColor : this.ios.selectedSegmentTintColor;
72+
return SDK_VERSION < 13 ? this.ios.tintColor : this.ios.selectedSegmentTintColor;
7473
}
7574
[selectedBackgroundColorProperty.setNative](value: UIColor | Color) {
76-
const currentOsVersion = iOSNativeHelper.MajorVersion;
7775
const color = value instanceof Color ? value.ios : value;
78-
if (currentOsVersion < 13) {
76+
if (SDK_VERSION < 13) {
7977
this.ios.tintColor = color;
8078
} else {
8179
this.ios.selectedSegmentTintColor = color;
@@ -92,6 +90,8 @@ export class SegmentedBar extends SegmentedBarBase {
9290
const attrs = currentAttrs ? currentAttrs.mutableCopy() : NSMutableDictionary.new();
9391
attrs.setValueForKey(color, NSForegroundColorAttributeName);
9492
bar.setTitleTextAttributesForState(attrs, UIControlState.Normal);
93+
// Set the selected text color
94+
this.setSelectedTextColor(bar);
9595
}
9696

9797
[fontInternalProperty.getDefault](): Font {
@@ -105,6 +105,27 @@ export class SegmentedBar extends SegmentedBarBase {
105105
attrs.setValueForKey(font, NSFontAttributeName);
106106
bar.setTitleTextAttributesForState(attrs, UIControlState.Normal);
107107
}
108+
setSelectedTextColor(bar: UISegmentedControl) {
109+
try {
110+
const selectedTextColor = this.getColorForIOS(this?.selectedTextColor ?? this?.color ?? '#000000');
111+
if (!selectedTextColor) {
112+
Trace.write(`unable te set selectedTextColor`, Trace.categories.Error);
113+
}
114+
const selectedText = bar.titleTextAttributesForState(UIControlState.Selected);
115+
const attrsSelected = selectedText ? selectedText.mutableCopy() : NSMutableDictionary.new();
116+
attrsSelected.setValueForKey(selectedTextColor, NSForegroundColorAttributeName);
117+
bar.setTitleTextAttributesForState(attrsSelected, UIControlState.Selected);
118+
} catch (e) {
119+
console.error(`SegmentedBar:`, e);
120+
}
121+
}
122+
private getColorForIOS(color: string | Color): UIColor {
123+
if (typeof color === 'string') {
124+
return new Color(color).ios;
125+
} else if (color instanceof Color) {
126+
return color.ios;
127+
}
128+
}
108129
}
109130

110131
@NativeClass
@@ -122,6 +143,7 @@ class SelectionHandlerImpl extends NSObject {
122143
const owner = this._owner?.deref();
123144
if (owner) {
124145
owner.selectedIndex = sender.selectedSegmentIndex;
146+
owner.setSelectedTextColor(sender);
125147
}
126148
}
127149

packages/core/ui/segmented-bar/segmented-bar-common.ts

Lines changed: 17 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -38,6 +38,13 @@ export abstract class SegmentedBarBase extends View implements SegmentedBarDefin
3838
this.style.selectedBackgroundColor = value;
3939
}
4040

41+
public get selectedTextColor(): Color {
42+
return this.style.selectedTabTextColor;
43+
}
44+
public set selectedTextColor(value: Color) {
45+
this.style.selectedTabTextColor = value;
46+
}
47+
4148
public _addArrayFromBuilder(name: string, value: Array<any>): void {
4249
if (name === 'items') {
4350
this.items = value;
@@ -141,6 +148,16 @@ export const selectedBackgroundColorProperty = new InheritedCssProperty<Style, C
141148
name: 'selectedBackgroundColor',
142149
cssName: 'selected-background-color',
143150
equalityComparer: Color.equals,
151+
defaultValue: new Color('blue'),
144152
valueConverter: (v) => new Color(v),
145153
});
146154
selectedBackgroundColorProperty.register(Style);
155+
156+
export const selectedTextColorProperty = new InheritedCssProperty<Style, Color>({
157+
name: 'selectedTextColor',
158+
cssName: 'selected-text-color',
159+
equalityComparer: Color.equals,
160+
defaultValue: new Color('black'),
161+
valueConverter: (v) => new Color(v),
162+
});
163+
selectedTextColorProperty.register(Style);

packages/core/ui/styling/style/index.ts

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -206,6 +206,7 @@ export class Style extends Observable implements StyleDefinition {
206206

207207
//SegmentedBar-specific props
208208
public selectedBackgroundColor: Color;
209+
public selectedTextColor: Color;
209210

210211
// Page-specific props
211212
public statusBarStyle: 'light' | 'dark';

packages/core/utils/ios/index.ts

Lines changed: 3 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -94,6 +94,9 @@ export function isLandscape(): boolean {
9494
return isDeviceOrientationLandscape || isStatusBarOrientationLandscape;
9595
}
9696

97+
/**
98+
* @deprecated use Utils.SDK_VERSION instead which is a float of the {major}.{minor} verison
99+
*/
97100
export const MajorVersion = NSString.stringWithString(UIDevice.currentDevice.systemVersion).intValue;
98101

99102
export function openFile(filePath: string): boolean {

0 commit comments

Comments
 (0)