mirror of
https://github.com/NativeScript/NativeScript.git
synced 2025-08-18 22:01:42 +08:00
fix: android cleanup after new fragment handling
This commit is contained in:
@ -91,57 +91,6 @@ function initializeNativeClasses() {
|
|||||||
|
|
||||||
return tabItem.nativeViewProtected;
|
return tabItem.nativeViewProtected;
|
||||||
}
|
}
|
||||||
|
|
||||||
public onDestroyView() {
|
|
||||||
const hasRemovingParent = this.getRemovingParentFragment();
|
|
||||||
|
|
||||||
// Get view as bitmap and set it as background. This is workaround for the disapearing nested fragments.
|
|
||||||
// TODO: Consider removing it when update to androidx.fragment:1.2.0
|
|
||||||
if (hasRemovingParent && this.owner.selectedIndex === this.index) {
|
|
||||||
const bitmapDrawable = new android.graphics.drawable.BitmapDrawable(appResources, this.backgroundBitmap);
|
|
||||||
this.owner._originalBackground = this.owner.backgroundColor || new Color('White');
|
|
||||||
this.owner.nativeViewProtected.setBackgroundDrawable(bitmapDrawable);
|
|
||||||
this.backgroundBitmap = null;
|
|
||||||
|
|
||||||
let thisView = this.getView();
|
|
||||||
if (thisView) {
|
|
||||||
let thisViewParent = thisView.getParent();
|
|
||||||
if (thisViewParent && thisViewParent instanceof android.view.ViewGroup) {
|
|
||||||
thisViewParent.removeView(thisView);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
super.onDestroyView();
|
|
||||||
}
|
|
||||||
|
|
||||||
public onPause(): void {
|
|
||||||
const hasRemovingParent = this.getRemovingParentFragment();
|
|
||||||
|
|
||||||
// Get view as bitmap and set it as background. This is workaround for the disapearing nested fragments.
|
|
||||||
// TODO: Consider removing it when update to androidx.fragment:1.2.0
|
|
||||||
if (hasRemovingParent && this.owner.selectedIndex === this.index) {
|
|
||||||
this.backgroundBitmap = this.loadBitmapFromView(this.owner.nativeViewProtected);
|
|
||||||
}
|
|
||||||
|
|
||||||
super.onPause();
|
|
||||||
}
|
|
||||||
|
|
||||||
private loadBitmapFromView(view: android.view.View): android.graphics.Bitmap {
|
|
||||||
// Another way to get view bitmap. Test performance vs setDrawingCacheEnabled
|
|
||||||
// const width = view.getWidth();
|
|
||||||
// const height = view.getHeight();
|
|
||||||
// const bitmap = android.graphics.Bitmap.createBitmap(width, height, android.graphics.Bitmap.Config.ARGB_8888);
|
|
||||||
// const canvas = new android.graphics.Canvas(bitmap);
|
|
||||||
// view.layout(0, 0, width, height);
|
|
||||||
// view.draw(canvas);
|
|
||||||
|
|
||||||
view.setDrawingCacheEnabled(true);
|
|
||||||
const bitmap = android.graphics.Bitmap.createBitmap(view.getDrawingCache());
|
|
||||||
view.setDrawingCacheEnabled(false);
|
|
||||||
|
|
||||||
return bitmap;
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
|
|
||||||
@NativeClass
|
@NativeClass
|
||||||
@ -250,7 +199,7 @@ function iterateIndexRange(index: number, eps: number, lastIndex: number, callba
|
|||||||
@CSSType('BottomNavigation')
|
@CSSType('BottomNavigation')
|
||||||
export class BottomNavigation extends TabNavigationBase {
|
export class BottomNavigation extends TabNavigationBase {
|
||||||
private _contentView: org.nativescript.widgets.ContentLayout;
|
private _contentView: org.nativescript.widgets.ContentLayout;
|
||||||
private _contentViewId: number = -1;
|
private _contentViewId = -1;
|
||||||
private _bottomNavigationBar: org.nativescript.widgets.BottomNavigationBar;
|
private _bottomNavigationBar: org.nativescript.widgets.BottomNavigationBar;
|
||||||
private _currentFragment: androidx.fragment.app.Fragment;
|
private _currentFragment: androidx.fragment.app.Fragment;
|
||||||
private _currentTransaction: androidx.fragment.app.FragmentTransaction;
|
private _currentTransaction: androidx.fragment.app.FragmentTransaction;
|
||||||
@ -347,8 +296,8 @@ export class BottomNavigation extends TabNavigationBase {
|
|||||||
const lastIndex = this.items.length - 1;
|
const lastIndex = this.items.length - 1;
|
||||||
const offsideItems = 0;
|
const offsideItems = 0;
|
||||||
|
|
||||||
let toUnload = [];
|
const toUnload = [];
|
||||||
let toLoad = [];
|
const toLoad = [];
|
||||||
|
|
||||||
iterateIndexRange(newIndex, offsideItems, lastIndex, (i) => toLoad.push(i));
|
iterateIndexRange(newIndex, offsideItems, lastIndex, (i) => toLoad.push(i));
|
||||||
|
|
||||||
@ -610,7 +559,7 @@ export class BottomNavigation extends TabNavigationBase {
|
|||||||
tabItemSpec.backgroundColor = backgroundColor ? backgroundColor.android : this.getTabBarBackgroundArgbColor();
|
tabItemSpec.backgroundColor = backgroundColor ? backgroundColor.android : this.getTabBarBackgroundArgbColor();
|
||||||
|
|
||||||
// COLOR
|
// COLOR
|
||||||
let itemColor = this.selectedIndex === tabStripItem._index ? this._selectedItemColor : this._unSelectedItemColor;
|
const itemColor = this.selectedIndex === tabStripItem._index ? this._selectedItemColor : this._unSelectedItemColor;
|
||||||
const color = itemColor || titleLabel.style.color;
|
const color = itemColor || titleLabel.style.color;
|
||||||
tabItemSpec.color = color && color.android;
|
tabItemSpec.color = color && color.android;
|
||||||
|
|
||||||
@ -669,7 +618,7 @@ export class BottomNavigation extends TabNavigationBase {
|
|||||||
image = this.getFixedSizeIcon(image);
|
image = this.getFixedSizeIcon(image);
|
||||||
}
|
}
|
||||||
|
|
||||||
let imageDrawable = new android.graphics.drawable.BitmapDrawable(application.android.context.getResources(), image);
|
const imageDrawable = new android.graphics.drawable.BitmapDrawable(application.android.context.getResources(), image);
|
||||||
|
|
||||||
return {
|
return {
|
||||||
drawable: imageDrawable,
|
drawable: imageDrawable,
|
||||||
@ -681,7 +630,7 @@ export class BottomNavigation extends TabNavigationBase {
|
|||||||
}
|
}
|
||||||
|
|
||||||
private getIconInfo(tabStripItem: TabStripItem, color?: Color): IconInfo {
|
private getIconInfo(tabStripItem: TabStripItem, color?: Color): IconInfo {
|
||||||
let originalIcon = this.getOriginalIcon(tabStripItem, color);
|
const originalIcon = this.getOriginalIcon(tabStripItem, color);
|
||||||
|
|
||||||
return this.getDrawableInfo(originalIcon);
|
return this.getDrawableInfo(originalIcon);
|
||||||
}
|
}
|
||||||
@ -841,7 +790,7 @@ export class BottomNavigation extends TabNavigationBase {
|
|||||||
}
|
}
|
||||||
|
|
||||||
public setTabBarTextTransform(value: TextTransform): void {
|
public setTabBarTextTransform(value: TextTransform): void {
|
||||||
let items = this.tabStrip && this.tabStrip.items;
|
const items = this.tabStrip && this.tabStrip.items;
|
||||||
if (items) {
|
if (items) {
|
||||||
items.forEach((tabStripItem) => {
|
items.forEach((tabStripItem) => {
|
||||||
if (tabStripItem.label && tabStripItem.nativeViewProtected) {
|
if (tabStripItem.label && tabStripItem.nativeViewProtected) {
|
||||||
|
@ -81,7 +81,7 @@ function getAttachListener(): android.view.View.OnAttachStateChangeListener {
|
|||||||
export class Frame extends FrameBase {
|
export class Frame extends FrameBase {
|
||||||
public _originalBackground: any;
|
public _originalBackground: any;
|
||||||
private _android: AndroidFrame;
|
private _android: AndroidFrame;
|
||||||
private _containerViewId: number = -1;
|
private _containerViewId = -1;
|
||||||
private _tearDownPending = false;
|
private _tearDownPending = false;
|
||||||
private _attachedToWindow = false;
|
private _attachedToWindow = false;
|
||||||
private _cachedTransitionState: TransitionState;
|
private _cachedTransitionState: TransitionState;
|
||||||
@ -190,7 +190,7 @@ export class Frame extends FrameBase {
|
|||||||
// simulated navigation (NoTransition, zero duration animator) and thus the fragment immediately disappears;
|
// simulated navigation (NoTransition, zero duration animator) and thus the fragment immediately disappears;
|
||||||
// the user only sees the animation of the entering fragment as per its specific enter animation settings.
|
// the user only sees the animation of the entering fragment as per its specific enter animation settings.
|
||||||
// NOTE: we are restoring the animation settings in Frame.setCurrent(...) as navigation completes asynchronously
|
// NOTE: we are restoring the animation settings in Frame.setCurrent(...) as navigation completes asynchronously
|
||||||
let cachedTransitionState = getTransitionState(this._currentEntry);
|
const cachedTransitionState = getTransitionState(this._currentEntry);
|
||||||
|
|
||||||
if (cachedTransitionState) {
|
if (cachedTransitionState) {
|
||||||
this._cachedTransitionState = cachedTransitionState;
|
this._cachedTransitionState = cachedTransitionState;
|
||||||
@ -425,7 +425,7 @@ export class Frame extends FrameBase {
|
|||||||
navigationTransition = null;
|
navigationTransition = null;
|
||||||
}
|
}
|
||||||
|
|
||||||
let isNestedDefaultTransition = !currentEntry;
|
const isNestedDefaultTransition = !currentEntry;
|
||||||
|
|
||||||
_setAndroidFragmentTransitions(animated, navigationTransition, currentEntry, newEntry, this._android.frameId, transaction, isNestedDefaultTransition);
|
_setAndroidFragmentTransitions(animated, navigationTransition, currentEntry, newEntry, this._android.frameId, transaction, isNestedDefaultTransition);
|
||||||
|
|
||||||
@ -659,7 +659,7 @@ function clearEntry(entry: BackstackEntry): void {
|
|||||||
}
|
}
|
||||||
|
|
||||||
let framesCounter = 0;
|
let framesCounter = 0;
|
||||||
let framesCache = new Array<WeakRef<AndroidFrame>>();
|
const framesCache = new Array<WeakRef<AndroidFrame>>();
|
||||||
|
|
||||||
class AndroidFrame extends Observable implements AndroidFrameDefinition {
|
class AndroidFrame extends Observable implements AndroidFrameDefinition {
|
||||||
public rootViewGroup: android.view.ViewGroup;
|
public rootViewGroup: android.view.ViewGroup;
|
||||||
@ -689,7 +689,7 @@ class AndroidFrame extends Observable implements AndroidFrameDefinition {
|
|||||||
}
|
}
|
||||||
|
|
||||||
public get activity(): androidx.appcompat.app.AppCompatActivity {
|
public get activity(): androidx.appcompat.app.AppCompatActivity {
|
||||||
let activity: androidx.appcompat.app.AppCompatActivity = this.owner._context;
|
const activity: androidx.appcompat.app.AppCompatActivity = this.owner._context;
|
||||||
if (activity) {
|
if (activity) {
|
||||||
return activity;
|
return activity;
|
||||||
}
|
}
|
||||||
@ -708,12 +708,12 @@ class AndroidFrame extends Observable implements AndroidFrameDefinition {
|
|||||||
}
|
}
|
||||||
|
|
||||||
public get actionBar(): android.app.ActionBar {
|
public get actionBar(): android.app.ActionBar {
|
||||||
let activity = this.currentActivity;
|
const activity = this.currentActivity;
|
||||||
if (!activity) {
|
if (!activity) {
|
||||||
return undefined;
|
return undefined;
|
||||||
}
|
}
|
||||||
|
|
||||||
let bar = activity.getActionBar();
|
const bar = activity.getActionBar();
|
||||||
if (!bar) {
|
if (!bar) {
|
||||||
return undefined;
|
return undefined;
|
||||||
}
|
}
|
||||||
@ -727,7 +727,7 @@ class AndroidFrame extends Observable implements AndroidFrameDefinition {
|
|||||||
return activity;
|
return activity;
|
||||||
}
|
}
|
||||||
|
|
||||||
let frames = _stack();
|
const frames = _stack();
|
||||||
for (let length = frames.length, i = length - 1; i >= 0; i--) {
|
for (let length = frames.length, i = length - 1; i >= 0; i--) {
|
||||||
activity = frames[i].android.activity;
|
activity = frames[i].android.activity;
|
||||||
if (activity) {
|
if (activity) {
|
||||||
@ -812,7 +812,7 @@ function startActivity(activity: androidx.appcompat.app.AppCompatActivity, frame
|
|||||||
function getFrameByNumberId(frameId: number): Frame {
|
function getFrameByNumberId(frameId: number): Frame {
|
||||||
// Find the frame for this activity.
|
// Find the frame for this activity.
|
||||||
for (let i = 0; i < framesCache.length; i++) {
|
for (let i = 0; i < framesCache.length; i++) {
|
||||||
let aliveFrame = framesCache[i].get();
|
const aliveFrame = framesCache[i].get();
|
||||||
if (aliveFrame && aliveFrame.frameId === frameId) {
|
if (aliveFrame && aliveFrame.frameId === frameId) {
|
||||||
return aliveFrame.owner;
|
return aliveFrame.owner;
|
||||||
}
|
}
|
||||||
@ -975,23 +975,11 @@ class FragmentCallbacksImplementation implements AndroidFragmentCallbacks {
|
|||||||
|
|
||||||
@profile
|
@profile
|
||||||
public onDestroyView(fragment: org.nativescript.widgets.FragmentBase, superFunc: Function): void {
|
public onDestroyView(fragment: org.nativescript.widgets.FragmentBase, superFunc: Function): void {
|
||||||
try {
|
|
||||||
if (Trace.isEnabled()) {
|
if (Trace.isEnabled()) {
|
||||||
Trace.write(`${fragment}.onDestroyView()`, Trace.categories.NativeLifecycle);
|
Trace.write(`${fragment}.onDestroyView()`, Trace.categories.NativeLifecycle);
|
||||||
}
|
}
|
||||||
|
|
||||||
const hasRemovingParent = fragment.getRemovingParentFragment();
|
|
||||||
|
|
||||||
if (hasRemovingParent) {
|
|
||||||
const bitmapDrawable = new android.graphics.drawable.BitmapDrawable(application.android.context.getResources(), this.backgroundBitmap);
|
|
||||||
this.frame._originalBackground = this.frame.backgroundColor || new Color('White');
|
|
||||||
this.frame.nativeViewProtected.setBackgroundDrawable(bitmapDrawable);
|
|
||||||
this.backgroundBitmap = null;
|
|
||||||
}
|
|
||||||
} finally {
|
|
||||||
superFunc.call(fragment);
|
superFunc.call(fragment);
|
||||||
}
|
}
|
||||||
}
|
|
||||||
|
|
||||||
@profile
|
@profile
|
||||||
public onDestroy(fragment: androidx.fragment.app.Fragment, superFunc: Function): void {
|
public onDestroy(fragment: androidx.fragment.app.Fragment, superFunc: Function): void {
|
||||||
@ -1024,18 +1012,8 @@ class FragmentCallbacksImplementation implements AndroidFragmentCallbacks {
|
|||||||
|
|
||||||
@profile
|
@profile
|
||||||
public onPause(fragment: org.nativescript.widgets.FragmentBase, superFunc: Function): void {
|
public onPause(fragment: org.nativescript.widgets.FragmentBase, superFunc: Function): void {
|
||||||
try {
|
|
||||||
// Get view as bitmap and set it as background. This is workaround for the disapearing nested fragments.
|
|
||||||
// TODO: Consider removing it when update to androidx.fragment:1.2.0
|
|
||||||
const hasRemovingParent = fragment.getRemovingParentFragment();
|
|
||||||
|
|
||||||
if (hasRemovingParent) {
|
|
||||||
this.backgroundBitmap = this.loadBitmapFromView(this.frame.nativeViewProtected);
|
|
||||||
}
|
|
||||||
} finally {
|
|
||||||
superFunc.call(fragment);
|
superFunc.call(fragment);
|
||||||
}
|
}
|
||||||
}
|
|
||||||
|
|
||||||
@profile
|
@profile
|
||||||
public onStop(fragment: androidx.fragment.app.Fragment, superFunc: Function): void {
|
public onStop(fragment: androidx.fragment.app.Fragment, superFunc: Function): void {
|
||||||
@ -1101,7 +1079,7 @@ class ActivityCallbacksImplementation implements AndroidActivityCallbacks {
|
|||||||
// If there is savedInstanceState and moduleLoaded is false we are restarted but process was killed.
|
// If there is savedInstanceState and moduleLoaded is false we are restarted but process was killed.
|
||||||
// For now we treat it like first run (e.g. we are not passing savedInstanceState so no fragments are being restored).
|
// For now we treat it like first run (e.g. we are not passing savedInstanceState so no fragments are being restored).
|
||||||
// When we add support for application save/load state - revise this logic.
|
// When we add support for application save/load state - revise this logic.
|
||||||
let isRestart = !!savedInstanceState && moduleLoaded;
|
const isRestart = !!savedInstanceState && moduleLoaded;
|
||||||
superFunc.call(activity, isRestart ? savedInstanceState : null);
|
superFunc.call(activity, isRestart ? savedInstanceState : null);
|
||||||
|
|
||||||
// Try to get the rootViewId form the saved state in case the activity
|
// Try to get the rootViewId form the saved state in case the activity
|
||||||
@ -1265,7 +1243,7 @@ class ActivityCallbacksImplementation implements AndroidActivityCallbacks {
|
|||||||
}
|
}
|
||||||
|
|
||||||
@profile
|
@profile
|
||||||
public onRequestPermissionsResult(activity: any, requestCode: number, permissions: Array<String>, grantResults: Array<number>, superFunc: Function): void {
|
public onRequestPermissionsResult(activity: any, requestCode: number, permissions: Array<string>, grantResults: Array<number>, superFunc: Function): void {
|
||||||
if (Trace.isEnabled()) {
|
if (Trace.isEnabled()) {
|
||||||
Trace.write('NativeScriptActivity.onRequestPermissionsResult;', Trace.categories.NativeLifecycle);
|
Trace.write('NativeScriptActivity.onRequestPermissionsResult;', Trace.categories.NativeLifecycle);
|
||||||
}
|
}
|
||||||
|
@ -82,49 +82,6 @@ function initializeNativeClasses() {
|
|||||||
|
|
||||||
return tabItem.view.nativeViewProtected;
|
return tabItem.view.nativeViewProtected;
|
||||||
}
|
}
|
||||||
|
|
||||||
public onDestroyView() {
|
|
||||||
const hasRemovingParent = this.getRemovingParentFragment();
|
|
||||||
|
|
||||||
// Get view as bitmap and set it as background. This is workaround for the disapearing nested fragments.
|
|
||||||
// TODO: Consider removing it when update to androidx.fragment:1.2.0
|
|
||||||
if (hasRemovingParent && this.owner.selectedIndex === this.index) {
|
|
||||||
const bitmapDrawable = new android.graphics.drawable.BitmapDrawable(appResources, this.backgroundBitmap);
|
|
||||||
this.owner._originalBackground = this.owner.backgroundColor || new Color('White');
|
|
||||||
this.owner.nativeViewProtected.setBackground(bitmapDrawable);
|
|
||||||
this.backgroundBitmap = null;
|
|
||||||
}
|
|
||||||
|
|
||||||
super.onDestroyView();
|
|
||||||
}
|
|
||||||
|
|
||||||
public onPause(): void {
|
|
||||||
const hasRemovingParent = this.getRemovingParentFragment();
|
|
||||||
|
|
||||||
// Get view as bitmap and set it as background. This is workaround for the disapearing nested fragments.
|
|
||||||
// TODO: Consider removing it when update to androidx.fragment:1.2.0
|
|
||||||
if (hasRemovingParent && this.owner.selectedIndex === this.index) {
|
|
||||||
this.backgroundBitmap = this.loadBitmapFromView(this.owner.nativeViewProtected);
|
|
||||||
}
|
|
||||||
|
|
||||||
super.onPause();
|
|
||||||
}
|
|
||||||
|
|
||||||
private loadBitmapFromView(view: android.view.View): android.graphics.Bitmap {
|
|
||||||
// Another way to get view bitmap. Test performance vs setDrawingCacheEnabled
|
|
||||||
// const width = view.getWidth();
|
|
||||||
// const height = view.getHeight();
|
|
||||||
// const bitmap = android.graphics.Bitmap.createBitmap(width, height, android.graphics.Bitmap.Config.ARGB_8888);
|
|
||||||
// const canvas = new android.graphics.Canvas(bitmap);
|
|
||||||
// view.layout(0, 0, width, height);
|
|
||||||
// view.draw(canvas);
|
|
||||||
|
|
||||||
view.setDrawingCacheEnabled(true);
|
|
||||||
const bitmap = android.graphics.Bitmap.createBitmap(view.getDrawingCache());
|
|
||||||
view.setDrawingCacheEnabled(false);
|
|
||||||
|
|
||||||
return bitmap;
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
|
|
||||||
const POSITION_UNCHANGED = -1;
|
const POSITION_UNCHANGED = -1;
|
||||||
@ -442,7 +399,7 @@ export class TabView extends TabViewBase {
|
|||||||
private _tabLayout: org.nativescript.widgets.TabLayout;
|
private _tabLayout: org.nativescript.widgets.TabLayout;
|
||||||
private _viewPager: androidx.viewpager.widget.ViewPager;
|
private _viewPager: androidx.viewpager.widget.ViewPager;
|
||||||
private _pagerAdapter: androidx.viewpager.widget.PagerAdapter;
|
private _pagerAdapter: androidx.viewpager.widget.PagerAdapter;
|
||||||
private _androidViewId: number = -1;
|
private _androidViewId = -1;
|
||||||
public _originalBackground: any;
|
public _originalBackground: any;
|
||||||
|
|
||||||
constructor() {
|
constructor() {
|
||||||
@ -549,8 +506,8 @@ export class TabView extends TabViewBase {
|
|||||||
const lastIndex = items.length - 1;
|
const lastIndex = items.length - 1;
|
||||||
const offsideItems = this.androidTabsPosition === 'top' ? this.androidOffscreenTabLimit : 1;
|
const offsideItems = this.androidTabsPosition === 'top' ? this.androidOffscreenTabLimit : 1;
|
||||||
|
|
||||||
let toUnload = [];
|
const toUnload = [];
|
||||||
let toLoad = [];
|
const toLoad = [];
|
||||||
|
|
||||||
iterateIndexRange(newIndex, offsideItems, lastIndex, (i) => toLoad.push(i));
|
iterateIndexRange(newIndex, offsideItems, lastIndex, (i) => toLoad.push(i));
|
||||||
|
|
||||||
@ -623,7 +580,7 @@ export class TabView extends TabViewBase {
|
|||||||
private disposeCurrentFragments(): void {
|
private disposeCurrentFragments(): void {
|
||||||
const fragmentManager = this._getFragmentManager();
|
const fragmentManager = this._getFragmentManager();
|
||||||
const transaction = fragmentManager.beginTransaction();
|
const transaction = fragmentManager.beginTransaction();
|
||||||
let fragments = <Array<any>>fragmentManager.getFragments().toArray();
|
const fragments = <Array<any>>fragmentManager.getFragments().toArray();
|
||||||
for (let i = 0; i < fragments.length; i++) {
|
for (let i = 0; i < fragments.length; i++) {
|
||||||
transaction.remove(fragments[i]);
|
transaction.remove(fragments[i]);
|
||||||
}
|
}
|
||||||
@ -769,7 +726,7 @@ export class TabView extends TabViewBase {
|
|||||||
return getDefaultAccentColor(this._context);
|
return getDefaultAccentColor(this._context);
|
||||||
}
|
}
|
||||||
[androidSelectedTabHighlightColorProperty.setNative](value: number | Color) {
|
[androidSelectedTabHighlightColorProperty.setNative](value: number | Color) {
|
||||||
let tabLayout = this._tabLayout;
|
const tabLayout = this._tabLayout;
|
||||||
const color = value instanceof Color ? value.android : value;
|
const color = value instanceof Color ? value.android : value;
|
||||||
tabLayout.setSelectedIndicatorColors([color]);
|
tabLayout.setSelectedIndicatorColors([color]);
|
||||||
}
|
}
|
||||||
|
Reference in New Issue
Block a user