`

缓存式的ViewPager&和其他手势控件冲突的解决办法

阅读更多
一般来说ViewPager如果有很多页的话,会加载它的上一页,当前页和下一页,当从n页以后再想回到第一页,就会再加载一次,这样第一页很多操作后的数据就会被重置,原因是在PagerAdapter的destroyItem经常会移除View,类似下面这样的代码:

@Override
        public void destroyItem(View container, int position, Object object)
        {
            // ((ViewPager) container).removeView(viewMap.get(position));//

        }


现在我不想移除它,需要让View保持原来的状态
那么就要采用一个Map用于保存View
HashMap<Integer, View> viewMap = new HashMap<Integer, View>();

然后在PagerAdapter的instantiateItem方法中如下用法:
@Override
        public Object instantiateItem(View container, int position)
        {
            View view = null;
            if (viewMap.containsKey(position))
            {
                view = viewMap.get(position);
            }
            else
            {
                view = getLayoutInflater().inflate(R.layout.item_for_gallery, null);
                viewMap.put(position, view);

                ((ViewPager) container).addView(view, 0);
}
}

这样就保证不会View不会被重置了。

伪代码如下:
package com.mobovip.bgr;

import java.util.ArrayList;
import java.util.HashMap;

import android.content.Context;
import android.os.Bundle;
import android.os.Parcelable;
import android.view.View;
import android.view.ViewGroup;

import com.mobovip.model.Prize;
import com.mobovip.util.Utils;

public class PrizeActivity extends BaseActivity
{

    private Context context;

    private HashMap<Integer, View> viewMap = new HashMap<Integer, View>();

    private com.mobovip.view.MyViewPager viewPager;

    private MyAdapter adapter;

    private ArrayList<Prize> prizes;

    @Override
    protected void onCreate(Bundle savedInstanceState)
    {
        super.onCreate(savedInstanceState);
        setContentView(R.layout.activity_prize);
        context = this;
        initViews();
    }

    @Override
    public void onResume()
    {
        super.onResume();
        initValues();
    }

    @Override
    protected void onDestroy()
    {
        // TODO Auto-generated method stub
        super.onDestroy();
    }

    @Override
    protected void initViews()
    {
        // TODO Auto-generated method stub
        viewPager = (com.mobovip.view.MyViewPager) findViewById(R.id.viewPager);
        // viewPager.setOnPageChangeListener(new MyOnPageChangeListener());
    }

    @Override
    protected void initValues()
    {
        // TODO Auto-generated method stub

    }

    @Override
    protected void updateViews(Object obj)
    {
        // TODO Auto-generated method stub
        prizes = (ArrayList<Prize>) obj;
        if (prizes == null)
        {
            return;
        }

        if (adapter == null)
        {
            adapter = new MyAdapter();
            viewPager.setAdapter(adapter);
            viewPager.setCurrentItem(0);
        }
        else
        {
            adapter.notifyDataSetChanged();
        }

    }

    class MyAdapter extends PagerAdapter
    {

        @Override
        public void destroyItem(View container, int position, Object object)
        {
            // 无需removeView
            // ((ViewPager) container).removeView(viewMap.get(position));//
            // View view = (View)object;

        }

        @Override
        public void finishUpdate(View container)
        {
        }

        @Override
        public int getCount()
        {
            return prizes.size();
        }

        /**
         * 跳转到每个页面都要执行的方法
         */
        @Override
        public void setPrimaryItem(View container, int position, Object object)
        {
        }

        @Override
        public Object instantiateItem(View container, int position)
        {
            View view = null;
            if (viewMap.containsKey(position))
            {
                view = viewMap.get(position);
            }
            else
            {
                view = getLayoutInflater().inflate(R.layout.item_for_gallery, null);
                viewMap.put(position, view);
                final Prize prize = prizes.get(position);
                String format = "MM-dd-yyyy HH:mm:ss";
                int days = Utils.days(prize.getCreateTime(), getCurTime(format), format);
                prize.setExpires(prize.getExpires() - days);

                ((ViewPager) container).addView(view, 0);
                com.mobovip.view.WinView winView = (com.mobovip.view.WinView) view.findViewById(R.id.winView);
                winView.setPrize(prize);
                //处理其他逻辑
                ......
            }
            return view;
        }

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

        @Override
        public void restoreState(Parcelable arg0, ClassLoader arg1)
        {
        }

        @Override
        public Parcelable saveState()
        {
            return null;
        }

        @Override
        public void startUpdate(View container)
        {
        }

        @Override
        public void finishUpdate(ViewGroup container)
        {
            // TODO Auto-generated method stub
            super.finishUpdate(container);
        }

    }

}



上面有一个自定义控件WinView,是一个刮刮卡效果的类,上面有手势刮奖的效果,
现在问题是,由于ViewPager和WinView都具有手势操作的能力,所以这两个控件放在一起回发生冲突,为了防止这种冲突就需要重写一下ViewPager
import android.content.Context;
import android.util.AttributeSet;
import android.view.View;

public class MyViewPager extends ViewPager
{
    public MyViewPager(Context context)
    {
        super(context);
        // TODO Auto-generated constructor stub
    }

    public MyViewPager(Context context, AttributeSet attrs)
    {
        super(context, attrs);
        // TODO Auto-generated constructor stub
    }

    @Override
    protected boolean canScroll(View v, boolean checkV, int dx, int x, int y)
    {
        if (v != this && v instanceof WinView)
        {// 解决冲突
            return true;
        }
        return super.canScroll(v, checkV, dx, x, y);
    }

}


重写canScroll方法,将WinView排除在外即可。


如果不重写ViewPager,那么需要在WinView的
public boolean onTouchEvent(MotionEvent event)中写入如下语句,该方法专门用于剥夺父级控件的控制权

// 阻止父控件获得触摸操作,拦截触摸事件,防止与ViewPager等控件发生手势冲突
getParent().requestDisallowInterceptTouchEvent(true);


这样可以不用重写ViewPager了,推荐这样写(虽然我没试过!P)
分享到:
评论
2 楼 yangsiyu11 2016-06-24  
最后一句话最关键了 找了一下午
1 楼 lxh2002 2015-08-08  
感谢楼主分享,正好解决了我的问题。不过发现,
重写ViewPager的canScroll()完全正常,但在自定义View中requestDisallowInterceptTouchEvent()则无效,还没仔细研究是什么原因。

相关推荐

    listview与viewpager组合2

    6. 最后,测试和调试:确保在各种设备和屏幕尺寸上都能正常工作,同时注意滑动冲突的解决,避免ListView和ViewPager之间的滑动手势相互干扰。 通过这样的组合,我们可以创建出更富有层次感和交互性的界面,提升用户...

    Android点击查看大图,支持手势Viewpager

    这个功能结合了ImageView、ViewPager和手势识别技术,提供了用户友好的交互体验。下面我们将详细探讨这一主题的相关知识点。 1. **ImageView**: ImageView是Android系统提供的用于显示图像的基本组件。它可以加载...

    安卓滑动控件集

    2. **手势冲突**:处理好ViewPager与其他手势交互控件间的事件冲突。 3. **自定义适配器**:根据需求自定义PagerAdapter,实现动态加载数据。 4. **适配不同屏幕尺寸**:确保滑动控件在各种设备上表现良好。 5. **...

    仿淘宝ViewPager左滑查看详情

    然后,通过计算手指移动的距离和方向,判断是应该由父布局处理滑动(切换整个页面)还是由子控件(如ViewPager)处理(在当前页面内滑动浏览更多内容)。 在处理事件冲突时,可能需要用到`...

    PictureView:自定义ImageView,支持缩放,拖动,双击放大缩小,解决与ViewPager的事件冲突

    `PictureView`是一个自定义的ImageView,特别设计来支持图片的缩放、拖动以及双击放大缩小功能,同时解决了与ViewPager组件之间可能存在的事件冲突问题。这个自定义控件使得在展示图像时,用户可以更自由地交互,...

    高仿微信图片放大拖动浏览,自定义ImageView

    需要注意的是,ViewPager的默认滑动冲突处理可能会影响自定义控件的手势操作。我们需要在XlhZoomImageView中重写onInterceptTouchEvent()方法,确保手势优先由自定义控件处理。同时,适配ViewPager的...

    Android基础控件——Banner轮播图的无限循环轮播功能、手动滑动功能(新)

    本文将深入探讨如何实现一个带有无限循环轮播和手动滑动功能的Banner控件。 首先,我们需要创建一个自定义的View来承载轮播图。这个自定义View通常会继承自`LinearLayout`或`FrameLayout`,以便容纳多个ImageView或...

    横屏侧滑的girdview

    在Android开发中,"横屏侧滑的girdview"是一种常见的用户界面设计,它结合了ViewPager和GridView组件,提供了一种优雅的方式展示大量数据,同时允许用户通过侧滑来切换不同的视图或页面。这种设计通常用于图片浏览、...

    android Banner图片循环滑动轮播

    - 考虑用户的交互,要处理ViewPager的手势滑动事件,防止自动滚动与手动滑动冲突。可以监听ViewPager的`addOnPageChangeListener()`,在监听器中暂停或恢复自动滚动。 9. **优化与性能** - 由于ViewPager会预加载...

    应聘Android工程师_2年开发经验.doc

    1. 在新闻模块的开发中,解决了ViewPager和SlidingMenu的事件冲突,通过ListView的分批加载优化用户体验,并优化了UI结构。 2. 在购彩模块的开发中,搭建了应用框架,实现了多级联动,使用OOP优化了XML协议处理,...

    android图片轮播

    在Android应用开发中,图片轮播是一种常见的交互方式,用于展示多...以上就是利用Android的`ViewPager`控件实现图片轮播的基本步骤和注意事项。通过这种方式,开发者可以创建出功能丰富、用户体验良好的图片轮播效果。

    Android SwipeView类似桌面的滑动界面.rar

    - 使用`ViewPager`的缓存机制:只加载当前显示的页面和相邻的页面,以减少内存消耗。 - 适当的视图复用:如果子视图内容复杂,可以考虑复用机制,避免重复创建和销毁视图。 - 利用`RecyclerView`:对于大量数据...

    Android相册-可滑动放大浏览

    - 在处理手势时,要注意防止误触,例如避免在滑动和缩放之间产生冲突。 以上就是实现“Android相册-可滑动放大浏览”的核心知识点。在实际开发中,你可能还需要考虑更多细节,比如图片的加载策略、手势识别的精度...

    Android轮播图的实现

    实现这个功能,我们可以使用ViewPager,它是Android SDK提供的一种可以左右滑动切换页面的控件,非常适合用来构建轮播效果。 1. **使用ViewPager** - 创建一个继承自PagerAdapter的自定义Adapter,例如`...

    ListView上拉加载下拉刷新升级版:滑动tabHost结合listView数据刷新

    在Android开发中,ListView是常用的数据展示控件,它能够高效地处理大量数据并提供滚动效果。然而,随着用户需求的提升,简单的ListView已经不能满足所有场景,特别是当需要实现上拉加载更多和下拉刷新功能时。...

Global site tag (gtag.js) - Google Analytics