在ScrollView中实现ViewPager的懒加载

6
我正在尝试将多个 ViewPager 嵌入到一个 ScrollView 中,每个 ViewPager 都使用 FragmentStatePagerAdapter。每个 ViewPager 由具有三个 ImageViews 的片段组成。
我使用 UniversalImageLoader 异步加载图像,但我无法实现懒加载。
问题在于,当我的应用程序膨胀时,例如为每个 TripplePosterFragment1 膨胀了 10 个 ViewPagers,每个都有 3 个 ImageViews,并且再为每个 TripplePosterFragment2 膨胀了另外 10 个 ViewPagers 时,由于 mPager.setOffscreenPageLimit(1) 被触发,会出现问题。
这总共会有 60 个异步请求,在我的 progressLayout 可见时触发。
我的 MainFragment 具有以下方法:
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);
}

我的 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)));
    }
}

ImageView的渲染发生在TripplePosterFragment中:

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");
        }
    }
}

我需要检查图片是否可见,当它们可见时加载它们。但是在日志中会不断输出“Im NOT within”。我确信有一种类似这样的方法可以做到,但我需要一些帮助。
我试过在ListView中完成大部分工作,但至少在阅读了一些内容之后,这并不是最优解。ViewPager inside ListView 更新 与之前相同的核心问题,但使用新的水平ListView替代Pagers。
ListView看起来是正确的选择。通过使用ArrayAdapter将多个HListViews填充到常规垂直ListView中,为每个新行垂直懒加载图像,并为内部的每个图像水平懒加载,正如预期的那样。
问题:水平位置丢失。horizontalAdapter从回收视图继承到下一个列表项。这将新的列表项定位到回收列表项的位置。
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;
}

解决方案可能是将内部的horizontalAdapter保存到指定的列表项位置,但当HListView本身被回收时,我不知道如何做到这一点。
更新3
找到了一个适用于HListViews的解决方案。但我仍然需要测试是否适用于ViewPagers
它在父ListView上使用addHeaderView为每个内部HListView懒加载水平和垂直图片。我使用了HorizontalVariableListViewUniversalImageLoader来制作旋转木马。
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);
}
2个回答

3

为什么不使用ListView而使用ScrollView?因为它具有视图回收功能,所以只会加载当前屏幕可见的页面。否则,您需要对ScrollView进行子类化,以检查Pager是否当前可见。


是的,看起来这是正确的方法。我无法让视图和适配器的回收工作正常。我已经放弃了使用分页器,转而使用HorizontalListViews。但是在ScrollView中加载所有图像时会出现相同的行为。正如你所说,HorizontalListViews是可循环利用的,但与每个可循环利用视图绑定的适配器也是如此。我的答案已更新! - Rob
1
我可以提供以下两种解决方案: 1)将您的适配器保存在List中,并通过其位置获取所需的适配器(实际上,我认为这不是一个好主意,因为从内存角度来看它并不有效) 2)向您的Carousel(我假设它具有要显示的数据列表)类添加指针,该指针将指向活动位置,然后修改SubCategoryCarouselAdapter构造函数以获取此指针并设置相应的位置(我认为这种方式比第一种更好,因为对于指针,它只能是表示页面编号的int值) - Chaosit
1
如果您的HListView被分页为ViewPager,则至少应该起作用。 - Chaosit
  1. 如果使用分页器,最好的解决方案可能是第二个。但我不确定是否可以重用适配器来回收视图,然后使用保存的指针更新位置。我猜这就是你建议的方式?
我已经采用了一种不同的方法更新了我的问题。这实际上会在水平和垂直方向上都延迟加载图像。持有此图像的片段也加载得很快。我不知道这是否对整体产生不良影响,但我找不到更好的解决方案。
- Rob

2

你能在这个位置设置一个断点吗?

if (image.getLocalVisibleRect(scrollBounds)) {

看一下图像和滚动边界具有哪些属性(宽度/高度/位置)?

此外,何时会出现

private void initViews() {

called?


网页内容由stack overflow 提供, 点击上面的
可以查看英文原文,
原文链接