संक्रमण एनीमेशन के दौरान नेस्टेड टुकड़े गायब हो जाते हैं


100

यहाँ परिदृश्य है: गतिविधि में टुकड़ा होता है A, जो बदले में टुकड़ों getChildFragmentManager()को जोड़ने A1और A2इसके 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चलाने के लिए एनीमेशन ( एनीमेशन 2) पर चलना, पूरे कंटेनर को एनिमेट करना, जिसमें उसके नेस्टेड बच्चे भी शामिल हैं।

क्या इसे प्राप्त करने का कोई तरीका है?

संपादित करें : कृपया यहां एक परीक्षण मामला खोजें

Edit2 : स्थिर एनिमेशन के साथ कोशिश करते रहने के लिए मुझे पुश करने के लिए @StevenByle का धन्यवाद। जाहिरा तौर पर आप प्रति-ऑप्स आधार पर एनिमेशन सेट कर सकते हैं (संपूर्ण लेन-देन के लिए वैश्विक नहीं), जिसका अर्थ है कि बच्चों के पास एक अनिश्चित स्थिर एनीमेशन सेट हो सकता है, जबकि उनके माता-पिता का एक अलग एनीमेशन हो सकता है और पूरी चीज़ एक लेनदेन में प्रतिबद्ध हो सकती है । नीचे चर्चा और अद्यतन परीक्षण केस परियोजना देखें


R.id.fragmentHolderए, ए 1, ए 2, आदि के संबंध में क्या है ?
कॉमन्सवेयर

fragmentHolder गतिविधि के लेआउट में एक आईडी है, टुकड़ा {एक, दो} धारक टुकड़ा A के लेआउट में हैं। तीनों अलग-अलग हैं। फ्रैगमेंट ए को शुरू में फ्रेगमेंटहोल्डर में जोड़ा गया था (यानी, टुकड़े बी की जगह ए ए टुकड़ा है)।
19

मैंने यहाँ एक नमूना परियोजना बनाई है: github.com/BurntBrunch/NestedFragmentsAnimationsTest , वहाँ भी एक रिपॉजिटरी में शामिल एक एपीके है। यह वास्तव में कष्टप्रद बग है और मैं इसके चारों ओर काम करने का एक रास्ता तलाश रहा हूं (यह मानते हुए कि यह मेरे कोड में नहीं है)।
11

मुझे अब इस मुद्दे के बारे में थोड़ा और पता है। टुकड़ों के गायब होने का कारण यह है कि बच्चे माता-पिता से पहले जीवन चक्र की घटनाओं को संभालते हैं। संक्षेप में, A1 और A2 को A से पहले हटा दिया जाता है और चूंकि उनके पास एनिमेशन सेट नहीं होते हैं, वे अचानक गायब हो जाते हैं। कुछ हद तक इसे कम करने का एक तरीका स्पष्ट रूप से ए और ए 2 को बदलने वाले लेन-देन में ए 1 और ए 2 को हटाना है। वे बाहर निकलने के दौरान चेतन करते हैं, हालांकि उनकी एनीमेशन गति चुक जाती है, क्योंकि मूल कंटेनर भी एनिमेट कर रहा है। एक समाधान जो इस कला का उत्पादन नहीं करता है उसकी सराहना की जाएगी।
डेलेयन

प्रश्न में आपके द्वारा उल्लेखित परिवर्तन (स्टार्टर के टुकड़े की जगह) वह वास्तविक है जिसे आप करना चाहते हैं या यह केवल एक उदाहरण है? आप changeFragmentविधि को केवल एक बार कॉल करेंगे ?
लुक्सप्रॉग

जवाबों:


36

नेस्टेड टुकड़ों को गायब होते देखने वाले उपयोगकर्ता से बचने के लिए जब माता-पिता के टुकड़े को हटा दिया जाता है / लेन-देन में बदल दिया जाता है, तो आप उन टुकड़ों को अभी भी उनकी छवि प्रदान करके "अनुकरण" कर सकते हैं, जैसा कि वे स्क्रीन पर दिखाई देते थे। इस छवि को नेस्टेड अंशों के कंटेनर के लिए पृष्ठभूमि के रूप में उपयोग किया जाएगा, भले ही नेस्टेड टुकड़े के विचार चले जाएं, छवि उनकी उपस्थिति का अनुकरण करेगी। इसके अलावा, मैं एक समस्या के रूप में नेस्टेड टुकड़ा के विचारों के साथ अन्तरक्रियाशीलता को खोना नहीं देखता क्योंकि मुझे नहीं लगता कि आप चाहते हैं कि उपयोगकर्ता उन पर कार्रवाई करें जब वे हटाए जाने की प्रक्रिया में हों (शायद एक उपयोगकर्ता कार्रवाई के रूप में कुंआ)।

