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


128

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

दो टुकड़े

कुछ UI ईवेंट पर (जैसे, Fragment B में किसी चीज़ पर टैप करना), हम चाहते हैं:

  • स्क्रीन के बाईं ओर स्लाइड करने के लिए खंड A
  • स्क्रीन के बाएं किनारे पर स्लाइड करने के लिए फ्रेग्मेंट बी और फ्रैगमेंट ए द्वारा खाली किए गए स्पॉट को लेने के लिए सिकोड़ें
  • Fragment C स्क्रीन के दाईं ओर से स्लाइड करने के लिए और Fragment B द्वारा खाली किए गए स्पॉट को लेने के लिए

और, BACK बटन प्रेस पर, हम चाहते हैं कि संचालन का वह सेट उलटा हो।

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


@Reto Meier ने उसी मूल प्रश्न के लिए इस लोकप्रिय उत्तर का योगदान दिया , यह दर्शाता है कि आप setCustomAnimations()a के साथ उपयोग करेंगे FragmentTransaction। दो-टुकड़े वाले परिदृश्य के लिए (उदाहरण के लिए, आप केवल प्रारंभ में A को देखें, और इसे एनिमेटेड प्रभावों का उपयोग करते हुए एक नए Fragment B के साथ बदलना चाहते हैं), मैं पूर्ण अनुबंध में हूं। तथापि:

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

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


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


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


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


2
क्या यह रोमेन गाई द्वारा पोस्ट किया गया कुछ ऐसा नहीं है? curious-creature.org/2011/02/22/…
फर्नांडो गैलेगो

1
@ ferdy182: वह टुकड़े AFAICT का उपयोग नहीं कर रहा है। नेत्रहीन, यह सही बुनियादी प्रभाव है, और मैं इसे खंड-आधारित उत्तर बनाने के प्रयास के लिए एक अन्य डेटा बिंदु के रूप में उपयोग करने में सक्षम हो सकता हूं। धन्यवाद!
कॉमन्सवेयर

1
बस एक विचार: मेरे नेक्सस 7 पर मानक ईमेल ऐप का एक समान (हालांकि पूरी तरह से समान नहीं) व्यवहार है - जो खुला स्रोत होना चाहिए।
क्रिस्टोफर ओर

4
ईमेल एप्लिकेशन एक कस्टम "थ्रीपैनलेयआउट" का उपयोग करता है जो बाएं हाथ के दृश्य की स्थिति को एनिमेट करता है, और अन्य दो दृश्यों की चौड़ाई / विज़िबिलिटी - जिनमें से प्रत्येक में प्रासंगिक फ़्रैगमेंट होता है।
क्रिस्टोफर ओर

2
अरे @CommonsWare मैं यहाँ अपने पूरे जवाब के साथ ppl को परेशान नहीं करूँगा, लेकिन आपके लिए एक ऐसा ही सवाल था जिसमें मैंने बहुत संतोषजनक जवाब दिया। तो, बस आपको सुझाव है कि आप इसे देखें (टिप्पणियों की भी जाँच करें): stackoverflow.com/a/14155204/906362
Budius

जवाबों:


67

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

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


उपयोग:

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बाएं फलक का वजन परम के रूप में हो जाता है, दूसरे दृश्य को देखते हुए weight=1

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

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

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

व्यू 2 सही है_ देखें 1

तथा

View3 है right_of View2

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

