Files
NativeScript/nativescript-core/ui/segmented-bar/segmented-bar.android.ts
Alexander Vakrilov cc97a16800 feat: Scoped Packages (#7911)
* chore: move tns-core-modules to nativescript-core

* chore: preparing compat generate script

* chore: add missing definitions

* chore: no need for http-request to be private

* chore: packages chore

* test: generate tests for tns-core-modules

* chore: add anroid module for consistency

* chore: add .npmignore

* chore: added privateModulesWhitelist

* chore(webpack): added bundle-entry-points

* chore: scripts

* chore: tests changed to use @ns/core

* test: add scoped-packages test project

* test: fix types

* test: update test project

* chore: build scripts

* chore: update build script

* chore: npm scripts cleanup

* chore: make the compat pgk work with old wp config

* test: generate diff friendly tests

* chore: create barrel exports

* chore: move files after rebase

* chore: typedoc config

* chore: compat mode

* chore: review of barrels

* chore: remove tns-core-modules import after rebase

* chore: dev workflow setup

* chore: update developer-workflow

* docs: experiment with API extractor

* chore: api-extractor and barrel exports

* chore: api-extractor configs

* chore: generate d.ts rollup with api-extractor

* refactor: move methods inside Frame

* chore: fic tests to use Frame static methods

* refactor: create Builder class

* refactor: use Builder class in tests

* refactor: include Style in ui barrel

* chore: separate compat build script

* chore: fix tslint errors

* chore: update NATIVESCRIPT_CORE_ARGS

* chore: fix compat pack

* chore: fix ui-test-app build with linked modules

* chore: Application, ApplicationSettings, Connectivity and Http

* chore: export Trace, Profiling and Utils

* refactor: Static create methods for ImageSource

* chore: fix deprecated usages of ImageSource

* chore: move Span and FormattedString to ui

* chore: add events-args and ImageSource to index files

* chore: check for CLI >= 6.2 when building for IOS

* chore: update travis build

* chore: copy Pod file to compat package

* chore: update error msg ui-tests-app

* refactor: Apply suggestions from code review

Co-Authored-By: Martin Yankov <m.i.yankov@gmail.com>

* chore: typings and refs

* chore: add missing d.ts files for public API

* chore: adress code review FB

* chore: update api-report

* chore: dev-workflow for other apps

* chore: api update

* chore: update api-report
2019-10-17 00:45:33 +03:00

274 lines
9.7 KiB
TypeScript

import { Font } from "../styling/font";
import {
SegmentedBarItemBase, SegmentedBarBase, selectedIndexProperty, itemsProperty, selectedBackgroundColorProperty,
colorProperty, fontInternalProperty, fontSizeProperty, Color, layout
} from "./segmented-bar-common";
export * from "./segmented-bar-common";
const R_ID_TABS = 0x01020013;
const R_ID_TABCONTENT = 0x01020011;
const R_ATTR_STATE_SELECTED = 0x010100a1;
const TITLE_TEXT_VIEW_ID = 16908310; // http://developer.android.com/reference/android/R.id.html#title
interface TabChangeListener {
new(owner: SegmentedBar): android.widget.TabHost.OnTabChangeListener;
}
interface TabContentFactory {
new(owner: SegmentedBar): android.widget.TabHost.TabContentFactory;
}
interface TabHost {
new(context: android.content.Context, attrs: android.util.AttributeSet): android.widget.TabHost;
}
let apiLevel: number;
let selectedIndicatorThickness: number;
let TabHost: TabHost;
let TabChangeListener: TabChangeListener;
let TabContentFactory: TabContentFactory;
function initializeNativeClasses(): void {
if (TabChangeListener) {
return;
}
apiLevel = android.os.Build.VERSION.SDK_INT;
// Indicator thickness for material - 2dip. For pre-material - 5dip.
selectedIndicatorThickness = layout.toDevicePixels(apiLevel >= 21 ? 2 : 5);
@Interfaces([android.widget.TabHost.OnTabChangeListener])
class TabChangeListenerImpl extends java.lang.Object implements android.widget.TabHost.OnTabChangeListener {
constructor(public owner: SegmentedBar) {
super();
return global.__native(this);
}
onTabChanged(id: string): void {
const owner = this.owner;
if (owner.shouldChangeSelectedIndex()) {
owner.selectedIndex = parseInt(id);
}
}
}
@Interfaces([android.widget.TabHost.TabContentFactory])
class TabContentFactoryImpl extends java.lang.Object implements android.widget.TabHost.TabContentFactory {
constructor(public owner: SegmentedBar) {
super();
return global.__native(this);
}
createTabContent(tag: string): android.view.View {
const tv = new android.widget.TextView(this.owner._context);
// This is collapsed by default and made visible
// by android when TabItem becomes visible/selected.
// TODO: Try commenting visibility change.
tv.setVisibility(android.view.View.GONE);
tv.setMaxLines(1);
tv.setEllipsize(android.text.TextUtils.TruncateAt.END);
return tv;
}
}
class TabHostImpl extends android.widget.TabHost {
constructor(context: android.content.Context, attrs: android.util.AttributeSet) {
super(context, attrs);
return global.__native(this);
}
public onAttachedToWindow(): void {
// overriden to remove the code that will steal the focus from edit fields.
}
}
TabHost = TabHostImpl;
TabChangeListener = TabChangeListenerImpl;
TabContentFactory = TabContentFactoryImpl;
}
export class SegmentedBarItem extends SegmentedBarItemBase {
nativeViewProtected: android.widget.TextView;
public setupNativeView(tabIndex: number): void {
// TabHost.TabSpec.setIndicator DOES NOT WORK once the title has been set.
// http://stackoverflow.com/questions/2935781/modify-tab-indicator-dynamically-in-android
const titleTextView = <android.widget.TextView>this.parent.nativeViewProtected.getTabWidget().getChildAt(tabIndex).findViewById(TITLE_TEXT_VIEW_ID);
this.setNativeView(titleTextView);
if (titleTextView) {
if (this.titleDirty) {
this._update();
}
}
}
private titleDirty: boolean;
public _update(): void {
const tv = this.nativeViewProtected;
if (tv) {
let title = this.title;
title = (title === null || title === undefined) ? "" : title;
tv.setText(title);
this.titleDirty = false;
} else {
this.titleDirty = true;
}
}
[colorProperty.getDefault](): number {
return this.nativeViewProtected.getCurrentTextColor();
}
[colorProperty.setNative](value: Color | number) {
const color = value instanceof Color ? value.android : value;
this.nativeViewProtected.setTextColor(color);
}
[fontSizeProperty.getDefault](): { nativeSize: number } {
return { nativeSize: this.nativeViewProtected.getTextSize() };
}
[fontSizeProperty.setNative](value: number | { nativeSize: number }) {
if (typeof value === "number") {
this.nativeViewProtected.setTextSize(value);
} else {
this.nativeViewProtected.setTextSize(android.util.TypedValue.COMPLEX_UNIT_PX, value.nativeSize);
}
}
[fontInternalProperty.getDefault](): android.graphics.Typeface {
return this.nativeViewProtected.getTypeface();
}
[fontInternalProperty.setNative](value: Font | android.graphics.Typeface) {
this.nativeViewProtected.setTypeface(value instanceof Font ? value.getAndroidTypeface() : value);
}
[selectedBackgroundColorProperty.getDefault](): android.graphics.drawable.Drawable {
const viewGroup = <android.view.ViewGroup>this.nativeViewProtected.getParent();
return viewGroup.getBackground();
}
[selectedBackgroundColorProperty.setNative](value: Color | android.graphics.drawable.Drawable) {
const nativeView = this.nativeViewProtected;
const viewGroup = <android.view.ViewGroup>nativeView.getParent();
if (value instanceof Color) {
const color = value.android;
const backgroundDrawable = viewGroup.getBackground();
if (apiLevel > 21 && backgroundDrawable) {
const newDrawable = tryCloneDrawable(backgroundDrawable, nativeView.getResources());
newDrawable.setColorFilter(color, android.graphics.PorterDuff.Mode.SRC_IN);
viewGroup.setBackground(newDrawable);
} else {
const stateDrawable = new android.graphics.drawable.StateListDrawable();
const colorDrawable: android.graphics.drawable.ColorDrawable = new org.nativescript.widgets.SegmentedBarColorDrawable(color, selectedIndicatorThickness);
const arr = Array.create("int", 1);
arr[0] = R_ATTR_STATE_SELECTED;
stateDrawable.addState(arr, colorDrawable);
stateDrawable.setBounds(0, 15, viewGroup.getRight(), viewGroup.getBottom());
viewGroup.setBackground(stateDrawable);
}
} else {
const backgroundDrawable = tryCloneDrawable(value, nativeView.getResources());
viewGroup.setBackground(backgroundDrawable);
}
}
}
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;
}
export class SegmentedBar extends SegmentedBarBase {
nativeViewProtected: android.widget.TabHost;
private _tabContentFactory: android.widget.TabHost.TabContentFactory;
private _addingTab: boolean;
public shouldChangeSelectedIndex(): boolean {
return !this._addingTab;
}
public createNativeView() {
initializeNativeClasses();
const context: android.content.Context = this._context;
const nativeView = new TabHost(context, null);
const tabHostLayout = new android.widget.LinearLayout(context);
tabHostLayout.setOrientation(android.widget.LinearLayout.VERTICAL);
const tabWidget = new android.widget.TabWidget(context);
tabWidget.setId(R_ID_TABS);
tabHostLayout.addView(tabWidget);
const frame = new android.widget.FrameLayout(context);
frame.setId(R_ID_TABCONTENT);
frame.setVisibility(android.view.View.GONE);
tabHostLayout.addView(frame);
nativeView.addView(tabHostLayout);
return nativeView;
}
public initNativeView(): void {
super.initNativeView();
const nativeView = this.nativeViewProtected;
const listener = new TabChangeListener(this);
nativeView.setOnTabChangedListener(listener);
(<any>nativeView).listener = listener;
nativeView.setup();
this._tabContentFactory = this._tabContentFactory || new TabContentFactory(this);
}
public disposeNativeView() {
const nativeView: any = this.nativeViewProtected;
nativeView.listener.owner = null;
super.disposeNativeView();
}
private insertTab(tabItem: SegmentedBarItem, index: number): void {
const tabHost = this.nativeViewProtected;
const tab = tabHost.newTabSpec(index + "");
tab.setIndicator(tabItem.title + "");
tab.setContent(this._tabContentFactory);
this._addingTab = true;
tabHost.addTab(tab);
tabItem.setupNativeView(index);
this._addingTab = false;
}
[selectedIndexProperty.getDefault](): number {
return -1;
}
[selectedIndexProperty.setNative](value: number) {
this.nativeViewProtected.setCurrentTab(value);
}
[itemsProperty.getDefault](): SegmentedBarItem[] {
return null;
}
[itemsProperty.setNative](value: SegmentedBarItem[]) {
this.nativeViewProtected.clearAllTabs();
const newItems = value;
if (newItems) {
newItems.forEach((item, i, arr) => this.insertTab(item, i));
}
selectedIndexProperty.coerce(this);
}
}