Skip to content

Commit

Permalink
feat(SegmentedBar): selectedTextColor added and selectedBackgroundCol…
Browse files Browse the repository at this point in the history
…or improvements (#10474)
  • Loading branch information
kefahB committed Jan 19, 2024
1 parent 135d37b commit 3a0afdb
Show file tree
Hide file tree
Showing 10 changed files with 197 additions and 11 deletions.
@@ -1,4 +1,9 @@
import * as segmentedBarModule from '@nativescript/core/ui/segmented-bar';
import { Color } from '@nativescript/core';

export function getNativeTabWidget(bar: segmentedBarModule.SegmentedBar): android.widget.TabWidget {
return (<android.widget.TabHost>bar.android).getTabWidget();
}

export function getNativeItemsCount(bar: segmentedBarModule.SegmentedBar): number {
return (<android.widget.TabHost>bar.android).getTabWidget().getTabCount();
Expand All @@ -25,3 +30,54 @@ export function checkNativeItemsTextColor(bar: segmentedBarModule.SegmentedBar):
export function setNativeSelectedIndex(bar: segmentedBarModule.SegmentedBar, index: number): void {
(<android.widget.TabHost>bar.android).setCurrentTab(index);
}

export var checkBackgroundColorUpdatedAfterItemSelected = function (bar: segmentedBarModule.SegmentedBar): boolean {
let isValid = 0;
bar.selectedIndex = 0;
bar.selectedTextColor = new Color('green');
bar.selectedBackgroundColor = new Color('red');

const tabWidget = getNativeTabWidget(bar);
if (tabWidget) {
for (let i = 0; i < tabWidget.getTabCount(); i++) {
const view = tabWidget.getChildTabViewAt(i);
const item = bar.items[i];
const textView = item?.nativeViewProtected;

const newDrawable = tryCloneDrawable(view.getBackground(), view.getResources());
newDrawable.setColorFilter(new android.graphics.Paint(bar.selectedBackgroundColor.android).getColorFilter());

if (bar.selectedIndex == i) {
if (view.getBackground() !== newDrawable) {
console.log('>>>>>>>>>>>>>>>>>>>>>> newDrawable', view.getBackground());
console.log('>>>>>>>>>>>>>>>>>>>>>> bar.selectedBackgroundColor.android', newDrawable);
console.log('>>>>>>>>>>>>>>>>>>>>>> selectedBackgroundColor', newDrawable.getColorFilter(), view.getBackground().getColorFilter());
console.log('>>>>>>>>>>>>>>>>>>>>>> selectedBackgroundColor', newDrawable.hashCode(), view.hashCode());

isValid++;
break;
} else if (textView.getCurrentTextColor() !== bar.selectedTextColor) {
console.log('>>>>>>>>>>>>>>>>>>>>>>');
console.log('>>>>>>>>>>>>>>>>>>>>>>');
console.log('>>>>>>>>>>>>>>>>>>>>>> selectedTextColor');

isValid++;
break;
}
}
}
}

function tryCloneDrawable(value: android.graphics.drawable.Drawable, resources: android.content.res.Resources): android.graphics.drawable.Drawable {
if (value) {
const constantState = value.getConstantState();
if (constantState) {
return constantState.newDrawable(resources);
}
}

return value;
}

return isValid === 0;
};
Expand Up @@ -5,3 +5,5 @@ export declare function getNativeItemsCount(bar: segmentedBarModule.SegmentedBar
export declare function setNativeSelectedIndex(bar: segmentedBarModule.SegmentedBar, index: number): void;

export declare function checkNativeItemsTextColor(bar: segmentedBarModule.SegmentedBar): boolean;

export declare function checkBackgroundColorUpdatedAfterItemSelected(bar: segmentedBarModule.SegmentedBar): boolean;
18 changes: 18 additions & 0 deletions apps/automated/src/ui/segmented-bar/segmented-bar-tests.ts
Expand Up @@ -276,3 +276,21 @@ export function test_SettingNumberAsTitleFromXML_DoesNotThrow() {
TKUnit.assertEqual(item.title, '1');
});
}

/*export function testBackgroundColorUpdatedAfterItemSelected() {
let segmentedBar = new segmentedBarModule.SegmentedBar();
let item1 = new segmentedBarModule.SegmentedBarItem();
(<any>item1).title = 1;
let item2 = new segmentedBarModule.SegmentedBarItem();
(<any>item2).title = 2;
let item3 = new segmentedBarModule.SegmentedBarItem();
(<any>item3).title = 3;
let item4 = new segmentedBarModule.SegmentedBarItem();
(<any>item4).title = 4;
segmentedBar.items = [item1, item2, item3, item4];
buildUIAndRunTest(segmentedBar, function (views: Array<View>) {
TKUnit.assertTrue(segmentedBarTestsNative.checkBackgroundColorUpdatedAfterItemSelected(segmentedBar));
});
}*/
15 changes: 14 additions & 1 deletion apps/ui/src/segmented-bar/all-page.xml
Expand Up @@ -7,7 +7,20 @@
<SegmentedBarItem title="Item 3" />
</SegmentedBar.items>
</SegmentedBar>
<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;">
<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">
<SegmentedBar.items>
<SegmentedBarItem title="Item 1" />
<SegmentedBarItem title="Item 2" />
<SegmentedBarItem title="Item 3" />
</SegmentedBar.items>
</SegmentedBar>
<SegmentedBar selectedIndex="2"
selectedTextColor="#00ffd9"
color="red"
android:backgroundColor="#A8A8A8"
selectedBackgroundColor="blue"
android:borderRadius="6"
>
<SegmentedBar.items>
<SegmentedBarItem title="Item 1" />
<SegmentedBarItem title="Item 2" />
Expand Down
52 changes: 48 additions & 4 deletions packages/core/ui/segmented-bar/index.android.ts
@@ -1,10 +1,11 @@
import { Font } from '../styling/font';
import { SegmentedBarItemBase, SegmentedBarBase, selectedIndexProperty, itemsProperty, selectedBackgroundColorProperty } from './segmented-bar-common';
import { SegmentedBarItemBase, SegmentedBarBase, selectedIndexProperty, itemsProperty, selectedBackgroundColorProperty, selectedTextColorProperty } from './segmented-bar-common';
import { isEnabledProperty } from '../core/view';
import { colorProperty, fontInternalProperty, fontSizeProperty } from '../styling/style-properties';
import { Color } from '../../color';
import { layout } from '../../utils';
import { SDK_VERSION } from '../../utils/constants';
import { Trace } from '../../trace';

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

Expand Down Expand Up @@ -51,8 +52,13 @@ function initializeNativeClasses(): void {

onTabChanged(id: string): void {
const owner = this.owner;
if (owner.shouldChangeSelectedIndex()) {
owner.selectedIndex = parseInt(id);
if (owner) {
setTimeout(() => {
owner.setTabColor(id);
});
if (owner.shouldChangeSelectedIndex()) {
owner.selectedIndex = parseInt(id);
}
}
}
}
Expand Down Expand Up @@ -165,7 +171,7 @@ export class SegmentedBarItem extends SegmentedBarItemBase {
const backgroundDrawable = viewGroup.getBackground();
if (SDK_VERSION > 21 && backgroundDrawable) {
const newDrawable = tryCloneDrawable(backgroundDrawable, nativeView.getResources());
newDrawable.setColorFilter(color, android.graphics.PorterDuff.Mode.SRC_IN);
newDrawable.setColorFilter(new android.graphics.Paint(color).getColorFilter());
viewGroup.setBackground(newDrawable);
} else {
const stateDrawable = new android.graphics.drawable.StateListDrawable();
Expand Down Expand Up @@ -292,4 +298,42 @@ export class SegmentedBar extends SegmentedBarBase {
tabWidget.setEnabled(value);
}
}
public setTabColor(index) {
try {
const tabWidget = this.nativeViewProtected?.getTabWidget();
if (tabWidget) {
const unselectedTextColor = this.getColorForAndroid(this.color ?? '#6e6e6e');
const selectedTextColor = this.getColorForAndroid(this?.selectedTextColor ?? '#000000');
const unselectedBackgroundColor = this.getColorForAndroid(this?.backgroundColor ?? '#dbdbdb');
const selectedBackgroundColor = this.getColorForAndroid(this?.selectedBackgroundColor ?? this?.backgroundColor ?? 'blue');
if (tabWidget) {
for (let i = 0; i < tabWidget.getTabCount(); i++) {
const view = tabWidget.getChildTabViewAt(i);
const item = this.items[i];
const textView = item?.nativeViewProtected;
view.setBackgroundColor(unselectedBackgroundColor);
if (textView) {
textView.setTextColor(unselectedTextColor);
}
if (index == i) {
view.setBackgroundColor(selectedBackgroundColor);
if (textView) {
textView.setTextColor(selectedTextColor);
}
continue;
}
}
}
}
} catch (e) {
Trace.error(e);
}
}
private getColorForAndroid(color: string | Color): number {
if (typeof color === 'string') {
return new Color(color).android;
} else if (color instanceof Color) {
return color.android;
}
}
}
10 changes: 10 additions & 0 deletions packages/core/ui/segmented-bar/index.d.ts
Expand Up @@ -44,6 +44,11 @@ export class SegmentedBar extends View implements AddChildFromBuilder, AddArrayF
*/
selectedBackgroundColor: Color;

/**
* Gets or sets the selected text color of the SegmentedBar component.
*/
selectedTextColor: Color;

/**
* Gets or sets the items of the SegmentedBar.
*/
Expand Down Expand Up @@ -90,3 +95,8 @@ export const selectedBackgroundColorProperty: CssProperty<Style, Color>;
* Gets or sets the items dependency property of the SegmentedBar.
*/
export const itemsProperty: Property<SegmentedBar, SegmentedBarItem[]>;

/**
* Gets or sets the selected text color property of the SegmentedBar.
*/
export const selectedTextColorProperty: CssProperty<Style, Color>;
34 changes: 28 additions & 6 deletions packages/core/ui/segmented-bar/index.ios.ts
Expand Up @@ -2,7 +2,8 @@ import { Font } from '../styling/font';
import { SegmentedBarItemBase, SegmentedBarBase, selectedIndexProperty, itemsProperty, selectedBackgroundColorProperty } from './segmented-bar-common';
import { colorProperty, fontInternalProperty } from '../styling/style-properties';
import { Color } from '../../color';
import { iOSNativeHelper } from '../../utils';
import { Trace } from '../../trace';
import { SDK_VERSION } from '../../utils';
export * from './segmented-bar-common';

export class SegmentedBarItem extends SegmentedBarItemBase {
Expand Down Expand Up @@ -68,14 +69,11 @@ export class SegmentedBar extends SegmentedBarBase {
}

[selectedBackgroundColorProperty.getDefault](): UIColor {
const currentOsVersion = iOSNativeHelper.MajorVersion;

return currentOsVersion < 13 ? this.ios.tintColor : this.ios.selectedSegmentTintColor;
return SDK_VERSION < 13 ? this.ios.tintColor : this.ios.selectedSegmentTintColor;
}
[selectedBackgroundColorProperty.setNative](value: UIColor | Color) {
const currentOsVersion = iOSNativeHelper.MajorVersion;
const color = value instanceof Color ? value.ios : value;
if (currentOsVersion < 13) {
if (SDK_VERSION < 13) {
this.ios.tintColor = color;
} else {
this.ios.selectedSegmentTintColor = color;
Expand All @@ -92,6 +90,8 @@ export class SegmentedBar extends SegmentedBarBase {
const attrs = currentAttrs ? currentAttrs.mutableCopy() : NSMutableDictionary.new();
attrs.setValueForKey(color, NSForegroundColorAttributeName);
bar.setTitleTextAttributesForState(attrs, UIControlState.Normal);
// Set the selected text color
this.setSelectedTextColor(bar);
}

[fontInternalProperty.getDefault](): Font {
Expand All @@ -105,6 +105,27 @@ export class SegmentedBar extends SegmentedBarBase {
attrs.setValueForKey(font, NSFontAttributeName);
bar.setTitleTextAttributesForState(attrs, UIControlState.Normal);
}
setSelectedTextColor(bar: UISegmentedControl) {
try {
const selectedTextColor = this.getColorForIOS(this?.selectedTextColor ?? this?.color ?? '#000000');
if (!selectedTextColor) {
Trace.write(`unable te set selectedTextColor`, Trace.categories.Error);
}
const selectedText = bar.titleTextAttributesForState(UIControlState.Selected);
const attrsSelected = selectedText ? selectedText.mutableCopy() : NSMutableDictionary.new();
attrsSelected.setValueForKey(selectedTextColor, NSForegroundColorAttributeName);
bar.setTitleTextAttributesForState(attrsSelected, UIControlState.Selected);
} catch (e) {
console.error(`SegmentedBar:`, e);
}
}
private getColorForIOS(color: string | Color): UIColor {
if (typeof color === 'string') {
return new Color(color).ios;
} else if (color instanceof Color) {
return color.ios;
}
}
}

@NativeClass
Expand All @@ -122,6 +143,7 @@ class SelectionHandlerImpl extends NSObject {
const owner = this._owner?.deref();
if (owner) {
owner.selectedIndex = sender.selectedSegmentIndex;
owner.setSelectedTextColor(sender);
}
}

Expand Down
17 changes: 17 additions & 0 deletions packages/core/ui/segmented-bar/segmented-bar-common.ts
Expand Up @@ -38,6 +38,13 @@ export abstract class SegmentedBarBase extends View implements SegmentedBarDefin
this.style.selectedBackgroundColor = value;
}

public get selectedTextColor(): Color {
return this.style.selectedTabTextColor;
}
public set selectedTextColor(value: Color) {
this.style.selectedTabTextColor = value;
}

public _addArrayFromBuilder(name: string, value: Array<any>): void {
if (name === 'items') {
this.items = value;
Expand Down Expand Up @@ -141,6 +148,16 @@ export const selectedBackgroundColorProperty = new InheritedCssProperty<Style, C
name: 'selectedBackgroundColor',
cssName: 'selected-background-color',
equalityComparer: Color.equals,
defaultValue: new Color('blue'),
valueConverter: (v) => new Color(v),
});
selectedBackgroundColorProperty.register(Style);

export const selectedTextColorProperty = new InheritedCssProperty<Style, Color>({
name: 'selectedTextColor',
cssName: 'selected-text-color',
equalityComparer: Color.equals,
defaultValue: new Color('black'),
valueConverter: (v) => new Color(v),
});
selectedTextColorProperty.register(Style);
1 change: 1 addition & 0 deletions packages/core/ui/styling/style/index.ts
Expand Up @@ -206,6 +206,7 @@ export class Style extends Observable implements StyleDefinition {

//SegmentedBar-specific props
public selectedBackgroundColor: Color;
public selectedTextColor: Color;

// Page-specific props
public statusBarStyle: 'light' | 'dark';
Expand Down
3 changes: 3 additions & 0 deletions packages/core/utils/ios/index.ts
Expand Up @@ -94,6 +94,9 @@ export function isLandscape(): boolean {
return isDeviceOrientationLandscape || isStatusBarOrientationLandscape;
}

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

export function openFile(filePath: string): boolean {
Expand Down

0 comments on commit 3a0afdb

Please sign in to comment.