android - जीमेल थ्री-फ्रैगमेंट एनिमेशन परिदृश्य का पूरा कार्य नमूना?




android-fragments android-animation (4)

Github पर मेरा प्रस्ताव अपलोड किया गया है (सभी एंड्रॉइड संस्करणों के साथ काम कर रहा है हालांकि हार्डवेयर त्वरण को इस तरह के एनिमेशन के लिए दृढ़ता से अनुशंसा की जाती है। गैर हार्डवेयर त्वरित उपकरणों के लिए बिटमैप कैशिंग कार्यान्वयन बेहतर फिट होना चाहिए)

एनीमेशन के साथ डेमो वीडियो Here (स्क्रीन कास्ट का धीमा फ्रेम दर कारण। वास्तविक प्रदर्शन बहुत तेज़ है)

उपयोग:

layout = new ThreeLayout(this, 3);
layout.setAnimationDuration(1000);
setContentView(layout);
layout.getLeftView();   //<---inflate FragmentA here
layout.getMiddleView(); //<---inflate FragmentB here
layout.getRightView();  //<---inflate FragmentC here

//Left Animation set
layout.startLeftAnimation();

//Right Animation set
layout.startRightAnimation();

//You can even set interpolators

व्याख्या :

एक नया कस्टम रिलेवेटिवआउट (थ्रीलाउट) और 2 कस्टम एनीमेशन (MyScalAnimation, MyTranslateAnimation) बनाया

ThreeLayout बाएं फलक का वजन param के रूप में मिलता है, मानते हैं कि अन्य दृश्यमान दृश्य weight=1

तो new ThreeLayout(context,3) 3 बच्चों और बाएं फलक के साथ एक नया दृश्य बनाता है जिसमें कुल स्क्रीन का 1/3 है। अन्य दृश्य सभी उपलब्ध स्थान पर है।

यह रनटाइम पर चौड़ाई की गणना करता है, एक सुरक्षित कार्यान्वयन यह है कि पहली बार ड्रायटर्स की गणना ड्रॉ () में की जाती है। पद के बजाय ()

स्केल और अनुवाद एनिमेशन वास्तव में आकार बदलते हैं और दृश्य को स्थानांतरित करते हैं और छद्म- [स्केल, चाल] नहीं। ध्यान दें कि fillAfter(true) कहीं भी उपयोग नहीं किया जाता है।

View2 सही है I1 देखें

तथा

व्यू 3 व्यू 2 है

इन नियमों को सेट करने से संबंधित LAYout अन्य सभी का ख्याल रखता है। एनिमेशन margins (चाल पर) और [width,height] पैमाने पर बदलते हैं