प्रत्येक बच्चे तक पहुँचने के लिए (ताकि आप इसे अपने फ्रैगमेंट से बुला सकें

public FrameLayout getLeftLayout() {}

public FrameLayout getMiddleLayout() {}

public FrameLayout getRightLayout() {}

नीचे 2 एनिमेशन दिखाए गए हैं


चरण 1

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

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

चरण 2

- के बारे में -! -------- स्क्रीन में ------

[View1] [View2] [_____ View3_____]


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

1
@CommonsWare scaleAnimation सिर्फ एक अमूर्त नाम है। वास्तव में कोई स्केलिंग नहीं होती है। यह वास्तव में दृश्य की चौड़ाई का आकार बदलता है। स्रोत की जाँच करें। LayoutResizer इसके लिए एक बेहतर नाम हो सकता है।
कमजोर

1
scaleXमूल्य के आसपास स्रोत की मेरी व्याख्या नहीं है View, हालांकि मैं चीजों की गलत व्याख्या कर सकता हूं।
कॉमन्सवेयर

1
@CommonsWare इस github.com/weakwire/3PaneLayout/blob/master/src/com/example/… को देखें। एनिमेशन को विस्तारित करने का एकमात्र कारण इंटरपोलिएटटाइम तक पहुंच प्राप्त करना है। p. उपलब्धता = (इंट) चौड़ाई; सभी जादू करता है और यह स्केल नहीं है। यह वास्तविक दृश्य आयाम हैं जो निर्दिष्ट समय के दौरान बदल जाते हैं।
कमजोर

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

31

ठीक है, यहाँ मेरा अपना समाधान है, प्रश्न के टिप्पणियों में @ क्रिस्टोफर के सुझाव के अनुसार, ईमेल एओएसपी ऐप से लिया गया है।

https://github.com/commonsguy/cw-omnibus/tree/master/Animation/ThreePane

@ कमजोर पड़ने का समाधान मेरी याद दिलाता है, हालांकि वह Animationएनिमेटरों के बजाय क्लासिक का उपयोग करता है , और वह RelativeLayoutस्थिति को लागू करने के लिए नियमों का उपयोग करता है। बाउंटी दृष्टिकोण से, वह संभवतया बाउंटी प्राप्त करेगा, जब तक कि कोई अन्य एक चालाक समाधान के साथ कोई उत्तर नहीं देता।


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

package com.commonsware.android.anim.threepane;

import android.animation.Animator;
import android.animation.AnimatorListenerAdapter;
import android.animation.ObjectAnimator;
import android.content.Context;
import android.util.AttributeSet;
import android.view.View;
import android.widget.LinearLayout;

public class ThreePaneLayout extends LinearLayout {
  private static final int ANIM_DURATION=500;
  private View left=null;
  private View middle=null;
  private View right=null;
  private int leftWidth=-1;
  private int middleWidthNormal=-1;

  public ThreePaneLayout(Context context, AttributeSet attrs) {
    super(context, attrs);
    initSelf();
  }

  void initSelf() {
    setOrientation(HORIZONTAL);
  }

  @Override
  public void onFinishInflate() {
    super.onFinishInflate();

    left=getChildAt(0);
    middle=getChildAt(1);
    right=getChildAt(2);
  }

  public View getLeftView() {
    return(left);
  }

  public View getMiddleView() {
    return(middle);
  }

  public View getRightView() {
    return(right);
  }

  public void hideLeft() {
    if (leftWidth == -1) {
      leftWidth=left.getWidth();
      middleWidthNormal=middle.getWidth();
      resetWidget(left, leftWidth);
      resetWidget(middle, middleWidthNormal);
      resetWidget(right, middleWidthNormal);
      requestLayout();
    }

    translateWidgets(-1 * leftWidth, left, middle, right);

    ObjectAnimator.ofInt(this, "middleWidth", middleWidthNormal,
                         leftWidth).setDuration(ANIM_DURATION).start();
  }

  public void showLeft() {
    translateWidgets(leftWidth, left, middle, right);

    ObjectAnimator.ofInt(this, "middleWidth", leftWidth,
                         middleWidthNormal).setDuration(ANIM_DURATION)
                  .start();
  }

  public void setMiddleWidth(int value) {
    middle.getLayoutParams().width=value;
    requestLayout();
  }

  private void translateWidgets(int deltaX, View... views) {
    for (final View v : views) {
      v.setLayerType(View.LAYER_TYPE_HARDWARE, null);

      v.animate().translationXBy(deltaX).setDuration(ANIM_DURATION)
       .setListener(new AnimatorListenerAdapter() {
         @Override
         public void onAnimationEnd(Animator animation) {
           v.setLayerType(View.LAYER_TYPE_NONE, null);
         }
       });
    }
  }

  private void resetWidget(View v, int width) {
    LinearLayout.LayoutParams p=
        (LinearLayout.LayoutParams)v.getLayoutParams();

    p.width=width;
    p.weight=0;
  }
}

हालाँकि, रनटाइम के दौरान, कोई फर्क नहीं पड़ता कि आपने मूल रूप से चौड़ाई कैसे सेट की है, चौड़ाई प्रबंधन ThreePaneLayoutपहली बार आपके द्वारा उपयोग hideLeft()किया जाता है जो यह दिखाने से स्विच करता है कि किस प्रश्न को फ़्रैगमेंट ए और बी के रूप में फ्रैगमेंट्स बी और सी की शब्दावली में कहा गया है। ThreePaneLayout- जो टुकड़े करने के लिए कोई विशेष संबंध है - तीन टुकड़े कर रहे हैं left, middleऔर right। जिस समय आप कॉल करते हैं hideLeft(), हम उन आकारों को रिकॉर्ड करते हैं leftऔर middleउन तीनों में से किसी भी वजन का उपयोग करते हैं, जो पूरी तरह से आकार को नियंत्रित कर सकता है। समय के बिंदु पर hideLeft(), हम के आकार rightको मूल आकार के रूप में निर्धारित करते हैं middle

एनिमेशन दो गुना हैं:

  • एक का प्रयोग करें ViewPropertyAnimatorकी चौड़ाई से बाईं ओर तीन विजेट की एक अनुवाद प्रदर्शन करने के लिए left, एक हार्डवेयर परत का उपयोग
  • एक का उपयोग करें ObjectAnimatorके एक कस्टम छद्म संपत्ति पर middleWidthबदलने के लिए middleजो कुछ भी इसके बारे में मूल चौड़ाई के साथ शुरू किया था से चौड़ाईleft

(यह संभव है कि इन सभी के लिए AnimatorSetऔर ObjectAnimatorsइनका उपयोग करना एक बेहतर विचार है , हालांकि यह अभी के लिए काम करता है)

(यह भी संभव है कि middleWidth ObjectAnimatorहार्डवेयर लेयर का मान नगण्य हो, क्योंकि इसके लिए काफी निरंतर अमान्यकरण की आवश्यकता होती है)

(यह निश्चित रूप से संभव है कि मुझे अभी भी मेरे एनीमेशन की समझ में अंतराल है, और यह कि मुझे माता-पिता के कथन पसंद हैं)

शुद्ध प्रभाव यह है कि leftस्क्रीन से middleस्लाइड, मूल स्थिति और आकार के लिए स्लाइड left, और rightसही में अनुवाद करता है middle

showLeft() बस एनिमेटर्स के एक ही मिश्रण के साथ, विपरीत दिशाओं के साथ, प्रक्रिया को उलट देता है।

गतिविधि ThreePaneLayoutएक जोड़ी ListFragmentविजेट्स और एक को पकड़ने के लिए उपयोग करती है Button। बाईं ओर के टुकड़े में कुछ चुनकर बीच के टुकड़े को जोड़ता है (या सामग्री को अपडेट करता है)। बीच के टुकड़े में कुछ चुनकर कैप्शन सेट किया जाता है Button, और साथ में निष्पादित hideLeft()होता है ThreePaneLayout। BACK दबाने पर, यदि हम बाईं ओर छिपाते हैं, निष्पादित करेंगे showLeft(); अन्यथा, BACK गतिविधि से बाहर निकलता है। चूंकि यह FragmentTransactionsएनिमेशन को प्रभावित करने के लिए उपयोग नहीं करता है , इसलिए हम स्वयं "बैक स्टैक" का प्रबंधन कर रहे हैं।

जुड़ा हुआ प्रोजेक्ट ऊपर-ऊपर देशी टुकड़ों और देशी एनिमेटर फ्रेमवर्क का उपयोग करता है। मेरे पास उसी परियोजना का एक और संस्करण है जो एनीमेशन के लिए एंड्रॉइड सपोर्ट के टुकड़े और NineOldAndroids का उपयोग करता है :

https://github.com/commonsguy/cw-omnibus/tree/master/Animation/ThreePaneBC

बैकपोर्ट 1 पीढ़ी के किंडल फायर पर ठीक काम करता है, हालांकि एनीमेशन थोड़ा झटकेदार होता है, जिसमें निचले हार्डवेयर स्पेक्स और हार्डवेयर त्वरण समर्थन की कमी होती है। दोनों कार्यान्वयन एक नेक्सस 7 और अन्य वर्तमान-पीढ़ी के टैबलेट पर सहज लगते हैं।

मैं निश्चित रूप से इस समाधान को बेहतर बनाने के विचारों के लिए खुला हूं, या अन्य समाधान जो कि मैंने यहां क्या किया (या क्या @weakwire उपयोग किया गया है) पर स्पष्ट लाभ प्रदान करते हैं।

फिर से धन्यवाद जिन्होंने योगदान दिया है!


1
नमस्ते! समाधान के लिए धन्यवाद, लेकिन मुझे लगता है, v.setLayerType () को जोड़ना कभी-कभी चीजों को थोड़ा धीमा कर देता है। बस इन पंक्तियों को हटा दें (और श्रोता को भी) यह कम से कम Android 3+ उपकरणों के लिए सच है, जो मैंने अभी-अभी गैलेक्सी नेक्सस पर आजमाया है और इन पंक्तियों के बिना यह बहुत बेहतर काम कर रहा है
इवगेनी नेकु

1
"दोनों कार्यान्वयन नेक्सस 7 और अन्य वर्तमान-पीढ़ी के टैबलेट पर सहज लगते हैं।" मुझे तुम पर विश्वास है; लेकिन मैं एक Nexus 7 पर देशी ObjectAimimator के साथ आपके कार्यान्वयन का परीक्षण कर रहा हूं और यह थोड़ा पीछे है। सबसे संभावित कारण क्या होंगे? AndroidMAnifest में सच है: मेरे पास पहले से ही हार्डवेयर सक्रिय है। मैं वास्तव में नहीं जानता कि समस्या क्या हो सकती है। मैंने डैनियलग्रेच के वैरिएंट को भी आजमाया है और यह वही है। मैं एनीमेशन में अंतर देख सकता हूं (उनका एनीमेशन वजन पर आधारित है), लेकिन मैं यह नहीं देख सकता कि यह दोनों मामलों में क्यों पिछड़ जाएगा।
बोगदान ज़ुरैक

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

2
@CommonsWare: मैंने आपके कोड को 4.2, महान काम के साथ संकलित किया है। जब मैंने मध्य पर टैप किया ListViewऔर जल्दी और बार-बार बैक बटन दबाया तो पूरा लेआउट दाईं ओर चला गया। इसने बाईं ओर अतिरिक्त स्थान स्तंभ दिखाना शुरू कर दिया। यह व्यवहार इसलिए शुरू हुआ क्योंकि मैंने पहले एनीमेशन (मध्य पर टैप करके शुरू ListView) को पूरा नहीं होने दिया और बैक बटन दबाया। मैं बदल कर यह तय translationXByसाथ translationXमें translateWidgetsविधि और translateWidgets(leftWidth, left, middle, right);साथ translateWidgets(0, left, middle, right);में showLeft()विधि।
एम-वाजेह

2
मैं भी बदल दिया requestLayout();साथ middle.requestLayout();में setMiddleWidth(int value);विधि। यह प्रदर्शन को प्रभावित नहीं कर सकता क्योंकि मुझे लगता है कि GPU अभी भी एक पूर्ण लेआउट पास, कोई टिप्पणी करेगा?
एम-वाजेह

13

हमने PanesLibrary नामक एक पुस्तकालय का निर्माण किया जो इस समस्या को हल करता है। यह पहले की पेशकश की गई तुलना में अधिक लचीला है क्योंकि:

  • प्रत्येक फलक गतिशील रूप से आकार में हो सकता है
  • यह किसी भी संख्या में पैन की अनुमति देता है (सिर्फ 2 या 3 नहीं)
  • पैन के अंदर के टुकड़े को उन्मुखीकरण परिवर्तनों पर सही ढंग से रखा गया है।

आप इसे यहां देख सकते हैं: https://github.com/Mapsaurus/Android-PanesLibrary

यहाँ एक डेमो है: http://www.youtube.com/watch?v=UA-lAGVXoLU&feature=youtu.be

यह मूल रूप से आपको गतिशील रूप से आकार के किसी भी पैन को आसानी से जोड़ने और उन पैन में टुकड़े संलग्न करने की अनुमति देता है। उम्मीद है यह आपको उपयोगी होगा! :)


