2014-10-24 11 views
8

मैं अपने ग्रिड व्यू को नए रीसाइक्लर व्यू (ग्रिडलेआउट मैनेजर का उपयोग करके) के साथ बदलने की कोशिश कर रहा हूं लेकिन ऐसा लगता है कि यह ग्रिडलेआउटएनीमेशन (ClassCastException: LayoutAnimationController$AnimationParameters cannot be cast to GridLayoutAnimationController$AnimationParameters) के साथ अच्छी तरह से सामना नहीं करता है। यह नियमित लेआउट एनीमेशन के साथ काम करता है, लेकिन क्योंकि यह एक ग्रिड है, टैबलेट पर पूरा होने में बहुत लंबा समय लगता है।मैं रीसाइक्लिंग व्यू में ग्रिडलाउट एनीमेशन का उपयोग कैसे करूं?

जो मैं पूरा करने की कोशिश कर रहा हूं वह Hierarchical Timing जैसा है। यदि आप उदाहरण वीडियो देखते हैं, तो यह लेआउट एनीमेशन को ऊपर-बाएं से नीचे दाएं दाएं दाएं से चलाता है। एक नियमित लेआउट एनीमेशन पंक्ति के बाद एनीमेशन पंक्ति निष्पादित करेगा, इसलिए बड़े ग्रिड (जैसे टेबलेट) पर पूरा करने के लिए बहुत अधिक समय लेना। मैंने ItemAnimator की खोज करने का भी प्रयास किया है, लेकिन यह केवल "सभी नहीं" उदाहरण में सभी कोशिकाओं पर एनीमेशन चलाएगा।

क्या रीसाइक्लिंग व्यू में इस ग्रिड लेआउट एनीमेशन को पूरा करने का कोई तरीका है?

यह gridview_layout_animation.xml है:

<!-- replace gridLayoutAnimation with layoutAnimation and --> 
<!-- replace column- and rowDelay with delay for RecyclerView --> 

<gridLayoutAnimation xmlns:android="http://schemas.android.com/apk/res/android" 
    android:columnDelay="15%" 
    android:rowDelay="15%" 
    android:animation="@anim/grow_in" 
    android:animationOrder="normal" 
    android:direction="top_to_bottom|left_to_right" 
    android:interpolator="@android:interpolator/linear" 
/> 

और इस एनीमेशन grow_in.xml है:

<set android:shareInterpolator="false" 
xmlns:android="http://schemas.android.com/apk/res/android"> 
    <scale 
     android:interpolator="@android:interpolator/decelerate_quint" 
     android:fromXScale="0.0" 
     android:toXScale="1.0" 
     android:fromYScale="0.0" 
     android:toYScale="1.0" 
     android:pivotX="50%" 
     android:pivotY="50%" 
     android:fillAfter="true" 
     android:duration="400" 
     android:startOffset="200" 
    /> 
</set> 

संपादित करें: Galaxas0 के जवाब के आधार पर, here एक है समाधान जो आपको केवल कस्टम दृश्य का उपयोग करने की आवश्यकता है जो RecyclerView बढ़ाता है। मूल रूप से केवल attachLayoutAnimationParameters() विधि को ओवरराइड करना। इस <gridLayoutAnimation> के साथ काम करता है जैसा कि यह ग्रिड व्यू के साथ किया गया था।

public class GridRecyclerView extends RecyclerView { 

    public GridRecyclerView(Context context) { 
     super(context); 
    } 

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

    public GridRecyclerView(Context context, AttributeSet attrs, int defStyle) { 
     super(context, attrs, defStyle); 
    } 

    @Override 
    public void setLayoutManager(LayoutManager layout) { 
     if (layout instanceof GridLayoutManager){ 
      super.setLayoutManager(layout); 
     } else { 
      throw new ClassCastException("You should only use a GridLayoutManager with GridRecyclerView."); 
      } 
     } 

    @Override 
    protected void attachLayoutAnimationParameters(View child, ViewGroup.LayoutParams params, int index, int count) { 

     if (getAdapter() != null && getLayoutManager() instanceof GridLayoutManager){ 

      GridLayoutAnimationController.AnimationParameters animationParams = 
       (GridLayoutAnimationController.AnimationParameters) params.layoutAnimationParameters; 

      if (animationParams == null) { 
       animationParams = new GridLayoutAnimationController.AnimationParameters(); 
       params.layoutAnimationParameters = animationParams; 
      } 

      int columns = ((GridLayoutManager) getLayoutManager()).getSpanCount(); 

      animationParams.count = count; 
      animationParams.index = index; 
      animationParams.columnsCount = columns; 
      animationParams.rowsCount = count/columns; 

      final int invertedIndex = count - 1 - index; 
      animationParams.column = columns - 1 - (invertedIndex % columns); 
      animationParams.row = animationParams.rowsCount - 1 - invertedIndex/columns; 

     } else { 
      super.attachLayoutAnimationParameters(child, params, index, count); 
     } 
    } 
} 

उत्तर

5

LayoutAnimationControllerViewGroup में युग्मित है और दोनों ListView और GridView प्रदान करने के लिए नीचे दी गई विधि का विस्तार बच्चे की animationParams। मुद्दा यह है कि GridLayoutAnimationController को अपने स्वयं के AnimationParameters की आवश्यकता है जिसे क्लास-कास्ट नहीं किया जा सकता है।

/** 
    * Subclasses should override this method to set layout animation 
    * parameters on the supplied child. 
    * 
    * @param child the child to associate with animation parameters 
    * @param params the child's layout parameters which hold the animation 
    *  parameters 
    * @param index the index of the child in the view group 
    * @param count the number of children in the view group 
    */ 
    protected void attachLayoutAnimationParameters(View child, 
      LayoutParams params, int index, int count) { 
     LayoutAnimationController.AnimationParameters animationParams = 
        params.layoutAnimationParameters; 
     if (animationParams == null) { 
      animationParams = new LayoutAnimationController.AnimationParameters(); 
      params.layoutAnimationParameters = animationParams; 
     } 

     animationParams.count = count; 
     animationParams.index = index; 
    } 