मैंने बैकग्राउंड इमेज (कुछ बेसिक) सेट करने के साथ एक छोटा सा उदाहरण दिया है ।


1
मैंने आपको इनाम देने का फैसला किया है, क्योंकि वह समाधान था जिसका मैंने उपयोग किया था। आपके समय के लिए बहुत बहुत शुक्रिया!
19

16
वाह, इतनी गंदी। हमें एंड्रॉइड डेवलपर्स की लंबाई के लिए बस कुछ सुस्ती के लिए जाना है
डीन वाइल्ड

1
i। दूसरे टैब से एक व्यूपेजर है, मैं दूसरे टुकड़े की जगह ले रहा हूं और जब मैं इसे वापस दबा रहा हूं तो मुझे व्यूपेजर को दूसरा टैब दिखाने की जरूरत है, यह खुल रहा है लेकिन यह खाली पेज दिखा रहा है। मैंने कोशिश की कि आपने उपरोक्त धागे में क्या सुझाव दिया है लेकिन फिर भी यह वही है।
हरीश

यूजर के वापस आते ही समस्या बनी हुई है क्योंकि @Hish ने लिखा
Ewoks

1
गंभीरता से वाह? 2018 और यह अभी भी एक बात है? :(
आर्ची जी। 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;
    }
}

यह, दुर्भाग्य से, प्रतिबिंब की आवश्यकता होती है; हालाँकि, यह वर्कअराउंड समर्थन लाइब्रेरी के लिए है, आप अंतर्निहित कार्यान्वयन के जोखिम को तब तक नहीं चलाते हैं जब तक आप अपने समर्थन लाइब्रेरी को अपडेट नहीं करते। यदि आप स्रोत से समर्थन पुस्तकालय का निर्माण कर रहे हैं, तो आप अगली एनीमेशन संसाधन आईडी के लिए एक गौण जोड़ सकते हैं Fragment.javaऔर प्रतिबिंब की आवश्यकता को दूर कर सकते हैं।

