mirror of
https://github.com/NativeScript/NativeScript.git
synced 2025-08-15 11:01:21 +08:00
fix(android): nested fragment disappears on parent fragment removal (#6677)
This commit is contained in:
@ -1,10 +1,10 @@
|
||||
import { AndroidFragmentCallbacks, setFragmentCallbacks, setFragmentClass } from "./frame";
|
||||
|
||||
@JavaProxy("com.tns.FragmentClass")
|
||||
class FragmentClass extends android.support.v4.app.Fragment {
|
||||
class FragmentClass extends org.nativescript.widgets.FragmentBase {
|
||||
// This field is updated in the frame module upon `new` (although hacky this eases the Fragment->callbacks association a lot)
|
||||
private _callbacks: AndroidFragmentCallbacks;
|
||||
|
||||
|
||||
constructor() {
|
||||
super();
|
||||
return global.__native(this);
|
||||
@ -15,8 +15,7 @@ class FragmentClass extends android.support.v4.app.Fragment {
|
||||
}
|
||||
|
||||
public onCreateAnimator(transit: number, enter: boolean, nextAnim: number): android.animation.Animator {
|
||||
let result = this._callbacks.onCreateAnimator(this, transit, enter, nextAnim, super.onCreateAnimator);
|
||||
return result;
|
||||
return this._callbacks.onCreateAnimator(this, transit, enter, nextAnim, super.onCreateAnimator);
|
||||
}
|
||||
|
||||
public onStop(): void {
|
||||
|
@ -86,7 +86,20 @@ export function _setAndroidFragmentTransitions(
|
||||
name = navigationTransition.name ? navigationTransition.name.toLowerCase() : "";
|
||||
}
|
||||
|
||||
let useLollipopTransition = name && (name.indexOf("slide") === 0 || name === "fade" || name === "explode") && sdkVersion() >= 21;
|
||||
let useLollipopTransition = !!(name && (name.indexOf("slide") === 0 || name === "fade" || name === "explode") && sdkVersion() >= 21);
|
||||
// [nested frames / fragments] force disable lollipop transitions in case nested fragments
|
||||
// are detected as applying dummy animator to the nested fragment with the same duration as
|
||||
// the exit animator of the removing parent fragment as a workaround for
|
||||
// https://code.google.com/p/android/issues/detail?id=55228 works only if custom animations are
|
||||
// used
|
||||
// NOTE: this effectively means you cannot use Explode transition in nested frames scenarios as
|
||||
// we have implementations only for slide, fade, and flip
|
||||
if (currentFragment &&
|
||||
currentFragment.getChildFragmentManager() &&
|
||||
currentFragment.getChildFragmentManager().getFragments().toArray().length > 0) {
|
||||
useLollipopTransition = false;
|
||||
}
|
||||
|
||||
if (!animated) {
|
||||
name = "none";
|
||||
} else if (transition) {
|
||||
|
@ -457,8 +457,8 @@ export class FrameBase extends CustomLayoutView implements FrameDefinition {
|
||||
}
|
||||
|
||||
public _onRootViewReset(): void {
|
||||
this._removeFromFrameStack();
|
||||
super._onRootViewReset();
|
||||
this._removeFromFrameStack();
|
||||
}
|
||||
|
||||
get _childrenCount(): number {
|
||||
|
@ -209,8 +209,12 @@ export class Frame extends FrameBase {
|
||||
}
|
||||
|
||||
public _onRootViewReset(): void {
|
||||
this.disposeCurrentFragment();
|
||||
super._onRootViewReset();
|
||||
|
||||
// call this AFTER the super call to ensure descendants apply their rootview-reset logic first
|
||||
// i.e. in a scenario with nested frames / frame with tabview let the descendandt cleanup the inner
|
||||
// fragments first, and then cleanup the parent fragments
|
||||
this.disposeCurrentFragment();
|
||||
}
|
||||
|
||||
onUnloaded() {
|
||||
@ -223,11 +227,6 @@ export class Frame extends FrameBase {
|
||||
}
|
||||
|
||||
private disposeCurrentFragment(): void {
|
||||
// when interacting with nested fragments it seems Android is smart enough
|
||||
// to automatically remove child fragments when parent fragment is removed;
|
||||
// however, we must add a fragment.isAdded() guard as our logic will try to
|
||||
// explicitly remove the already removed child fragment causing an
|
||||
// IllegalStateException: Fragment has not been attached yet.
|
||||
if (!this._currentEntry ||
|
||||
!this._currentEntry.fragment ||
|
||||
!this._currentEntry.fragment.isAdded()) {
|
||||
@ -742,7 +741,13 @@ class FragmentCallbacksImplementation implements AndroidFragmentCallbacks {
|
||||
}
|
||||
|
||||
@profile
|
||||
public onCreateAnimator(fragment: android.support.v4.app.Fragment, transit: number, enter: boolean, nextAnim: number, superFunc: Function): android.animation.Animator {
|
||||
public onCreateAnimator(fragment: org.nativescript.widgets.FragmentBase, transit: number, enter: boolean, nextAnim: number, superFunc: Function): android.animation.Animator {
|
||||
// HACK: FragmentBase class MUST handle removing nested fragment scenario to workaround
|
||||
// https://code.google.com/p/android/issues/detail?id=55228
|
||||
if (!enter && fragment.getRemovingParentFragment()) {
|
||||
return superFunc.call(fragment, transit, enter, nextAnim);
|
||||
}
|
||||
|
||||
let nextAnimString: string;
|
||||
switch (nextAnim) {
|
||||
case AnimationType.enterFakeResourceId: nextAnimString = "enter"; break;
|
||||
|
@ -45,7 +45,7 @@ function initializeNativeClasses() {
|
||||
return;
|
||||
}
|
||||
|
||||
class TabFragmentImplementation extends android.support.v4.app.Fragment {
|
||||
class TabFragmentImplementation extends org.nativescript.widgets.FragmentBase {
|
||||
private tab: TabView;
|
||||
private index: number;
|
||||
|
||||
@ -55,7 +55,6 @@ function initializeNativeClasses() {
|
||||
}
|
||||
|
||||
static newInstance(tabId: number, index: number): TabFragmentImplementation {
|
||||
|
||||
const args = new android.os.Bundle();
|
||||
args.putInt(TABID, tabId);
|
||||
args.putInt(INDEX, index);
|
||||
@ -79,10 +78,6 @@ function initializeNativeClasses() {
|
||||
|
||||
return tabItem.view.nativeViewProtected;
|
||||
}
|
||||
|
||||
public onDestroyView() {
|
||||
super.onDestroyView();
|
||||
}
|
||||
}
|
||||
|
||||
const POSITION_UNCHANGED = -1;
|
||||
@ -560,8 +555,13 @@ export class TabView extends TabViewBase {
|
||||
}
|
||||
|
||||
public _onRootViewReset(): void {
|
||||
this.disposeCurrentFragments();
|
||||
super._onRootViewReset();
|
||||
|
||||
// call this AFTER the super call to ensure descendants apply their rootview-reset logic first
|
||||
// i.e. in a scenario with tab frames let the frames cleanup their fragments first, and then
|
||||
// cleanup the tab fragments to avoid
|
||||
// android.content.res.Resources$NotFoundException: Unable to find resource ID #0xfffffff6
|
||||
this.disposeCurrentFragments();
|
||||
}
|
||||
|
||||
private disposeCurrentFragments(): void {
|
||||
|
@ -164,6 +164,12 @@
|
||||
public verticalAlignment: VerticalAlignment;
|
||||
}
|
||||
|
||||
export class FragmentBase extends android.support.v4.app.Fragment {
|
||||
constructor();
|
||||
|
||||
public getRemovingParentFragment(): android.support.v4.app.Fragment;
|
||||
}
|
||||
|
||||
export enum Stretch {
|
||||
none,
|
||||
aspectFill,
|
||||
|
Reference in New Issue
Block a user