Make carousel with ViewFlipper or ViewPager

2020-05-20 02:13发布

Since GalleryView deprecated we should immigrate to some alternative widgets, In my case ViewFlipper is the best but I have faced with several issues, as you can see in the following screenshot I have designed a carousel ImageGallery with GalleryView:

enter image description here

With ViewFlipper everything works as I expected, But I'm not able to implement two things:

1- ViewFlipper always shows one item; however I need to display three items (or even more) at once.

2- ViewFlipper is non-touchable widget and it's not what I want!


As FlávioFaria mentioned about ViewPager in the following post, It's a great case too but I can't pass my scale up animation to it!

I've done everything with ViewPager, now it's working great but I have missed one functionality and that is infinity scrolling!

Added my PagerAdapter class

public class CarouselAdapter extends PagerAdapter  
{  
    private Context mContext;
    private ImageLoader imageLoader;
    private String[] bannerUri;

    public CarouselAdapter (Context c, String[] bannerArray) 
    { 
        this.mContext = c; 
        this.bannerUri = bannerArray;
        // Setup image loader
        this.imageLoader = ImageLoader.getInstance();
        ImageLoaderConfiguration config = new ImageLoaderConfiguration.Builder(c)
            .threadPoolSize(2) 
            .memoryCache(new WeakMemoryCache())
            .discCacheFileNameGenerator(new Md5FileNameGenerator())
            .build();
        this.imageLoader.init(config);
    } 

    @Override
    public Object instantiateItem(ViewGroup container, int position)
    {
        if (position >= bannerUri.length) 
            position %= bannerUri.length;

        ImageView i = new ImageView(mContext);
        displayImage(i, bannerUri[position]);
        i.setScaleType(ScaleType.FIT_XY); 
        container.addView(i);
        return i;
    }

    @Override
    public void destroyItem(ViewGroup container, int position, Object object) 
    {
        container.removeView((View)object);
    }

    @Override
    public int getCount() 
    {
        return Integer.MAX_VALUE;
    }

    @Override
    public boolean isViewFromObject(View view, Object object)
    {
         return (view == object);
    }

    private void displayImage(final ImageView mImage, String ImageUri)
    {
        DisplayImageOptions defaultOptions = new DisplayImageOptions.Builder()
            .showStubImage(R.drawable.border)
            .showImageForEmptyUri(R.drawable.border)
            .imageScaleType(ImageScaleType.EXACTLY)
            .bitmapConfig(Bitmap.Config.RGB_565)
            .resetViewBeforeLoading()
            .cacheOnDisc() 
            .displayer(new FadeInBitmapDisplayer(740))
            .build();

        imageLoader.loadImage(ImageUri, defaultOptions, new SimpleImageLoadingListener() 
        {
            public void onLoadingComplete(String imageUri, View view, Bitmap loadedImage)
            {
                mImage.setImageDrawable(new BitmapDrawable(mContext.getResources()
                        , getDesiredBitmap(loadedImage, 12)));
            }
        });
    }

    private Bitmap getDesiredBitmap(Bitmap originalImage, int roundValue)
    {
        // Create required bitmaps
        Bitmap shadowBitmap = BitmapFactory.decodeResource(mContext.getResources()
                , R.drawable.samsungapps_thumb_shadow);
        Bitmap outputBitmap = Bitmap.createBitmap(originalImage.getWidth()
                , originalImage.getHeight() + 80, Bitmap.Config.ARGB_8888);
        // Create canvas and pass bitmap to it 
        Canvas mCanvas = new Canvas(outputBitmap);
        // And finally draw the shaodw
        mCanvas.drawBitmap(Bitmap.createScaledBitmap(shadowBitmap, originalImage.getWidth()
                , (int)(shadowBitmap.getHeight() / 2.3), false), 0, originalImage.getHeight(), null);

        mCanvas.drawBitmap(originalImage, 0, 0, null);

        return outputBitmap;
    }
}

Any idea about how to accomplish these two things?

3条回答
欢心
2楼-- · 2020-05-20 02:53
甜甜的少女心
3楼-- · 2020-05-20 03:08

Ok, here's one thing you can do:

  1. Use a horizontal list view solution (example here)

  2. Make sure each item takes about 1/3 of the width of the screen. Maybe a bit more.

  3. For the stickiness of the center item, handle touch events so that it will smooth scroll to the middle item, for example as shown on samsung's sample "circle launcher" .

  4. For more fancy effects, make the size/location properties of the views change similar to the sample i've written about on #3 .

查看更多
来,给爷笑一个
4楼-- · 2020-05-20 03:09

after going through your code i found that CarouselAdapter is behaving in circular manner(infinite scrolling) part of code is which causes this is:-

@Override
    public int getCount() 
    {
        return Integer.MAX_VALUE;
    }

and

@Override
    public Object instantiateItem(ViewGroup container, int position)
    {
        if (position >= bannerUri.length) 
            position %= bannerUri.length;
       .
       . 
       .
    }

However you are doing

        ImageView i = new ImageView(mContext);
        displayImage(i, bannerUri[position]);
        i.setScaleType(ScaleType.FIT_XY); 
        container.addView(i);
        return i;

in instantiateItem, so for each page in your ViewPager, you are allocating memory for ImageView and ViewPager is getting run out of memory because of this. ViewPager has method public void setOffscreenPageLimit (int limit) which will limit the memory allocated by destroying idle pages in view hierarchy.. See below from the android documentation

Set the number of pages that should be retained to either side of the current page in the view hierarchy in an idle state. Pages beyond this limit will be recreated from the adapter when needed.

This is offered as an optimization. If you know in advance the number of pages you will need to support or have lazy-loading mechanisms in place on your pages, tweaking this setting can have benefits in perceived smoothness of paging animations and interaction. If you have a small number of pages (3-4) that you can keep active all at once, less time will be spent in layout for newly created view subtrees as the user pages back and forth.

You should keep this limit low, especially if your pages have complex layouts. This setting defaults to 1.

As mentioned above, If do not specify any value to it , it will use default value 1 and ViewPager will destroy idle pages from view hierarchy. So you need to pass optimised value to it, according to your memory requirements(number of images and average image size), that will solve your Out of memory issue..

查看更多
登录 后发表回答