6

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

एक साधारण लेआउट से शुरू करें। चूंकि हम एनिमेशन करने जा रहे हैं layout_weight, हमें LinearLayout3 पैनलों के लिए मूल दृश्य की आवश्यकता है :

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


1
खैर, जीमेल निश्चित रूप से मेरे द्वारा वर्णित फ्रेगमेंट ए के रूप में एक अनुवाद करता है। मुझे चिंता होगी कि इसके वजन को कम करने से दृश्य कलाकृतियों को पेश किया जा सकता है (उदाहरण के लिए, एनीमेशन के रूप में लंबवत रूप से खुद TextViewको wrap_contentखींचकर)। हालांकि, यह हो सकता है कि वजन को एनिमेट करना यह है कि वे कैसे आकार देते हैं जिसे मैंने फ्रैगमेंट बी के रूप में संदर्भित किया था! धन्यवाद!
कॉमन्सवेयर

1
कोई चिंता नहीं! हालांकि यह एक अच्छा बिंदु है, इससे बच्चे के विचारों में 'फ्रैगमेंट ए' के ​​आधार पर दृश्य कलाकृतियों की संभावना होगी। चलो आशा करते हैं कि कोई इसे करने के लिए एक और अधिक ठोस तरीका
ढूंढता है

5

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

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

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

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


मैंने पहले कभी "शो लेआउट सीमा" का उपयोग नहीं किया था - जो इस तरह बंद स्रोत एप्लिकेशन के लिए बहुत उपयोगी है (धन्यवाद!)। ऐसा प्रतीत होता है कि जिसे मैंने फ्रैगमेंट ए के रूप में वर्णित किया था, वह ऑफ-स्क्रीन का अनुवाद कर रहा है (आप इसकी दाईं ओर की स्लाइड को राइट-टू-लेफ्ट देख सकते हैं), इससे पहले कि मैंने फ्रैगमेंट बी के रूप में जो वर्णन किया है, उसमें नीचे पॉप करने से पहले ऐसा महसूस होता है TranslateAnimation, हालांकि मैं सुनिश्चित करें कि समान सिरों को पूरा करने के लिए एनिमेटरों का उपयोग करने के तरीके हैं। मुझे इस पर कुछ प्रयोग करने होंगे। धन्यवाद!
कॉमन्सवेयर सेप

2

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

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

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

FragmentB का उपयोग लेआउट_toLeftOf / ToRightOf इसे खंड A और C से जोड़े रखने के लिए।

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

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

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

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

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