Make carousel with ViewFlipper or ViewPager
Asked Answered
I

3

9

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?

Inextinguishable answered 4/12, 2011 at 22:55 Comment(17)
I've never tried GalleryView myself, and though don't know exactly how it works, but would it be a solution to use one of the open sourced horizontal ListViews?Gloucester
@Inextinguishable have you tried it already? or you just want the code done?Prayer
@DiogoBento Yes, Do you have another suggestion?Inextinguishable
@Inextinguishable here is a ViewPager with infinite scroll: thehayro.blogspot.de/2012/12/… It is pretty easy to animate views entering / leaving.Mantle
@SherifelKhatib Already saw that, but it's little unintelligible for me!Inextinguishable
@Inextinguishable What do you mean "ViewFlipper is non-touchable"?Mantle
@SherifelKhatib I mean you can't change an item with pushing your finger to right or left, Anyway the first item is more important to me.Inextinguishable
@Inextinguishable Ok you can solve this by using this implementation on your ViewFlipper: https://mcmap.net/q/45579/-fling-gesture-detection-on-grid-layout However, it will not be as handsome as a ViewPager because the flipping will happen after the swipe. I would seriously advice you to use a viewpager. I will stick to this by posting a small help in an answerMantle
@SherifelKhatib Okay give me an example about this through ViewPager and then I give you +400 reputation :-).Inextinguishable
your last edit says you are almost done with ViewPager & only infinite scrolling is left..What do mean by infinite scrolling here? does it mean image scrolling in circular motion?Heterosporous
your Pageadaptor seems to be circular to me.. your getcount returns "Integer.MAX_VALUE" and inside instantiateItem you are doing "if (position >= bannerUri.length) position %= bannerUri.length;".. isn't it?Heterosporous
@Heterosporous You're right, But I got OOM that cause from my bitmaps and I wonder why?! while I'm using LazyLoading mechanism!Inextinguishable
did u have a look at setOffscreenPageLimit in ViewPager.. ? it will solve your OOM issue hopefully.. You need to set some optimised value to it...One question to understand problem better..how many images do you have in bannerArray and what is average image size and oom issue comes after how many page scroll?Heterosporous
@Heterosporous Interesting, I currently have this method in my code but when I remove it OOM has disappeared!Inextinguishable
oh i see... what was the value you were passing to it... as it defaults to 1, now as you have removed it will be 1 by native implementation..Heterosporous
let us continue this discussion in chatHeterosporous
@iSun: this carousel looks simple and useful.With a view to help other developers,can you plz share the code of this carousel?Schuster
H
2

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

Heterosporous answered 19/4, 2013 at 20:4 Comment(0)
S
1

Consider using a ViewPager with multiple pages:

http://commonsware.com/blog/2012/08/20/multiple-view-viewpager-options.html

Sperm answered 17/4, 2013 at 21:55 Comment(7)
Thanks, I already used that and it has several issues in dragging an item!Inextinguishable
Thanks but I'm looking for ViewFlipper.Inextinguishable
@Inextinguishable Why ViewFlipper? Is there any feauture that you like?Prayer
ViewFlipper is only meant to show one item at a time. It is the wrong component to use if you want to show multiple children. From the ViewFlipper documentation: Simple ViewAnimator that will animate between two or more views that have been added to it. Only one child is shown at a time. If requested, can automatically flip between each child at a regular interval.Drip
@DiogoBento yup, it has infinity scrolling.Inextinguishable
@Drip What's your suggestion instead of ViewFilpper?Inextinguishable
Not sure what infinity scrolling means. I would look into ViewPager as Flavio suggested. It uses an adapter pattern, which really would give you infinity scrolling.Drip
Z
1

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 .

Zincography answered 18/4, 2013 at 12:6 Comment(9)
I don't understand. Are you talking about using ViewPager? If so, in order to mimic infinite scrolling, you can set the number of pages to Integer.MAX_VALUE, and set the current page to the middle of it.Zincography
Yes I'm talking about ViewPager, I also tried Integer.MAX_VALUE but I've faced with OOM because I fetched my images from internet.Inextinguishable
OOM isn't related to ViewPager. I think you just store them all or you store huge bitmaps. Try downsampling and using cache mechanism. For more info , read this: developer.android.com/training/displaying-bitmaps/index.htmlZincography
I'm using LazyLoading mechanism so it's not related to my bitmaps.Inextinguishable
@Inextinguishable Can you please give some more information? Is LazyLoading a library you are using or you are talking about a general idea? In any case, most of the times, you get OOM because you store too many bitmaps or too large bitmaps. It has nothing to do with ViewPager. Maybe your loading doesn't dispose of old bitmaps?Zincography
Yes, you're right I checked the log cat, UIL load about 2,147,483,647 bitmaps at same time that's equivalent to Integer max value, I've edited my post and add my PagerAdapter, Could you check it please?Inextinguishable
Well there are some tips I can give you, but one thing I can say is that you load all of the pages (and their bitmaps) instead of doing it only when the user needs to show them. Try using fragments for the pages and load their content only when needed. There is a reason most of the samples of ViewPager use fragments. They have their own lifecycle . This could be perfect for your case.Zincography
I act according to your suggestion, OOM has gone but the other problem appeared, setCurrentItem() of ViewPager working but without smooth scrolling while i set the flag to true!Inextinguishable
@Inextinguishable Have you used the fragments (can't see the new code) methodology? What do you mean smooth scrolling? Which flag are you talking about? Please show your code.Zincography

© 2022 - 2024 — McMap. All rights reserved.