전환 애니메이션 중에 중첩 된 조각이 사라집니다.


99

여기에 시나리오는 다음과 같습니다 활동 조각 포함 A차례 사용에 getChildFragmentManager()조각을 추가 할 수 A1A2의 그것 onCreate과 같이 :

getChildFragmentManager()
  .beginTransaction()
  .replace(R.id.fragmentOneHolder, new FragmentA1())
  .replace(R.id.fragmentTwoHolder, new FragmentA2())
  .commit()

지금까지 모든 것이 예상대로 실행되고 있습니다.

그런 다음 활동에서 다음 트랜잭션을 실행합니다.

getSupportFragmentManager()
  .beginTransaction()
  .setCustomAnimations(anim1, anim2, anim1, anim2)
  .replace(R.id.fragmentHolder, new FragmentB())
  .addToBackStack(null)
  .commit()

전환하는 동안 enter조각에 대한 애니메이션 B은 올바르게 실행되지만 조각 A1 및 A2는 완전히 사라집니다 . 뒤로 버튼으로 트랜잭션을 되 돌리면 제대로 초기화되고 popEnter애니메이션 중에 정상적으로 표시됩니다 .

내 간단한 테스트에서 더 이상해졌습니다. 하위 조각 (아래 참조)에 대한 exit애니메이션을 설정하면 조각을 추가 할 때 애니메이션이 간헐적으로 실행됩니다.B

getChildFragmentManager()
  .beginTransaction()
  .setCustomAnimations(enter, exit)
  .replace(R.id.fragmentOneHolder, new FragmentA1())
  .replace(R.id.fragmentTwoHolder, new FragmentA2())
  .commit()

내가 달성하고자하는 효과는 간단하다 - 내가 원하는 exit(또는해야 popExit조각에?) 애니메이션 A의 중첩 된 어린이를 포함한 전체 컨테이너, 애니메이션, 실행 (anim2을).

그것을 달성하는 방법이 있습니까?

편집 : 여기 에서 테스트 케이스를 찾으 십시오 .

Edit2 : 정적 애니메이션을 계속 사용하도록 저를 밀어 준 @StevenByle에게 감사드립니다. 분명히 당신은 작업 단위로 애니메이션을 설정할 수 있습니다 (전체 트랜잭션에 전역이 아님). 즉, 자식은 무한한 정적 애니메이션 세트를 가질 수 있지만 부모는 다른 애니메이션을 가질 수 있으며 전체가 하나의 트랜잭션에서 커밋 될 수 있습니다. . 아래 토론과 업데이트 된 테스트 케이스 프로젝트를 참조하십시오 .


R.id.fragmentHolderA, A1, A2 등과 관련하여 무엇입니까 ?
CommonsWare 2013

fragmentHolder는 활동 레이아웃의 ID이고 fragment {One, Two} Holder는 조각 A의 레이아웃에 있습니다. 세 가지 모두 구별됩니다. 단편 A는 처음에 fragmentHolder에 추가되었습니다 (즉, 단편 B가 단편 A를 대체 함).
Delyan 2013

여기에 샘플 프로젝트를 만들었습니다 : github.com/BurntBrunch/NestedFragmentsAnimationsTest , 저장소에 포함 된 apk도 있습니다. 이것은 정말 성가신 버그이며이를 해결하는 방법을 찾고 있습니다 (내 코드에 없다고 가정).
Delyan 2013

이제이 문제에 대해 조금 더 알고 있습니다. 조각이 사라지는 이유는 자식이 부모보다 먼저 수명주기 이벤트를 처리하기 때문입니다. 본질적으로 A1과 A2는 A보다 먼저 제거되고 애니메이션이 설정되지 않았기 때문에 갑자기 사라집니다. 이를 어느 정도 완화하는 방법은 A를 대체하는 트랜잭션에서 A1과 A2를 명시 적으로 제거하는 것입니다. 이렇게하면 종료 할 때 애니메이션되지만 상위 컨테이너도 애니메이션되므로 애니메이션 속도가 제곱됩니다. 이 인공물을 생성하지 않는 해결책을 주시면 감사하겠습니다.
Delyan 2013

