Im trying to inflate multiple ViewPagers
into a ScrollView
where each ViewPager
is using a FragmentStatePagerAdapter.
The ViewPager
consist of fragments with three ImageViews
for each page.
Im using UniversalImageLoader for the async loading of the images but I cant get a lazy load to work.
The problem is when my app is inflating lets say 10 ViewPagers
with 3 ImageViews
for each TripplePosterFragment1
, and another 10 ViewPagers
with 3 ImageViews
for TripplePosterFragment2
since the mPager.setOffscreenPageLimit(1)
kicks in.
Its a total of 60 async requests firing during my progressLayout
is visible.
My MainFragment
with following method:
private void renderSubCarousels(ArrayList<Carousel> carousels) {
LayoutInflater mInflater = (LayoutInflater)getActivity().getSystemService(Context.LAYOUT_INFLATER_SERVICE);
int i = 1;
LinearLayout subCarouselLayout = (LinearLayout) mScrollView.findViewById(R.id.index_subcategory_carousel_container);
for (final Carousel carousel : carousels) {
RelativeLayout carouselWrapper = (RelativeLayout) mInflater.inflate(R.layout.main_pager_layout, null);
LinearLayout mContainer = (LinearLayout) carouselWrapper.findViewById(R.id.main_pager_container);
mContainer.setId(Constants.BASEID_LINEARLAYOUT + i);
ViewPager mPager = (ViewPager) mContainer.findViewById(R.id.main_pager);
mPager.setId(Constants.BASEID_VIEWPAGER + i);
mPager.setAdapter(new PagerPosterAdapter(getFragmentManager(),Constants.TRIPLE_POSTERS, carousel));
subCarouselLayout.addView(carouselWrapper);
i++;
}
progressLayout.setVisibility(View.GONE);
}
My FragmentStatePagerAdapter
:
public class PagerPosterAdapter extends FragmentStatePagerAdapter {
private int mPageSize;
private Carousel mCarousel;
public PagerPosterAdapter(FragmentManager fm, int pageSize, Carousel carousel) {
super(fm);
this.mPageSize = pageSize;
this.mCarousel = carousel;
}
@Override
public int getCount() {
int maxPageIndex = (int) Math.ceil((float) mCarousel.getAssets().size() / mPageSize);
return maxPageIndex;
}
@Override
public Fragment getItem(int position) {
ArrayList<Asset> assets = mCarousel.getAssets();
int from = position*mPageSize;
int to = (position+1)*(mPageSize);
if(to > assets.size()-1)
to = assets.size();
return (TripplePosterFragment.newInstance(assets.subList(from, to)));
}
}
The TripplePosterFragment
where the ImageView rendering happens:
private void initViews() {
ImageView mFirstImageView = (ImageView) mLinearLayout.findViewById(R.id.first_pager_poster);
ImageView mSecondImageView = (ImageView)mLinearLayout.findViewById(R.id.second_pager_poster);
ImageView mThirdImageView = (ImageView)mLinearLayout.findViewById(R.id.third_pager_poster);
for(int i = 0;i < assets.size(); i++){
ImageView image = null;
switch(i){
case 0:
image = (ImageView) mLinearLayout.findViewById(R.id.first_pager_poster);
break;
case 1:
image = (ImageView) mLinearLayout.findViewById(R.id.second_pager_poster);
break;
case 2:
image = (ImageView) mLinearLayout.findViewById(R.id.third_pager_poster);
break;
default:
continue;
}
//The ScrollView in MainFragment
CustomScrollView mParentScrollView = (CustomScrollView)getActivity().findViewById(R.id.index_scrollviewparent);
Rect scrollBounds = new Rect();
mParentScrollView.getHitRect(scrollBounds);
if (image.getLocalVisibleRect(scrollBounds)) {
// Any portion of the imageView, even a single pixel, is within the visible window
ImageLoader.getInstance().displayImage(assets.get(i).getPoster(), image);
System.out.println("Im within");
else {
// NONE of the imageView is within the visible window
System.out.println("Im NOT within");
}
}
}
I need to check if the images are visible and load them when they are. But System.out.println("Im NOT within");
is spammed in the Log
. Im sure there is a way of doing it similar to this, but I need some help.
I've tried a quick approach of doing much of the meat inside a ListView but its not optimal, at least after some reading, ViewPager inside ListView
UPDATE
Same core issue as before, but using a new approach HorizontalListViews instad of Pagers.
ListViews
seems like the way to go. By using ArrayAdapter
to populate a regular vertical ListView
with multiple HListViews
lazy loads the images vertically for each new row, and horizontally for each image inside, as intended.
Problem: Horizontal positions are lost. The horizontalAdapter
is inherited from a recycled view onto next list item. This positions the new list item to where the recycled list item was.
public View getView(int position, View convertView, ViewGroup parent) {
final ViewHolder holder;
View view = convertView;
if (view == null) {
holder = new ViewHolder();
view = mInflater.inflate(R.layout.carousel_frame_layout, null);
holder.carouselList = (HListView) view.findViewById(R.id.hListView);
view.setTag(holder);
}
else {
holder = (ViewHolder) view.getTag();
}
Carousel mCarousel = mData.get(position);
// Problem: Re-uses adapters from convertview
if (holder.carouselList.getAdapter() == null) {
SubCategoryCarouselAdapter horizontalAdapter = new SubCategoryCarouselAdapter(mContext, mCarousel.getAssets());
holder.carouselList.setAdapter(horizontalAdapter);
} else {
((SubCategoryCarouselAdapter) holder.carouselList.getAdapter()).update(mCarousel.getAssets());
}
return view;
}
The solution could be to save the inner horizontalAdapter
to a designated list item position, but I dont know how to do this when the HListView
itself is recycled.
UPDATE 3
Found a working solution for HListViews
. But I have still to test if this is working for ViewPagers
.
Its lazy loading images both horizontally and vertically when using addHeaderView
on parent ListView
for each inner HListView
. I´ve used HorizontalVariableListView together with UniversalImageLoader for the carousels.
LayoutInflater mInflater = (LayoutInflater) getActivity().getSystemService
(Context.LAYOUT_INFLATER_SERVICE);
for (final Carousel carousel : carousels) {
View carouselWrapper = mInflater.inflate(R.layout.carousel_sub_category_layout, null);
listView.addHeaderView(carouselWrapper);
listView.setAdapter(null);
HListView horizontalList = (HListView) carouselWrapper.findViewById(R.id.hListView);
SubCategoryCarouselAdapter mAdapter = new SubCategoryCarouselAdapter(getActivity(), carousel.getAssets());
horizontalList.setAdapter(mAdapter);
}
Why not use a ListView instead of ScrollView? It has a function of recycling views, so loading will start only for those pagers which are visible on screen right now. Otherwise you should subclass your ScrollView in order to check if Pager is visible right now
Could you set a breakpoint at
if (image.getLocalVisibleRect(scrollBounds)) {
and see what properties (width/height/position) image and scrollBounds have?
Also, when is
private void initViews() {
called?
If you love us? You can donate to us via Paypal or buy me a coffee so we can maintain and grow! Thank you!
Donate Us With