यह समाधान माता-पिता की एनीमेशन अवधि को "अनुमान" करने की आवश्यकता को हटा देता है (ताकि "कुछ भी न करें" एनीमेशन में माता-पिता के निकास एनीमेशन के समान अवधि हो), और आपको अभी भी बच्चे के टुकड़े पर कस्टम एनिमेशन करने की अनुमति मिलती है (जैसे कि यदि आप ' अलग एनिमेशन के साथ चारों ओर बच्चे के टुकड़े को स्वैप करना)।


5
यह धागे में मेरा पसंदीदा समाधान है। बिटमैप की आवश्यकता नहीं है, बच्चे के टुकड़े में किसी भी अतिरिक्त कोड की आवश्यकता नहीं है, और वास्तव में माता-पिता से बच्चे के टुकड़े करने के लिए जानकारी को लीक नहीं करता है।
जकॉफिनेटेड

1
@EugenPechanec आपको माता-पिता के टुकड़े से अगले की जरूरत है - बच्चे से नहीं। यह पूरी बात है।
केविन कोप्पॉक

1
दुर्भाग्य से यह दृष्टिकोण बच्चे के टुकड़े के लिए एक स्मृति रिसाव का कारण बनता है और मूल रूप से माता-पिता के टुकड़े के लिए और साथ ही लॉलीपॉप से ​​नीचे के एंड्रॉइड संस्करणों पर:
Cosmin

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");
डेविड लारिसोलिस

5
@DavidLericolais, आपके बाद कोड की एक और पंक्ति जोड़ना चाहेगा। val nextAnimResource = nextAnimField.getInt(animationInfo);लाइन बदलने के लिएint nextAnimResource = nextAnimField.getInt(fragment);
tingyik90

32

मैं एक सुंदर साफ समाधान के साथ आने में सक्षम था। IMO इसकी सबसे कम हैकी है, और जबकि यह तकनीकी रूप से "बिटमैप" समाधान है जो कम से कम सुगंधित दायित्व द्वारा सारगर्भित है।

यह सुनिश्चित करें कि आपका बच्चा फ्रैगस इस के साथ एक मूल वर्ग को ओवरराइड करता है:

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

Im स्पष्टता के लिए मेरा समाधान पोस्ट कर रहा हूं। समाधान काफी सरल है। यदि आप माता-पिता के खंड लेनदेन एनीमेशन की नकल करने की कोशिश कर रहे हैं, तो बस उसी अवधि के साथ बच्चे के टुकड़े के लेनदेन के लिए एक कस्टम एनीमेशन जोड़ें। ओह और सुनिश्चित करें कि आप जोड़ने से पहले कस्टम एनीमेशन सेट करें ()।

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>

मैंने कुछ ऐसा ही किया है, लेकिन बच्चे को अपडेट करते समय "ऐड" के बजाय "शो" का उपयोग किया है। मैंने "getChildFragmentManager ()। ExecutePendingTransactions ()" भी जोड़ा, हालांकि मुझे यकीन नहीं है कि अगर यह कड़ाई से आवश्यक है। यह समाधान ठीक काम करता है, हालांकि, और कुछ सुझाव की तरह यह "छवि प्रदान करने" की आवश्यकता नहीं है।
ब्रायन येनचो

यह बहुत अच्छा था। हालाँकि, मुझे अपने बच्चे के टुकड़ों को बदलने में देरी हो रही थी। : इस से बचने के लिए, बस कोई anim के साथ 2 पैरामीटर सेटfragmentTransaction.setCustomAnimations(R.anim.none, 0, R.anim.none, R.anim.none)
ओनो

7

मैं समझता हूं कि यह आपकी समस्या को पूरी तरह से हल करने में सक्षम नहीं हो सकता है, लेकिन हो सकता है कि यह किसी और की जरूरतों के अनुरूप हो, आप अपने बच्चों के लिए enter/ exitऔर popEnter/ popExitएनिमेशन जोड़ सकते हैं Fragmentजो वास्तव में एस को स्थानांतरित नहीं करते / चेतन करते हैं Fragment। जब तक एनिमेशन में उनके माता-पिता के Fragmentएनिमेशन के समान अवधि / ऑफसेट होते हैं , तब तक वे माता-पिता के एनीमेशन के साथ चलते / चेतन होते दिखाई देंगे।


1
मैंने लुक्सप्रॉग को इनाम दिया है क्योंकि उनका समाधान सार्वभौमिक रूप से काम करता है। मैंने स्थैतिक एनिमेशन ट्रिक की कोशिश की (अवधि वास्तव में मायने नहीं रखती है - एक बार माता-पिता के चले जाने के बाद, विचार स्पष्ट रूप से गायब हो जाते हैं) लेकिन वे सभी संभव मामलों में काम नहीं करते थे (प्रश्न के तहत मेरी टिप्पणी देखें)। इसके अलावा, यह दृष्टिकोण अमूर्त लीक करता है, क्योंकि बच्चों के साथ एक टुकड़ा के माता-पिता को उस तथ्य के बारे में जानने और बच्चों के एनिमेशन को निर्धारित करने के लिए अतिरिक्त कदम उठाने की आवश्यकता होती है। किसी भी मामले में, आपके समय के लिए बहुत बहुत धन्यवाद!
Delyan

सहमत, यह एक वॉटरटाइट समाधान की तुलना में अधिक समाधान है, और इसे थोड़ा नाजुक माना जा सकता है। लेकिन यह सरल मामलों के लिए काम करेगा।
स्टीवन बाईले

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);
}

धन्यवाद! शायद सबसे अच्छा नहीं, लेकिन संभवतः सबसे सरल समाधान।
बग ५६

2

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

संपादित करें: मैंने इस समाधान को लागू करने को समाप्त कर दिया क्योंकि इसमें अन्य समस्याएं थीं। स्क्वायर हाल ही में 2 पुस्तकालयों के साथ निकला है जो टुकड़ों को प्रतिस्थापित करते हैं। मैं कहूंगा कि यह वास्तव में टुकड़ों को हैक करने की कोशिश करने से बेहतर विकल्प हो सकता है कि कुछ ऐसा नहीं करना चाहिए जो उन्हें करना है।

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

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