के बाद डिफ़ॉल्ट रूप से इस विधि GridLayoutAnimationController.AnimationParameters के बजाय एक LayoutAnimationController.AnimationParameters कहते हैं, ठीक बना सकते हैं और पहले से एक संलग्न करने के लिए होना चाहिए। क्या हम लागू करने की आवश्यकता क्या GridView पहले से ही करता है:

@Override 
protected void attachLayoutAnimationParameters(View child, 
     ViewGroup.LayoutParams params, int index, int count) { 

    GridLayoutAnimationController.AnimationParameters animationParams = 
      (GridLayoutAnimationController.AnimationParameters) params.layoutAnimationParameters; 

    if (animationParams == null) { 
     animationParams = new GridLayoutAnimationController.AnimationParameters(); 
     params.layoutAnimationParameters = animationParams; 
    } 

    animationParams.count = count; 
    animationParams.index = index; 
    animationParams.columnsCount = mNumColumns; 
    animationParams.rowsCount = count/mNumColumns; 

    if (!mStackFromBottom) { 
     animationParams.column = index % mNumColumns; 
     animationParams.row = index/mNumColumns; 
    } else { 
     final int invertedIndex = count - 1 - index; 

     animationParams.column = mNumColumns - 1 - (invertedIndex % mNumColumns); 
     animationParams.row = animationParams.rowsCount - 1 - invertedIndex/mNumColumns; 
    } 
} 

GridView को दोहराने के लिए, निकटतम बात हम कर सकते हैं onBindViewHolder() में संशोधनों जो उन्हें dispatchDraw से पहले चलाने की अनुमति देता जूता पहनने का साधन है, कॉल कि एनिमेशन से चलाता है।

ViewGroup.LayoutParams params = holder.itemView.getLayoutParams(); 
     GridLayoutAnimationController.AnimationParameters animationParams = new GridLayoutAnimationController.AnimationParameters(); 
     params.layoutAnimationParameters = animationParams; 

     animationParams.count = 9; 
     animationParams.columnsCount = 3; 
     animationParams.rowsCount = 3; 
     animationParams.index = position; 
     animationParams.column = position/animationParams.columnsCount; 
     animationParams.row = position % animationParams.columnsCount; 

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

चूंकि यह एक एपीआई है जो एपीआई 1 के बाद से कोई वास्तविक दस्तावेज़ीकरण या नमूने नहीं है, इसलिए मैं इसका उपयोग करने के खिलाफ अत्यधिक सुझाव दूंगा, क्योंकि इसकी कार्यक्षमता को दोहराने के कई तरीके हैं।

+0

आप कैसे समझाने कर सकते हैं? मैंने इसे डिफ़ॉल्ट ItemAnimator के साथ-साथ विभिन्न [ItemAnimators] के उदाहरण डाउनलोड करने का प्रयास किया है (https://github.com/gabrielemariotti/RecyclerViewItemAnimators/tree/master/library/src/main/java/it/gmariotti/recyclerview/itemanimator) लेकिन मैं उस एनीमेशन को नहीं देख सकता जिसे मैं ढूंढ रहा हूं। – Musenkishi

+0

क्या आपने सुनिश्चित किया है कि 'NotifyDataSetChanged() 'का उपयोग न करें, और इसके बजाय' NotifyItemRangeAdded()' और 'NotifyItemRangeRemoved()' का उपयोग करें? यह हमेशा पहली लोड एनीमेशन ट्रिगर करना चाहिए। –

+0

हां, मैंने 'notifyItemRangeAdded()' का उपयोग करने का प्रयास किया है, लेकिन जैसा कि मैंने उपरोक्त वर्णित किया है, यह मुझे वांछित व्यवहार नहीं दे रहा है। 'सूचित करें ItemRangeAdded() 'पहली पंक्ति पर एनीमेशन चलाएगा और ** ** ** दूसरी पंक्ति पर शुरू नहीं होगा जब तक कि पहले की सभी कोशिकाओं ने अपनी एनीमेशन शुरू नहीं की हो। एनीमेशन जो मैं ' 'से प्राप्त कर सकता हूं, पंक्तियों में तिरछे हो सकता है, जिसका अर्थ है कि यह एक ही समय में कई पंक्तियों को एनिमेट करना शुरू कर सकता है। अनिवार्य रूप से ग्रिड में सभी कोशिकाओं को ऊपर से बाएं से दाएं नीचे की लहर में दिखाई देते हैं। – Musenkishi

0
https://gist.github.com/Musenkishi/8df1ab549857756098ba

कोई सुराग पर

का हवाला देते हुए @Musenkishi। क्या आप एडाप्टर सेट करने के बाद recyclerView.scheduleLayoutAnimation(); पर कॉल कर रहे हैं?और क्या आपने लेआउट में <GridRecyclerView> पर android:layoutAnimation="@anim/your_layout_animation" सेट किया है?

इससे मेरा मुद्दा हल हो गया।

2

सरल समाधान

TransitionManager.beginDelayedTransition(moviesGridRecycler); 
gridLayoutManager.setSpanCount(gridColumns); 
adapter.notifyDataSetChanged(); 

लेकिन यह न भूलें बनाने के लिए अपने RecyclerAdapter setHasStableIds(true); और लागू getItemID()

@Override 
public long getItemId(int position) { 
    return yourItemSpecificLongID; 
} 
संबंधित मुद्दे