ViewPager inside CardView inside RecyclerView Android

前端 未结 1 1285
别跟我提以往
别跟我提以往 2021-02-06 16:27

I\'m trying to design something very similar to this design from the Material Design website.

So basically, I have a list of CardViews that each of them has mu

相关标签:
1条回答
  • 2021-02-06 16:33

    From what I understand you have an simular issue to mine. I have managed to resolve the issue by switching to PagerAdapter as it gives you more control over the pages created and displayed.

    This is the solution I came up to:

    The PagerAdapter class:

    import android.content.Context;
    import android.support.annotation.NonNull;
    import android.support.v4.view.PagerAdapter;
    import android.util.Log;
    import android.view.LayoutInflater;
    import android.view.View;
    import android.view.ViewGroup;
    import android.widget.ImageView;
    import com.bumptech.glide.Glide;
    import com.bumptech.glide.load.DecodeFormat;
    import com.peoplepost.android.R;
    import com.peoplepost.android.common.listener.ItemClickSupport;
    import com.peoplepost.android.network.merv.model.Product;
    import java.util.ArrayList;
    import java.util.List;
    
    /**
     * <p>
     * Custom pager adapter which will manually create the pages needed for showing an slide pages gallery.
     * </p>
     * Created by Ionut Negru on 13/06/16.
     */
    public class GalleryAdapter extends PagerAdapter {
    
        private static final String TAG = "GalleryAdapter";
    
        private final List<Item> mItems;
        private final LayoutInflater mLayoutInflater;
        /**
         * The click event listener which will propagate click events to the parent or any other listener set
         */
        private ItemClickSupport.SimpleOnItemClickListener mOnItemClickListener;
    
        /**
         * Constructor for gallery adapter which will create and screen slide of images.
         *
         * @param context
         *         The context which will be used to inflate the layout for each page.
         * @param mediaGallery
         *         The list of items which need to be displayed as screen slide.
         */
        public GalleryAdapter(@NonNull Context context,
                                                @NonNull ArrayList<Item> mediaGallery) {
            super();
    
            // Inflater which will be used for creating all the necessary pages
            mLayoutInflater = (LayoutInflater) context.getSystemService(Context.LAYOUT_INFLATER_SERVICE);
    
            // The items which will be displayed.
            mItems = mediaGallery;
        }
    
        @Override
        public int getCount() {
            // Just to be safe, check also if we have an valid list of items - never return invalid size.
            return null == mItems ? 0 : mItems.size();
        }
    
        @Override
        public boolean isViewFromObject(View view, Object object) {
            // The object returned by instantiateItem() is a key/identifier. This method checks whether
            // the View passed to it (representing the page) is associated with that key or not.
            // It is required by a PagerAdapter to function properly.
            return view == object;
        }
    
        @Override
        public Object instantiateItem(ViewGroup container, final int position) {
            // This method should create the page for the given position passed to it as an argument.
            // In our case, we inflate() our layout resource to create the hierarchy of view objects and then
            // set resource for the ImageView in it.
            // Finally, the inflated view is added to the container (which should be the ViewPager) and return it as well.
    
            // inflate our layout resource
            View itemView = mLayoutInflater.inflate(R.layout.fragment_gallery_item, container, false);
    
            // Display the resource on the view
            displayGalleryItem((ImageView) itemView.findViewById(R.id.gallery_item), mItems.get(position));
    
            // Add our inflated view to the container
            container.addView(itemView);
    
            // Detect the click events and pass them to any listeners
            itemView.setOnClickListener(new View.OnClickListener() {
                @Override
                public void onClick(View v) {
                    if (null != mOnItemClickListener) {
                        mOnItemClickListener.onItemClicked(position);
                    }
                }
            });
    
            // Return our view
            return itemView;
        }
    
        @Override
        public void destroyItem(ViewGroup container, int position, Object object) {
            // Removes the page from the container for the given position. We simply removed object using removeView()
            // but could’ve also used removeViewAt() by passing it the position.
            try {
                // Remove the view from the container
                container.removeView((View) object);
    
                // Try to clear resources used for displaying this view
                Glide.clear(((View) object).findViewById(R.id.gallery_item));
                // Remove any resources used by this view
                unbindDrawables((View) object);
                // Invalidate the object
                object = null;
            } catch (Exception e) {
                Log.w(TAG, "destroyItem: failed to destroy item and clear it's used resources", e);
            }
        }
    
        /**
         * Recursively unbind any resources from the provided view. This method will clear the resources of all the
         * children of the view before invalidating the provided view itself.
         *
         * @param view
         *         The view for which to unbind resource.
         */
        protected void unbindDrawables(View view) {
            if (view.getBackground() != null) {
                view.getBackground().setCallback(null);
            }
            if (view instanceof ViewGroup) {
                for (int i = 0; i < ((ViewGroup) view).getChildCount(); i++) {
                    unbindDrawables(((ViewGroup) view).getChildAt(i));
                }
                ((ViewGroup) view).removeAllViews();
            }
        }
    
        /**
         * Set an listener which will notify of any click events that are detected on the pages of the view pager.
         *
         * @param onItemClickListener
         *         The listener. If {@code null} it will disable any events from being sent.
         */
        public void setOnItemClickListener(ItemClickSupport.SimpleOnItemClickListener onItemClickListener) {
            mOnItemClickListener = onItemClickListener;
        }
    
        /**
         * Display the gallery image into the image view provided.
         *
         * @param galleryView
         *         The view which will display the image.
         * @param galleryItem
         *         The item from which to get the image.
         */
        private void displayGalleryItem(ImageView galleryView, Item galleryItem) {
            if (null != galleryItem) {
                Glide.with(galleryView.getContext()) // Bind it with the context of the actual view used
                     .load(galleryItem.getImageUrl()) // Load the image
                     .asBitmap() // All our images are static, we want to display them as bitmaps
                     .format(DecodeFormat.PREFER_RGB_565) // the decode format - this will not use alpha at all
                     .centerCrop() // scale type
                     .placeholder(R.drawable.default_product_400_land) // temporary holder displayed while the image loads
                     .animate(R.anim.fade_in) // need to manually set the animation as bitmap cannot use cross fade
                     .thumbnail(0.2f) // make use of the thumbnail which can display a down-sized version of the image
                     .into(galleryView); // Voilla - the target view
            }
        }
    }
    

    And the updated onBindViewHolder() of the parent RecyclerView:

    @Override
    public void onBindViewHolder(MyHolder holder, int position) {
        super.onBindViewHolder(holder, position);
    
        Item listItem = get(position);
    
        ...
    
        GalleryAdapter adapter =
                        new GalleryAdapter(getActivity(), product.mediaGallery);
        // Set the custom click listener on the adapter directly
        adapter.setOnItemClickListener(new ItemClickSupport.SimpleOnItemClickListener() {
            @Override
            public void onItemClicked(int position) {
                // inner view pager page was clicked
            }
        });
        // Set the adapter on the view pager
        holder.imageGallery.setAdapter(adapter);
    
        ...
    }
    

    I noticed a little increase in memory usage, but the UI is very fluid. I guess some further optimizations can be made on how many pages are kept and how they are destroyed and restored.

    Your requirements are a little different, but the logic behind it should be the same. I hope this solves your issue.

    0 讨论(0)
提交回复
热议问题