प्रत्येक बच्चे तक पहुंचने के लिए (ताकि आप इसे अपने टुकड़े से फुला सकें जिसे आप कॉल कर सकते हैं

public FrameLayout getLeftLayout() {}

public FrameLayout getMiddleLayout() {}

public FrameLayout getRightLayout() {}

नीचे 2 एनिमेशन प्रदर्शित किए गए हैं

चरण 1

--- स्क्रीन में ----------! ----- आउट ----

[View1] [_____ View2 _____] [_____ View3_____]

चरण 2

--OUT -! -------- स्क्रीन में ------

[View1] [View2] [_____ View3_____]

टीएल; डीआर: मैं "जीमेल तीन-खंड एनीमेशन" परिदृश्य के रूप में संदर्भित करने के लिए एक पूर्ण कामकाजी नमूना ढूंढ रहा हूं। विशेष रूप से, हम इस तरह के दो टुकड़ों से शुरू करना चाहते हैं:

कुछ यूआई घटना पर (उदाहरण के लिए, फ्रैगमेंट बी में कुछ पर टैप करना), हम चाहते हैं:

  • स्क्रीन को बाईं ओर स्क्रीन से स्लाइड करने के लिए खंडन ए
  • स्क्रीन के बाएं किनारे पर स्लाइड करने के लिए फ्रैगमेंट बी और फ्रैगमेंट ए द्वारा खाली स्थान को लेने के लिए संक्षिप्त करें
  • स्क्रीन के दाईं ओर से स्लाइड करने के लिए फ्रैगमेंट सी और फ्रैगमेंट बी द्वारा खाली स्थान लेना

और, एक बैक बटन प्रेस पर, हम चाहते हैं कि संचालन के सेट को उलट दिया जाए।

अब, मैंने बहुत सारे आंशिक कार्यान्वयन देखा है; मैं नीचे उनमें से चार की समीक्षा करूंगा। अपूर्ण होने से परे, उनके सभी के पास समस्याएं हैं।

@ रीटो मेयर ने एक ही मूल प्रश्न के इस लोकप्रिय उत्तर का योगदान दिया, यह दर्शाता है कि आप FragmentTransaction साथ setCustomAnimations() उपयोग करेंगे। दो टुकड़े परिदृश्य के लिए (उदाहरण के लिए, आप केवल शुरुआत में फ्रैगमेंट ए देखते हैं, और इसे एनिमेटेड प्रभावों का उपयोग करके एक नए टुकड़े बी के साथ प्रतिस्थापित करना चाहते हैं), मैं पूर्ण समझौते में हूं। तथापि:

  • चूंकि आप केवल एक "इन" और एक "आउट" एनीमेशन निर्दिष्ट कर सकते हैं, इसलिए मैं नहीं देख सकता कि आप तीन खंड परिदृश्य के लिए आवश्यक सभी अलग-अलग एनिमेशन कैसे प्रबंधित करेंगे
  • <objectAnimator> अपने नमूना कोड में हार्ड-वायर्ड पोजिशन का उपयोग पिक्सल में करता है, और यह अलग-अलग स्क्रीन आकारों के साथ अव्यवहारिक प्रतीत होता है, फिर भी setCustomAnimations() एनीमेशन setCustomAnimations() को एनीमेशन संसाधनों की आवश्यकता होती है, जिससे जावा में इन चीजों को परिभाषित करने की संभावना को रोक दिया जाता है।
  • मैं android:layout_weight जैसी चीजों के साथ स्केल टाई के लिए ऑब्जेक्ट एनिमेटर्स के नुकसान के कारण हूं android:layout_weight प्रतिशत आधार पर स्थान आवंटित करने के लिए LinearLayout में LinearLayout
  • मुझे इस बात की हानि है कि शुरुआत में फ्रैगमेंट सी को कैसे संभाला जाता है ( GONE ? android:layout_weight 0 android:layout_weight ? 0 पैमाने पर प्री-एनिमेटेड? कुछ और?)

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

इस पेस्टबिन एंट्री के लेखक ने कुछ टैंटालाइजिंग स्यूडोकोड दिखाया है, मूल रूप से यह कहकर कि तीनों टुकड़े प्रारंभ में कंटेनर में रहेंगे, फ्रैगमेंट सी ने एक छिपे हुए hide() लेनदेन ऑपरेशन के माध्यम से शुरुआत में hide() था। फिर हम show() सी और hide() ए जब यूआई घटना होती है। हालांकि, मुझे नहीं लगता कि यह इस तथ्य को कैसे संभालता है कि बी आकार बदलता है। यह इस तथ्य पर भी निर्भर करता है कि आप स्पष्ट रूप से एक ही कंटेनर में कई टुकड़े जोड़ सकते हैं, और मुझे यकीन नहीं है कि यह लंबे समय तक विश्वसनीय व्यवहार है या नहीं (इसका उल्लेख नहीं करना चाहिए कि इसे तोड़ना चाहिए findFragmentById() , हालांकि मैं साथ रह सकता हूं उस)।

इस ब्लॉग पोस्ट के लेखक इंगित करते हैं कि जीमेल setCustomAnimations() का उपयोग नहीं कर रहा है, बल्कि इसके बजाय सीधे ऑब्जेक्ट एनिमेटर्स का उपयोग करता है ("आप रूट व्यू के बाएं हाशिए को बदलते हैं + सही दृश्य की चौड़ाई बदलते हैं")। हालांकि, यह अभी भी एक दो खंड समाधान AFAICT है, और कार्यान्वयन एक बार फिर हार्ड-वायर आयाम पिक्सल में दिखाया गया है।

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


आपके द्वारा लिंक किए गए उदाहरणों में से एक को बंद करना ( http://android.amberfog.com/?p=758 ), layout_weight संपत्ति को एनिमेट करने के बारे में कैसे? इस तरह, आप एक साथ 3 टुकड़ों के वजन में परिवर्तन को एनिमेट कर सकते हैं, और आपको बोनस मिलता है कि वे सभी अच्छी तरह से एक साथ स्लाइड करते हैं:

एक साधारण लेआउट के साथ शुरू करें। चूंकि हम layout_weight एनिमेट करने जा रहे हैं, इसलिए हमें 3 पैनलों के रूट रूट के रूप में एक LinearLayout आवश्यकता है .:

<?xml version="1.0" encoding="utf-8"?>
<LinearLayout
xmlns:android="http://schemas.android.com/apk/res/android"
android:id="@+id/container"
android:orientation="horizontal"
android:layout_width="match_parent"
android:layout_height="match_parent">

<LinearLayout
    android:id="@+id/panel1"
    android:layout_width="0dip"
    android:layout_weight="1"
    android:layout_height="match_parent"/>

<LinearLayout
    android:id="@+id/panel2"
    android:layout_width="0dip"
    android:layout_weight="2"
    android:layout_height="match_parent"/>

<LinearLayout
    android:id="@+id/panel3"
    android:layout_width="0dip"
    android:layout_weight="0"
    android:layout_height="match_parent"/>
</LinearLayout>

फिर डेमो वर्ग:

public class DemoActivity extends Activity implements View.OnClickListener {
    public static final int ANIM_DURATION = 500;
    private static final Interpolator interpolator = new DecelerateInterpolator();

    boolean isCollapsed = false;

    private Fragment frag1, frag2, frag3;
    private ViewGroup panel1, panel2, panel3;

    @Override
    public void onCreate(Bundle savedInstanceState) {
        super.onCreate(savedInstanceState);
        setContentView(R.layout.main);

        panel1 = (ViewGroup) findViewById(R.id.panel1);
        panel2 = (ViewGroup) findViewById(R.id.panel2);
        panel3 = (ViewGroup) findViewById(R.id.panel3);

        frag1 = new ColorFrag(Color.BLUE);
        frag2 = new InfoFrag();
        frag3 = new ColorFrag(Color.RED);

        final FragmentManager fm = getFragmentManager();
        final FragmentTransaction trans = fm.beginTransaction();

        trans.replace(R.id.panel1, frag1);
        trans.replace(R.id.panel2, frag2);
        trans.replace(R.id.panel3, frag3);

        trans.commit();
    }

    @Override
    public void onClick(View view) {
        toggleCollapseState();
    }

    private void toggleCollapseState() {
        //Most of the magic here can be attributed to: http://android.amberfog.com/?p=758

        if (isCollapsed) {
            PropertyValuesHolder[] arrayOfPropertyValuesHolder = new PropertyValuesHolder[3];
            arrayOfPropertyValuesHolder[0] = PropertyValuesHolder.ofFloat("Panel1Weight", 0.0f, 1.0f);
            arrayOfPropertyValuesHolder[1] = PropertyValuesHolder.ofFloat("Panel2Weight", 1.0f, 2.0f);
            arrayOfPropertyValuesHolder[2] = PropertyValuesHolder.ofFloat("Panel3Weight", 2.0f, 0.0f);
            ObjectAnimator localObjectAnimator = ObjectAnimator.ofPropertyValuesHolder(this, arrayOfPropertyValuesHolder).setDuration(ANIM_DURATION);
            localObjectAnimator.setInterpolator(interpolator);
            localObjectAnimator.start();
        } else {
            PropertyValuesHolder[] arrayOfPropertyValuesHolder = new PropertyValuesHolder[3];
            arrayOfPropertyValuesHolder[0] = PropertyValuesHolder.ofFloat("Panel1Weight", 1.0f, 0.0f);
            arrayOfPropertyValuesHolder[1] = PropertyValuesHolder.ofFloat("Panel2Weight", 2.0f, 1.0f);
            arrayOfPropertyValuesHolder[2] = PropertyValuesHolder.ofFloat("Panel3Weight", 0.0f, 2.0f);
            ObjectAnimator localObjectAnimator = ObjectAnimator.ofPropertyValuesHolder(this, arrayOfPropertyValuesHolder).setDuration(ANIM_DURATION);
            localObjectAnimator.setInterpolator(interpolator);
            localObjectAnimator.start();
        }
        isCollapsed = !isCollapsed;
    }

    @Override
    public void onBackPressed() {
        //TODO: Very basic stack handling. Would probably want to do something relating to fragments here..
        if(isCollapsed) {
            toggleCollapseState();
        } else {
            super.onBackPressed();
        }
    }

    /*
     * Our magic getters/setters below!
     */

    public float getPanel1Weight() {
        LinearLayout.LayoutParams params = (LinearLayout.LayoutParams)     panel1.getLayoutParams();
        return params.weight;
    }

    public void setPanel1Weight(float newWeight) {
        LinearLayout.LayoutParams params = (LinearLayout.LayoutParams) panel1.getLayoutParams();
        params.weight = newWeight;
        panel1.setLayoutParams(params);
    }

    public float getPanel2Weight() {
        LinearLayout.LayoutParams params = (LinearLayout.LayoutParams) panel2.getLayoutParams();
        return params.weight;
    }

    public void setPanel2Weight(float newWeight) {
        LinearLayout.LayoutParams params = (LinearLayout.LayoutParams) panel2.getLayoutParams();
        params.weight = newWeight;
        panel2.setLayoutParams(params);
    }

    public float getPanel3Weight() {
        LinearLayout.LayoutParams params = (LinearLayout.LayoutParams) panel3.getLayoutParams();
        return params.weight;
    }

    public void setPanel3Weight(float newWeight) {
        LinearLayout.LayoutParams params = (LinearLayout.LayoutParams) panel3.getLayoutParams();
        params.weight = newWeight;
        panel3.setLayoutParams(params);
    }


    /**
     * Crappy fragment which displays a toggle button
     */
    public static class InfoFrag extends Fragment {
        @Override
        public View onCreateView(LayoutInflater inflater, ViewGroup container, Bundle     savedInstanceState) {
            LinearLayout layout = new LinearLayout(getActivity());
            layout.setLayoutParams(new LayoutParams(LayoutParams.MATCH_PARENT, LayoutParams.MATCH_PARENT));
            layout.setBackgroundColor(Color.DKGRAY);

            Button b = new Button(getActivity());
            b.setOnClickListener((DemoActivity) getActivity());
            b.setText("Toggle Me!");

            layout.addView(b);

            return layout;
        }
    }

    /**
     * Crappy fragment which just fills the screen with a color
     */
    public static class ColorFrag extends Fragment {
        private int mColor;

        public ColorFrag() {
            mColor = Color.BLUE; //Default
        }

        public ColorFrag(int color) {
            mColor = color;
        }

        @Override
        public View onCreateView(LayoutInflater inflater, ViewGroup container, Bundle savedInstanceState) {
            FrameLayout layout = new FrameLayout(getActivity());
            layout.setLayoutParams(new LayoutParams(LayoutParams.MATCH_PARENT, LayoutParams.MATCH_PARENT));

            layout.setBackgroundColor(mColor);
            return layout;
        }
    }
}

इसके अलावा यह उदाहरण एनिमेशन प्राप्त करने के लिए FragmentTransactions का उपयोग नहीं करता है (बल्कि, यह उन दृश्यों को एनिमेट करता है जो टुकड़े संलग्न होते हैं), इसलिए आपको अपने सभी बैकस्टैक / खंड लेनदेन को करने की आवश्यकता होगी, लेकिन एनिमेशन को काम करने के प्रयास की तुलना में अच्छी तरह से, यह एक बुरा व्यापार बंद की तरह प्रतीत नहीं होता :)

कार्रवाई में भयानक कम-रेज वीडियो: http://youtu.be/Zm517j3bFCo


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

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

तो, मैं लेआउट एनिमेट करता हूं, मैं टुकड़े लेनदेन का उपयोग नहीं कर रहा हूं। यदि यह खुला है तो मैं खंड सी को बंद करने के लिए मैन्युअल रूप से बैक बटन को संभालता हूं।

FragmentB का उपयोग लेआउट_toLeftOf / ToRightOf को खंड ए और सी में गठबंधन रखने के लिए करें।

जब मेरा ऐप खंड सी को प्रदर्शित करने के लिए एक ईवेंट ट्रिगर करता है, तो मैं खंड-सी में स्लाइड करता हूं, और मैं एक ही समय में खंड ए को स्लाइड आउट करता हूं। (2 अलग एनीमेशन)। उलटा, जब टुकड़ा एक खुला, मैं एक ही समय में सी बंद कर दिया।

पोर्ट्रेट मोड में या छोटी स्क्रीन पर, मैं स्क्रीन पर थोड़ा अलग लेआउट और स्लाइड फ्रेगमेंट सी का उपयोग करता हूं।

फ्रैगमेंट ए और सी की चौड़ाई के लिए प्रतिशत का उपयोग करने के लिए, मुझे लगता है कि आपको इसे रन टाइम पर गणना करना होगा ... (?)

गतिविधि का लेआउट यहां दिया गया है:

<?xml version="1.0" encoding="utf-8"?>
<RelativeLayout xmlns:android="http://schemas.android.com/apk/res/android"
    android:id="@+id/rootpane"
    android:layout_width="fill_parent"
    android:layout_height="fill_parent">

    <!-- FRAGMENT A -->
    <fragment
        android:id="@+id/fragment_A"
        android:layout_width="300dp"
        android:layout_height="fill_parent"
        class="com.xyz.fragA" />

    <!-- FRAGMENT C -->
    <fragment
        android:id="@+id/fragment_C"
        android:layout_width="600dp"
        android:layout_height="match_parent"
        android:layout_alignParentRight="true"
        class="com.xyz.fragC"/>

    <!-- FRAGMENT B -->
    <fragment
        android:id="@+id/fragment_B"
        android:layout_width="match_parent"
        android:layout_height="fill_parent"
        android:layout_marginLeft="0dip"
        android:layout_marginRight="0dip"
        android:layout_toLeftOf="@id/fragment_C"
        android:layout_toRightOf="@id/fragment_A"
        class="com.xyz.fragB" />

</RelativeLayout>

FragmentC को अंदर या बाहर स्लाइड करने के लिए एनीमेशन:

private ValueAnimator createFragmentCAnimation(final View fragmentCRootView, boolean slideIn) {

    ValueAnimator anim = null;

    final RelativeLayout.LayoutParams lp = (RelativeLayout.LayoutParams) fragmentCRootView.getLayoutParams();
    if (slideIn) {
        // set the rightMargin so the view is just outside the right edge of the screen.
        lp.rightMargin = -(lp.width);
        // the view's visibility was GONE, make it VISIBLE
        fragmentCRootView.setVisibility(View.VISIBLE);
        anim = ValueAnimator.ofInt(lp.rightMargin, 0);
    } else
        // slide out: animate rightMargin until the view is outside the screen
        anim = ValueAnimator.ofInt(0, -(lp.width));

    anim.setInterpolator(new DecelerateInterpolator(5));
    anim.setDuration(300);
    anim.addUpdateListener(new AnimatorUpdateListener() {

        @Override
        public void onAnimationUpdate(ValueAnimator animation) {
            Integer rightMargin = (Integer) animation.getAnimatedValue();
            lp.rightMargin = rightMargin;
            fragmentCRootView.requestLayout();
        }
    });

    if (!slideIn) {
        // if the view was sliding out, set visibility to GONE once the animation is done
        anim.addListener(new AnimatorListenerAdapter() {

            @Override
            public void onAnimationEnd(Animator animation) {
                fragmentCRootView.setVisibility(View.GONE);
            }
        });
    }
    return anim;
}

यह टुकड़ों का उपयोग नहीं कर रहा है .... यह 3 बच्चों के साथ एक कस्टम लेआउट है। जब आप किसी संदेश पर क्लिक करते हैं, तो आप offsetLeftAndRight() और एनिमेटर का उपयोग करके 3 बच्चों को ऑफसेट करते हैं।

JellyBean आप "डेवलपर विकल्प" सेटिंग्स में "लेआउट सीमाएं दिखाएं" सक्षम कर सकते हैं। जब स्लाइड एनीमेशन पूर्ण हो जाता है, तब भी आप देख सकते हैं कि बायां मेनू अभी भी है, लेकिन मध्य पैनल के नीचे है।

यह सिरिल मोटीयर के फ्लाई-इन ऐप मेनू के समान है, लेकिन 2 के बजाय 3 तत्वों के साथ।

अतिरिक्त रूप से, तीसरे बच्चों का ViewPager इस व्यवहार का एक और संकेत है: ViewPager आमतौर पर टुकड़ों का उपयोग करता है (मुझे पता है कि उन्हें नहीं करना है, लेकिन मैंने कभी भी Fragment कार्यान्वयन को कभी नहीं देखा है), और चूंकि आप अंदर Fragments का उपयोग नहीं कर सकते एक और Fragment 3 बच्चे शायद टुकड़े नहीं हैं ....







android-animation