मुझे लगा कि मैं भविष्य में इस समस्या से जूझ रहे लोगों की मदद करने के लिए यह उपाय करूंगा। यदि आप अन्य लोगों के साथ मूल पोस्टर वार्तालाप के माध्यम से ट्रेस करते हैं, और जिस कोड को उन्होंने पोस्ट किया है, उसे देखते हैं, तो आप मूल पोस्टर को देखेंगे, जो मूल अंश को एनिमेट करते हुए बच्चे के टुकड़े पर नो-ऑप एनीमेशन का उपयोग करने के निष्कर्ष पर पहुंचता है। यह समाधान आदर्श नहीं है क्योंकि यह आपको सभी बच्चे के टुकड़ों पर नज़र रखने के लिए मजबूर करता है, जो कि FragmentPagerAdapter के साथ एक ViewPager का उपयोग करते समय बोझिल हो सकता है।

चूँकि मैं बाल समाधान का उपयोग सभी जगह पर करता हूं, जो इस समाधान के साथ आया है जो कुशल है, और मॉड्यूलर (इसलिए इसे आसानी से हटाया जा सकता है) यदि वे कभी इसे ठीक करते हैं और इस नो-ऑप एनीमेशन की अब आवश्यकता नहीं है।

इसे लागू करने के कई तरीके हैं। मैंने एक सिंगलटन का उपयोग करने के लिए चुना है, और मैं इसे चाइल्डफ्रैगमेंटएनीमेशन मैनजर कहता हूं। यह मूल रूप से अपने माता-पिता के आधार पर मेरे लिए एक बच्चे के टुकड़े का ट्रैक रखेगा और पूछे जाने पर बच्चों को नो-ऑप एनीमेशन लागू करेगा।

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;
}

}

आगे आपको एक ऐसा वर्ग रखना होगा जो आपके सभी अंशों का विस्तार करता हो (कम से कम आपके बच्चे के टुकड़े) का विस्तार करता है। मेरे पास पहले से ही यह वर्ग था, और मैं इसे बेसफ्रैगमेंट कहता हूं। जब एक खंड दृश्य बनाया जाता है, तो हम इसे चाइल्डफ्रैगमेंटएनीमेशन मैनजर में जोड़ते हैं, और इसे नष्ट होने पर हटा देते हैं। आप इसे onAttach / Detach, या अन्य मिलान विधियों को अनुक्रम में कर सकते हैं। क्रिएट / डिस्टर्ब व्यू को चुनने का मेरा तर्क यह था क्योंकि अगर किसी फ्रैगमेंट में व्यू नहीं है, तो मैं इसे जारी रखने के लिए इसे एनिमेट करने की परवाह नहीं करता। इस दृष्टिकोण को ViewPagers के साथ भी बेहतर काम करना चाहिए जो Fragments का उपयोग करते हैं क्योंकि आप हर एक Fragment का ट्रैक नहीं रखेंगे जो कि FragmentPagerAdapter को पकड़े हुए है, लेकिन केवल 3।

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();

इसके अलावा, बस आपके पास यह है, यहाँ 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

मुझे लगता है कि मुझे इस समस्या का एक बेहतर समाधान मिल गया है जो वर्तमान टुकड़े को बिटमैप के रूप में स्नैपचैट करने से बेहतर है जैसा कि लुक्सप्रॉग ने सुझाव दिया था।

छल को हटाए जाने या अलग किए जाने के लिए छिपाना है और केवल एनिमेशन के पूरा होने के बाद ही खंड को हटा दिया जाता है या अपने स्वयं के खंड लेनदेन में अलग कर दिया जाता है।

कल्पना कीजिए कि हमारे पास FragmentAऔर FragmentBउप-टुकड़े के साथ दोनों हैं। अब जब आप सामान्य रूप से करेंगे:

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;

अब टुकड़े के कार्यान्वयन के लिए:

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 त्रुटि का कारण नहीं बनता क्योंकि यह एक फ़्रैगमेंट को दिखाने की कोशिश कर रहा है जिसे अलग कर दिया गया है?
अलेक्जेंड्रे

1

मैं नक्शा टुकड़ा के साथ एक ही मुद्दा रहा था। यह अपने खंडित होने के निकास एनीमेशन के दौरान गायब रहा। वर्कअराउंड चाइल्ड मैप फ्रैगमेंट के लिए एनीमेशन जोड़ना है जो इसे पेरेंट टुकड़ा के एग्जिट एनीमेशन के दौरान दिखाई देगा। बच्चे के टुकड़े का एनीमेशन इसकी अवधि के दौरान अपने अल्फा को 100% पर रख रहा है।