질문에서 언급 한 변경 사항 (스타터 조각 대체)은 실제로 수행하고 싶은 것입니까, 아니면 단지 예입니까? changeFragment메서드를 한 번만 호출 하시겠습니까?
Luksprog 2013.02.20

답변:


37

트랜잭션에서 상위 프래그먼트가 제거 / 교체 될 때 사용자가 중첩 된 프래그먼트가 사라지는 것을 방지하기 위해 화면에 표시된대로 해당 프래그먼트의 이미지를 제공하여 여전히 존재하는 프래그먼트를 "시뮬레이션"할 수 있습니다. 이 이미지는 중첩 된 조각 컨테이너의 배경으로 사용되므로 중첩 된 조각의보기가 사라지더라도 이미지는 그 존재를 시뮬레이션합니다. 또한 중첩 된 프래그먼트의 뷰와의 상호 작용을 잃어 버리는 것을 문제로 보지는 않습니다. 왜냐하면 사용자가 제거되는 과정에있을 때 사용자가 조치를 취하기를 원하지 않기 때문입니다 (아마도 잘).

나는 배경 이미지 (기본적인 것)를 설정 하는 약간의 예 를 만들었 습니다.


1
제가 사용하게 된 해결책이었던만큼 현상금을 지급하기로 결정했습니다. 시간 내 주셔서 감사합니다!
Delyan 2013

17
와, 너무 더럽 네요. 길이 우리 안드로이드 개발자들은 그냥 slickness에 대한에 가야
딘 와일드

1
두 번째 탭에서 Viewpager가 있습니다. 다른 조각을 바꾸고 있으며 다시 누르면 viewpager 두 번째 탭을 표시해야하지만 열리고 있지만 빈 페이지가 표시됩니다. 위의 스레드에서 제안한 것을 시도했지만 여전히 동일합니다.
Harish

@Harish가 쓴대로 사용자가 돌아올 때 문제가 남아 있습니다
Ewoks

1
진심으로? 그것의 2018이고 이것은 여전히 ​​일입니까? :(
Archie G. Quiñones

69

그래서 이것에 대한 많은 다른 해결 방법이있는 것 같지만 @ Jayd16의 대답에 따르면 저는 여전히 자식 조각에 대한 사용자 지정 전환 애니메이션을 허용하고 수행 할 필요가없는 매우 견고한 포괄 솔루션을 찾았다 고 생각합니다. 레이아웃의 비트 맵 캐시.

BaseFragment를 확장 하는 클래스가 Fragment있고 모든 조각이 해당 클래스를 확장하도록합니다 (하위 조각뿐 아니라).

해당 BaseFragment클래스에서 다음을 추가하십시오.

// Arbitrary value; set it to some reasonable default
private static final int DEFAULT_CHILD_ANIMATION_DURATION = 250;

@Override
public Animation onCreateAnimation(int transit, boolean enter, int nextAnim) {
    final Fragment parent = getParentFragment();

    // Apply the workaround only if this is a child fragment, and the parent
    // is being removed.
    if (!enter && parent != null && parent.isRemoving()) {
        // This is a workaround for the bug where child fragments disappear when
        // the parent is removed (as all children are first removed from the parent)
        // See https://code.google.com/p/android/issues/detail?id=55228
        Animation doNothingAnim = new AlphaAnimation(1, 1);
        doNothingAnim.setDuration(getNextAnimationDuration(parent, DEFAULT_CHILD_ANIMATION_DURATION));
        return doNothingAnim;
    } else {
        return super.onCreateAnimation(transit, enter, nextAnim);
    }
}

private static long getNextAnimationDuration(Fragment fragment, long defValue) {
    try {
        // Attempt to get the resource ID of the next animation that
        // will be applied to the given fragment.
        Field nextAnimField = Fragment.class.getDeclaredField("mNextAnim");
        nextAnimField.setAccessible(true);
        int nextAnimResource = nextAnimField.getInt(fragment);
        Animation nextAnim = AnimationUtils.loadAnimation(fragment.getActivity(), nextAnimResource);

        // ...and if it can be loaded, return that animation's duration
        return (nextAnim == null) ? defValue : nextAnim.getDuration();
    } catch (NoSuchFieldException|IllegalAccessException|Resources.NotFoundException ex) {
        Log.w(TAG, "Unable to load next animation from parent.", ex);
        return defValue;
    }
}

불행히도 그것은 반성을 필요로합니다. 그러나이 해결 방법은 지원 라이브러리에 대한 것이므로 지원 라이브러리를 업데이트하지 않는 한 기본 구현이 변경 될 위험이 없습니다. 소스에서 지원 라이브러리를 빌드하는 경우 다음 애니메이션 리소스 ID에 대한 접근자를 추가하고 Fragment.java리플렉션의 필요성을 제거 할 수 있습니다 .

이 솔루션은 부모의 애니메이션 지속 시간을 "추측"할 필요를 제거하고 ( "아무것도하지 않음"애니메이션이 부모의 이탈 애니메이션과 동일한 지속 시간을 갖도록) 여전히 자식 조각에서 사용자 정의 애니메이션을 수행 할 수 있도록합니다 (예 : 다른 애니메이션으로 하위 조각을 다시 교체).


5
이것은 스레드에서 내가 가장 좋아하는 솔루션입니다. 비트 맵이 필요하지 않고 자식 조각에 추가 코드가 필요하지 않으며 실제로 부모에서 자식 조각으로 정보를 유출하지 않습니다.
jacobhyphenated 14

1
@EugenPechanec 자식이 아닌 부모 조각 의 nextAnim이 필요합니다 . 그게 요점입니다.
Kevin Coppock

1
불행하게도 이것은 :( 롤리팝 아래의 안드로이드 버전뿐만 아니라 부모 조각에 대한 암시 자식 조각에 대한 원인을 메모리 누수에 접근하고
코스 민

8
이 매우 유용한 솔루션에 감사하지만 현재 지원 라이브러리를 사용하려면 약간의 업데이트가 필요합니다 (27.0.2,이 코드를 위반 한 버전을 알 수 없음). mNextAnim이제 mAnimationInfo개체 안에 있습니다. 이처럼 액세스 할 수 있습니다 :Field animInfoField = Fragment.class.getDeclaredField("mAnimationInfo"); animInfoField.setAccessible(true); Object animationInfo = animInfoField.get(fragment); Field nextAnimField = animationInfo.getClass().getDeclaredField("mNextAnim");
데이비드 Lericolais

5
@DavidLericolais, 당신의 코드 뒤에 또 다른 코드 줄을 추가하고 싶습니다. val nextAnimResource = nextAnimField.getInt(animationInfo);라인 교체int nextAnimResource = nextAnimField.getInt(fragment);
tingyik90

32

꽤 깨끗한 해결책을 찾을 수있었습니다. IMO는 해키가 가장 적으며 기술적으로는 "비트 맵 그리기"솔루션이지만 최소한 조각 lib에 의해 추상화됩니다.

자녀 조각이 다음과 같이 부모 클래스를 재정의하는지 확인하십시오.

private static final Animation dummyAnimation = new AlphaAnimation(1,1);
static{
    dummyAnimation.setDuration(500);
}

@Override
public Animation onCreateAnimation(int transit, boolean enter, int nextAnim) {
    if(!enter && getParentFragment() != null){
        return dummyAnimation;
    }
    return super.onCreateAnimation(transit, enter, nextAnim);
}

자식 조각에 이탈 애니메이션이있는 경우 깜박이는 대신 애니메이션이 적용됩니다. 일정 기간 동안 전체 알파에서 자식 조각을 단순히 그리는 애니메이션을 사용하여이를 활용할 수 있습니다. 이렇게하면 애니메이션이 진행되는 동안 부모 조각에 계속 표시되어 원하는 동작을 제공합니다.

내가 생각할 수있는 유일한 문제는 그 기간을 추적하는 것입니다. 큰 숫자로 설정할 수도 있지만 여전히 어딘가에 애니메이션을 그리는 경우 성능 문제가있을 수 있습니다.


감사합니다. 기간 시간의 값은 중요하지 않습니다
iscariot

지금까지 깨끗한 솔루션
리란 코헨

16

명확성을 위해 내 솔루션을 게시했습니다. 해결책은 아주 간단합니다. 부모의 조각 트랜잭션 애니메이션을 모방하려는 경우 동일한 기간으로 자식 조각 트랜잭션에 사용자 지정 애니메이션을 추가하기 만하면됩니다. 아 그리고 add () 전에 사용자 정의 애니메이션을 설정했는지 확인하십시오.

getChildFragmentManager().beginTransaction()
        .setCustomAnimations(R.anim.none, R.anim.none, R.anim.none, R.anim.none)
        .add(R.id.container, nestedFragment)
        .commit();

R.anim.none의 xml (부모님의 애니메이션 진입 / 종료 시간은 250ms입니다)

<?xml version="1.0" encoding="utf-8"?>
<set xmlns:android="http://schemas.android.com/apk/res/android">
    <translate android:fromXDelta="0" android:toXDelta="0" android:duration="250" />
</set>

나는 매우 비슷한 것을했지만 자식을 업데이트 할 때 "add"보다는 "show"를 사용했다. "getChildFragmentManager (). executePendingTransactions ()"도 추가했지만 이것이 꼭 필요한지 확실하지 않습니다. 하지만이 솔루션은 잘 작동하며 일부 제안과 같이 조각의 "이미지 제공"이 필요하지 않습니다.
Brian Yencho

이것은 훌륭했습니다. 그러나 내 자식 조각을 전환 할 때 지연이 발생했습니다. 이를 방지하려면 애니메이션없이 두 번째 매개 변수를 설정하십시오.fragmentTransaction.setCustomAnimations(R.anim.none, 0, R.anim.none, R.anim.none)
ono

7

나는 이것이 당신의 문제를 완전히 해결하지 못할 수도 있음을 이해하지만 다른 사람의 요구에 맞을 수도 있습니다. 실제로 s를 움직이거나 움직이지 않는 enter/ exitpopEnter/ popExit애니메이션을 자녀에게 추가 할 수 있습니다 . 애니메이션의 지속 시간 / 오프셋이 부모 애니메이션과 동일한 한 부모의 애니메이션과 함께 이동 / 애니메이션되는 것처럼 보입니다.FragmentFragmentFragment


1
그의 솔루션이 보편적으로 작동하기 때문에 나는 Luksprog에게 현상금을 수여했습니다. 나는 정적 애니메이션 트릭을 시도했지만 (실제로 기간은 중요하지 않습니다-부모가 사라지면 뷰가 분명히 사라집니다) 가능한 모든 경우에서 작동하지 않았습니다 (질문에 대한 내 의견 참조). 또한이 접근 방식은 추상화가 누출됩니다. 자식이있는 조각의 부모는 그 사실을 알고 자식 애니메이션을 설정하기위한 추가 단계를 수행해야하기 때문입니다. 어쨌든 시간 내 주셔서 감사합니다!
Delyan 2013

동의합니다. 이것은 방수 솔루션보다 더 많은 해결 방법이며 약간 취약한 것으로 간주 될 수 있습니다. 그러나 간단한 경우에는 작동합니다.
Steven Byle 2013

4

자식 조각에서이 작업을 수행 할 수 있습니다.

@Override
public Animator onCreateAnimator(int transit, boolean enter, int nextAnim) {
    if (true) {//condition
        ObjectAnimator objectAnimator = ObjectAnimator.ofFloat(getView(), "alpha", 1, 1);
        objectAnimator.setDuration(333);//time same with parent fragment's animation
        return objectAnimator;
    }
    return super.onCreateAnimator(transit, enter, nextAnim);
}

감사합니다! 아마도 최고는 아니지만 가장 간단한 해결책 일 수 있습니다.
bug56

2

@@@@@@@@@@@@@@@@@@@@@@@@@@@@

편집 : 다른 문제가 있었기 때문에이 솔루션을 구현하지 않았습니다. Square는 최근 조각을 대체하는 2 개의 라이브러리를 출시했습니다. 나는 이것이 구글이 원하지 않는 일을하도록 조각을 해킹하는 것보다 실제로 더 나은 대안이라고 말하고 싶다.

http://corner.squareup.com/2014/01/mortar-and-flow.html

@@@@@@@@@@@@@@@@@@@@@@@@@@@@

나는 미래에이 문제가있는 사람들을 돕기 위해이 해결책을 제시 할 것이라고 생각했습니다. 다른 사람들과의 원래 포스터 대화를 추적하고 그가 게시 한 코드를 보면 원본 포스터가 결국 부모 조각을 애니메이션하는 동안 자식 조각에 작동하지 않는 애니메이션을 사용하는 결론에 도달하는 것을 볼 수 있습니다. 이 솔루션은 FragmentPagerAdapter와 함께 ViewPager를 사용할 때 번거로울 수있는 모든 하위 조각을 추적해야하므로 이상적이지 않습니다.

나는 모든 곳에서 Child Fragments를 사용하기 때문에 효율적이고 모듈 식 (쉽게 제거 할 수 있도록) 솔루션을 찾았습니다.

이를 구현할 수있는 방법은 많이 있습니다. 싱글 톤을 사용하기로 선택했고이를 ChildFragmentAnimationManager라고 부릅니다. 기본적으로 부모를 기반으로 자식 조각을 추적하고 요청시 자식에게 작동하지 않는 애니메이션을 적용합니다.

public class ChildFragmentAnimationManager {

private static ChildFragmentAnimationManager instance = null;

private Map<Fragment, List<Fragment>> fragmentMap;

private ChildFragmentAnimationManager() {
    fragmentMap = new HashMap<Fragment, List<Fragment>>();
}

public static ChildFragmentAnimationManager instance() {
    if (instance == null) {
        instance = new ChildFragmentAnimationManager();
    }
    return instance;
}

public FragmentTransaction animate(FragmentTransaction ft, Fragment parent) {
    List<Fragment> children = getChildren(parent);

    ft.setCustomAnimations(R.anim.no_anim, R.anim.no_anim, R.anim.no_anim, R.anim.no_anim);
    for (Fragment child : children) {
        ft.remove(child);
    }

    return ft;
}

public void putChild(Fragment parent, Fragment child) {
    List<Fragment> children = getChildren(parent);
    children.add(child);
}

public void removeChild(Fragment parent, Fragment child) {
    List<Fragment> children = getChildren(parent);
    children.remove(child);
}

private List<Fragment> getChildren(Fragment parent) {
    List<Fragment> children;

    if ( fragmentMap.containsKey(parent) ) {
        children = fragmentMap.get(parent);
    } else {
        children = new ArrayList<Fragment>(3);
        fragmentMap.put(parent, children);
    }

    return children;
}

}

다음으로 모든 프래그먼트가 확장하는 프래그먼트를 확장하는 클래스가 있어야합니다 (적어도 하위 프래그먼트). 나는 이미이 클래스를 가지고 있었고 그것을 BaseFragment라고 부른다. 프래그먼트 뷰가 생성되면 ChildFragmentAnimationManager에 추가하고 소멸되면 제거합니다. onAttach / Detach 또는 시퀀스의 다른 일치 방법을 수행 할 수 있습니다. Create / Destroy View를 선택하는 논리는 Fragment에 View가없는 경우 계속 표시되도록 애니메이션하는 데 신경 쓰지 않기 때문입니다. 이 접근 방식은 FragmentPagerAdapter가 보유하고있는 모든 단일 Fragment를 추적하지 않고 3 개만 추적하므로 Fragment를 사용하는 ViewPager에서도 더 잘 작동합니다.

public abstract class BaseFragment extends Fragment {

@Override
public  View onCreateView(LayoutInflater inflater, ViewGroup container,
        Bundle savedInstanceState) {

    Fragment parent = getParentFragment();
    if (parent != null) {
        ChildFragmentAnimationManager.instance().putChild(parent, this);
    }

    return super.onCreateView(inflater, container, savedInstanceState);
}

@Override
public void onDestroyView() {
    Fragment parent = getParentFragment();
    if (parent != null) {
        ChildFragmentAnimationManager.instance().removeChild(parent, this);
    }

    super.onDestroyView();
}

}

이제 모든 프래그먼트가 상위 프래그먼트에 의해 메모리에 저장되었으므로 이와 같이 애니메이션을 호출 할 수 있으며 하위 프래그먼트는 사라지지 않습니다.

FragmentTransaction ft = getActivity().getSupportFragmentManager().beginTransaction();
ChildFragmentAnimationManager.instance().animate(ft, ReaderFragment.this)
                    .setCustomAnimations(R.anim.up_in, R.anim.up_out, R.anim.down_in, R.anim.down_out)
                    .replace(R.id.container, f)
                    .addToBackStack(null)
                    .commit();

또한 res / anim 폴더에있는 no_anim.xml 파일이 있습니다.

<?xml version="1.0" encoding="utf-8"?>
<set xmlns:android="http://schemas.android.com/apk/res/android" android:interpolator="@android:anim/linear_interpolator">
    <translate android:fromXDelta="0" android:toXDelta="0"
        android:duration="1000" />
</set>

다시 말하지만,이 솔루션이 완벽하다고 생각하지는 않지만 자식 조각이있는 모든 인스턴스보다 훨씬 낫습니다. 부모 조각에 사용자 지정 코드를 구현하여 각 자식을 추적합니다. 나는 거기에 있었고 재미가 없습니다.


1

Luksprog가 제안한 것처럼 현재 조각을 비트 맵으로 스냅 샷하는 것보다이 문제에 대한 더 나은 해결책을 찾은 것 같습니다.

트릭은 제거되거나 분리되는 조각 을 숨기고 애니메이션이 완료된 후에 만 ​​조각이 자체 조각 트랜잭션에서 제거되거나 분리됩니다.

FragmentAFragmentB, 둘 다 하위 조각 이 있다고 상상해보십시오 . 이제 일반적으로 할 때 :

getSupportFragmentManager()
  .beginTransaction()
  .setCustomAnimations(anim1, anim2, anim1, anim2)
  .add(R.id.fragmentHolder, new FragmentB())
  .remove(fragmentA)    <-------------------------------------------
  .addToBackStack(null)
  .commit()

대신 당신은

getSupportFragmentManager()
  .beginTransaction()
  .setCustomAnimations(anim1, anim2, anim1, anim2)
  .add(R.id.fragmentHolder, new FragmentB())
  .hide(fragmentA)    <---------------------------------------------
  .addToBackStack(null)
  .commit()

fragmentA.removeMe = true;

이제 Fragment 구현을 위해 :

public class BaseFragment extends Fragment {

    protected Boolean detachMe = false;
    protected Boolean removeMe = false;

    @Override
    public Animation onCreateAnimation(int transit, boolean enter, int nextAnim) {
        if (nextAnim == 0) {
            if (!enter) {
                onExit();
            }

            return null;
        }

        Animation animation = AnimationUtils.loadAnimation(getActivity(), nextAnim);
        assert animation != null;

        if (!enter) {
            animation.setAnimationListener(new Animation.AnimationListener() {
                @Override
                public void onAnimationStart(Animation animation) {
                }

                @Override
                public void onAnimationEnd(Animation animation) {
                    onExit();
                }

                @Override
                public void onAnimationRepeat(Animation animation) {
                }
            });
        }

        return animation;
    }

    private void onExit() {
        if (!detachMe && !removeMe) {
            return;
        }

        FragmentTransaction fragmentTransaction = getFragmentManager().beginTransaction();
        if (detachMe) {
            fragmentTransaction.detach(this);
            detachMe = false;
        } else if (removeMe) {
            fragmentTransaction.remove(this);
            removeMe = false;
        }
        fragmentTransaction.commit();
    }
}

popBackStack이 분리 된 Fragment를 표시하려고하기 때문에 오류가 발생하지 않습니까?
Alexandre

1

지도 조각과 동일한 문제가 발생했습니다. 포함하는 조각의 이탈 애니메이션 동안 계속 사라졌습니다. 해결 방법은 상위 프래그먼트의 이탈 애니메이션 중에 표시되는 하위 맵 프래그먼트에 애니메이션을 추가하는 것입니다. 하위 조각의 애니메이션은 기간 동안 알파를 100 %로 유지합니다.

애니메이션 : res / animator / keep_child_fragment.xml

<?xml version="1.0" encoding="utf-8"?>    
<set xmlns:android="http://schemas.android.com/apk/res/android">
    <objectAnimator
        android:propertyName="alpha"
        android:valueFrom="1.0"
        android:valueTo="1.0"
        android:duration="@integer/keep_child_fragment_animation_duration" />
</set>

그런 다음지도 조각이 부모 조각에 추가 될 때 애니메이션이 적용됩니다.

부모 조각

@Override
public View onCreateView(LayoutInflater inflater, ViewGroup container,
                         Bundle savedInstanceState) {

    View view = inflater.inflate(R.layout.map_parent_fragment, container, false);

    MapFragment mapFragment =  MapFragment.newInstance();

    getChildFragmentManager().beginTransaction()
            .setCustomAnimations(R.animator.keep_child_fragment, 0, 0, 0)
            .add(R.id.map, mapFragment)
            .commit();

    return view;
}

마지막으로 하위 조각 애니메이션의 기간은 리소스 파일에 설정됩니다.

values ​​/ integers.xml

<resources>
  <integer name="keep_child_fragment_animation_duration">500</integer>
</resources>

0

잘린 조각의 사라짐을 애니메이션으로 만들기 위해 ChildFragmentManager에서 스택을 강제로 팝백 할 수 있습니다. 전환 애니메이션이 실행됩니다. 이를 위해서는 OnBackButtonPressed 이벤트를 포착하거나 백 스택 변경 사항을 수신해야합니다.

다음은 코드가있는 예입니다.

View.OnClickListener() {//this is from custom button but you can listen for back button pressed
            @Override
            public void onClick(View v) {
                getChildFragmentManager().popBackStack();
                //and here we can manage other fragment operations 
            }
        });

  Fragment fr = MyNeastedFragment.newInstance(product);

  getChildFragmentManager()
          .beginTransaction()
                .setTransition(FragmentTransaction.TRANSIT_FRAGMENT_CLOSE)
                .replace(R.neasted_fragment_container, fr)
                .addToBackStack("Neasted Fragment")
                .commit();

0

최근에 내 질문 에서이 문제가 발생했습니다. 중첩 조각이 잘못 전환됨

비트 맵을 저장하지 않고 리플렉션이나 기타 만족스럽지 않은 방법을 사용하지 않고이 문제를 해결하는 솔루션이 있습니다.

예제 프로젝트는 여기에서 볼 수 있습니다 : https://github.com/zafrani/NestedFragmentTransitions

효과의 GIF는 여기에서 볼 수 있습니다 : https://imgur.com/94AvrW4

내 예에는 두 개의 상위 단편으로 분할 된 6 개의 하위 단편이 있습니다. 아무 문제없이 들어가기, 나가기, 팝, 푸시에 대한 전환을 달성 할 수 있습니다. 구성 변경 및 백 프레스도 성공적으로 처리됩니다.

솔루션의 대부분은 다음과 같은 BaseFragment의 onCreateAnimator 함수에 있습니다.

   override fun onCreateAnimator(transit: Int, enter: Boolean, nextAnim: Int): Animator {
    if (isConfigChange) {
        resetStates()
        return nothingAnim()
    }

    if (parentFragment is ParentFragment) {
        if ((parentFragment as BaseFragment).isPopping) {
            return nothingAnim()
        }
    }

    if (parentFragment != null && parentFragment.isRemoving) {
        return nothingAnim()
    }

    if (enter) {
        if (isPopping) {
            resetStates()
            return pushAnim()
        }
        if (isSuppressing) {
            resetStates()
            return nothingAnim()
        }
        return enterAnim()
    }

    if (isPopping) {
        resetStates()
        return popAnim()
    }

    if (isSuppressing) {
        resetStates()
        return nothingAnim()
    }

    return exitAnim()
}

활동 및 상위 프래그먼트는 이러한 부울의 상태를 설정합니다. 내 예제 프로젝트에서 방법과 위치를 쉽게 볼 수 있습니다.

내 예제에서는 지원 조각을 사용하지 않지만 동일한 논리를 해당 조각과 onCreateAnimation 함수와 함께 사용할 수 있습니다.


0

이 문제를 해결하는 간단한 방법 Fragment은 표준 라이브러리 조각 클래스 대신이 라이브러리 의 클래스를 사용하는 것입니다.

https://github.com/marksalpeter/contract-fragment

참고로 패키지에는 ContractFragment부모-자식 조각 관계를 활용하여 앱을 빌드하는 데 유용 할 수 있는 유용한 델리게이트 패턴도 포함되어 있습니다 .


0

위의 @kcoppock 답변에서,

Activity-> Fragment-> Fragments (다중 스택, 다음 도움말)가있는 경우 최상의 답변 IMHO에 대한 사소한 편집입니다.

public Animation onCreateAnimation(int transit, boolean enter, int nextAnim) {

    final Fragment parent = getParentFragment();

    Fragment parentOfParent = null;

    if( parent!=null ) {
        parentOfParent = parent.getParentFragment();
    }

    if( !enter && parent != null && parentOfParent!=null && parentOfParent.isRemoving()){
        Animation doNothingAnim = new AlphaAnimation(1, 1);
        doNothingAnim.setDuration(getNextAnimationDuration(parent, DEFAULT_CHILD_ANIMATION_DURATION));
        return doNothingAnim;
    } else
    if (!enter && parent != null && parent.isRemoving()) {
        // This is a workaround for the bug where child fragments disappear when
        // the parent is removed (as all children are first removed from the parent)
        // See https://code.google.com/p/android/issues/detail?id=55228
        Animation doNothingAnim = new AlphaAnimation(1, 1);
        doNothingAnim.setDuration(getNextAnimationDuration(parent, DEFAULT_CHILD_ANIMATION_DURATION));
        return doNothingAnim;
    } else {
        return super.onCreateAnimation(transit, enter, nextAnim);
    }
}

0

내 문제는 부모 조각 제거 (ft.remove (fragment))에 있었고 자식 애니메이션이 발생하지 않았습니다.

기본적인 문제는 부모 조각이 애니메이션을 종료하기 전에 자식 조각이 즉시 파괴된다는 것입니다.

부모 조각 제거시 자식 조각 사용자 지정 애니메이션이 실행되지 않습니다.

다른 사람들이 알지 못했던 것처럼 PARENT를 제거하기 전에 PARENT (아동이 아닌)를 숨기는 것이 좋습니다.

            val ft = fragmentManager?.beginTransaction()
            ft?.setCustomAnimations(R.anim.enter_from_right,
                    R.anim.exit_to_right)
            if (parentFragment.isHidden()) {
                ft?.show(vehicleModule)
            } else {
                ft?.hide(vehicleModule)
            }
            ft?.commit()

실제로 부모를 제거하려면 애니메이션이 언제 끝났는지 알 수 있도록 사용자 지정 애니메이션에 리스너를 설정해야합니다. 그러면 부모 조각 (제거)에서 안전하게 마무리를 수행 할 수 있습니다. 이렇게하지 않으면 적시에 애니메이션이 종료 될 수 있습니다. NB 애니메이션은 자체 비동기 대기열에서 수행됩니다.

BTW는 부모 애니메이션을 상속하므로 자식 조각에 사용자 지정 애니메이션이 필요하지 않습니다.



0

오래된 스레드이지만 누군가 여기에서 우연히 발견되는 경우 :

위의 모든 접근 방식은 저에게 매우 매력적이지 않습니다. 비트 맵 솔루션은 매우 더럽고 성능이 떨어집니다. 다른 것들은 자식 조각이 문제의 자식 조각을 만드는 데 사용 된 트랜잭션에 사용 된 전환 기간에 대해 알고 있어야합니다. 내 눈에 더 나은 솔루션은 다음과 같습니다.

val currentFragment = supportFragmentManager.findFragmentByTag(TAG)
val transaction = supportFragmentManager
    .beginTransaction()
    .setCustomAnimations(anim1, anim2, anim1, anim2)
    .add(R.id.fragmentHolder, FragmentB(), TAG)
if (currentFragment != null) {
    transaction.hide(currentFragment).commit()
    Handler().postDelayed({
        supportFragmentManager.beginTransaction().remove(currentFragment).commit()
    }, DURATION_OF_ANIM)
} else {
    transaction.commit()
}

현재 조각을 숨기고 새 조각을 추가하기 만하면 애니메이션이 완료되면 이전 조각을 제거합니다. 이렇게하면 한 곳에서 처리되고 비트 맵이 생성되지 않습니다.

당사 사이트를 사용함과 동시에 당사의 쿠키 정책개인정보 보호정책을 읽고 이해하였음을 인정하는 것으로 간주합니다.
Licensed under cc by-sa 3.0 with attribution required.