एनिमेशन: रेस / एनिमेटर / कीप_चाइल्ड_फ्रैगमेंट.एक्सएमएल

<?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;
}

अंत में, बाल टुकड़ा एनीमेशन की अवधि संसाधन फ़ाइल में सेट की गई है।

मान / integers.xml

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

0

जानवर के टुकड़े के चेतन प्रसार के लिए हम चाइल्डफ्रैगमेंट मैनजर पर पॉप बैक स्टैक को बाध्य कर सकते हैं। यह अग्नि संक्रमण एनीमेशन होगा। ऐसा करने के लिए हमें 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 बच्चों के टुकड़े हैं, दो माता-पिता के टुकड़ों के बीच विभाजन। मैं बिना किसी समस्या के प्रवेश, निकास, पॉप और धक्का के लिए संक्रमण प्राप्त करने में सक्षम हूं। कॉन्फ़िगरेशन परिवर्तन और बैक प्रेस भी सफलतापूर्वक संभाले हुए हैं।

समाधान का बड़ा हिस्सा मेरे बेसफ्रेगमेंट में है (मेरे बच्चों और माता-पिता के टुकड़ों द्वारा बढ़ाया गया टुकड़ा) 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()
}

गतिविधि और माता-पिता के टुकड़े इन बूलियन के राज्यों को स्थापित करने के लिए जिम्मेदार हैं। यह देखना आसान है कि मेरे उदाहरण प्रोजेक्ट से कैसे और कहां।

मैं अपने उदाहरण में समर्थन अंशों का उपयोग नहीं कर रहा हूं, लेकिन एक ही तर्क का उपयोग उनके साथ किया जा सकता है और उनके द्वारा किया जा सकता है।


0

इस समस्या को ठीक करने का एक सरल तरीका Fragmentमानक पुस्तकालय टुकड़ा वर्ग के बजाय इस लाइब्रेरी से कक्षा का उपयोग करना है :

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

एक साइड नोट के रूप में, पैकेज में एक उपयोगी प्रतिनिधि पैटर्न भी शामिल है जिसे कहा जाता है ContractFragmentकि आप माता-पिता के बच्चे के टुकड़े के रिश्ते का लाभ उठाते हुए अपने ऐप्स के निर्माण के लिए उपयोगी हो सकते हैं।


0

@Kcoppock के उपरोक्त उत्तर से,

यदि आपके पास गतिविधि-> टुकड़ा-> टुकड़े (एकाधिक स्टैकिंग, निम्नलिखित मदद करता है), तो सबसे अच्छा उत्तर एचएचओ के लिए एक छोटा संपादन।

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 (टुकड़ा)) पर थी, बाल एनिमेशन नहीं हो रहे थे।

मूल समस्या यह है कि बच्चे के टुकड़े तुरंत एनीमेशन से बाहर निकलने वाले माता-पिता के टुकड़े के लिए पूर्व निर्धारित हैं।

बाल टुकड़े कस्टम एनिमेशन पैरेंट फ्रैगमेंट हटाने पर निष्पादित नहीं होते हैं

जैसा कि दूसरों ने पाया है कि, 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()

यदि आप वास्तव में माता-पिता को हटाना चाहते हैं, तो आपको संभवतः एनीमेशन सुनने के लिए कस्टम एनीमेशन पर एक श्रोता स्थापित करना चाहिए, ताकि तब आप माता-पिता के टुकड़े (हटाने) पर सुरक्षित रूप से कुछ अंतिम रूप दे सकें। यदि आप ऐसा नहीं करते हैं, तो समय पर फैशन में, आप एनीमेशन को खत्म कर सकते हैं। एनबी एनीमेशन अपने स्वयं के अतुल्यकालिक कतार पर किया जाता है।

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()
}

हम अभी वर्तमान टुकड़े को छिपाते हैं और नया टुकड़ा जोड़ते हैं, जब एनीमेशन समाप्त हो जाता है तो हम पुराने टुकड़े को हटा देते हैं। इस तरह इसे एक जगह पर संभाला जाता है और कोई भी बिटमैप नहीं बनाया जाता है।

हमारी साइट का प्रयोग करके, आप स्वीकार करते हैं कि आपने हमारी Cookie Policy और निजता नीति को पढ़ और समझा लिया है।
Licensed under cc by-sa 3.0 with attribution required.