热门标签 | HotTags
当前位置:  开发笔记 > Android > 正文

Android使用ViewPager实现无限滑动效果

相信在大家开发Android的时候,我们常常用ViewPager来为自己的应用创建广告条幅,并且常常会遇到ViewPager无限滑动这样的需求。下面来一起看看吧。

前言

其实仔细想一下原理还是挺简单的。无非是当我们滑动到最后一页,再向后滑动时定位到第一页;当我们滑动到第一页,再向前滑动时定位到最后一页。

但是,相信很多朋友都遇到过这个问题:视图的过度效果不自然。

小编也是通过百度和谷歌查找了很多解决方案,实验了很多方法,总结了一个相对不错的方法,接下来给各位分享下滑动效果、实现细节以及一些踩过的坑。

1.无限滑动效果(左右无限滑动)

事先准备好2张滑动图片(有想试验的小伙伴,自备图片啊,小编就不提供了...)


运行效果图(左右无限循环):

为了显示更加直观,小编仅用了2张图片。

2.代码实现

(1) Activity的Xml布局文件(非常简单的布局)



 

(2)Activity

public class MainActivity extends AppCompatActivity {

 private ViewPager mViewPager;
 private ViewPagerAdapter mAdapter;
 private int[] images; // 图片资源数组

 @Override
 protected void onCreate(Bundle savedInstanceState) {
  super.onCreate(savedInstanceState);
  setContentView(R.layout.activity_main);
  initView(); // 初始化视图
  initData(); // 初始化数据
 }

 /**
  * 初始化视图
  */
 private void initView() {
  mViewPager = (ViewPager) findViewById(R.id.view_pager);
 }

 /**
  * 初始化数据
  */
 private void initData() {
  images = new int[]{R.mipmap.image1, R.mipmap.image2};
  mAdapter = new ViewPagerAdapter(this, images);
  mViewPager.setAdapter(mAdapter);

  // 将ViewPager定位到中间页(Short.MAX_VALUE/2附近的图片资源数组第1个元素对应的页面)
  // 目的:1.图片个数 >1 才轮播 2.定位到中间页,向左向右都可滑
  if(images.length > 1) {
   mViewPager.setCurrentItem(((Short.MAX_VALUE / 2) / images.length) * images.length, false);
  }
 }
}

(3)ViewPagerAdapter

/**
 * @ClassName: ViewPagerAdapter
 * @Description: ViewPager适配器
 * @Author Wangnan
 * @Date 2016/9/1
 */
public class ViewPagerAdapter extends PagerAdapter{

 private Context mContext;
 private int[] mImages; // 图片资源ID数组
 private List mImageViews; // ImageView集合

 public ViewPagerAdapter(Context context, int[] images){
  mCOntext= context;
  mImages = images;
  mImageViews = new ArrayList<>();
  initImageViews(mImages);
 }

 /**
  * 初始化ImageViews集合
  * @param imageIds
  */
 private void initImageViews(int[] imageIds) {

  // 根据图片资源数组填充ImageViews集合
  for(int i = 0 ; i  1 && mImageViews.size() <4){
   initImageViews(imageIds);
  }
 }

 @Override
 public int getCount() {
  return mImageViews.size() <=1 &#63; mImageViews.size() : Short.MAX_VALUE;
 }

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

 @Override
 public Object instantiateItem(ViewGroup container, int position) {
  ImageView mImageView = mImageViews.get(position % mImageViews.size());
  container.addView(mImageView);
  return mImageView;
 }

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

具体需要解释的地方,代码中都做了相应的注释,就不再多做解释了,但后面小编还会解释遇到的两个坑点。

3.细节踩坑

相信在看小编的实现方式之前,有人在网上也找到了很多相似的实现。小编接下来要讲的就是 —— 对“这些相似的实现”踩一下坑。

1. 出现异常:java.lang.IllegalStateException: The specified child already has a parent. You must call removeView() on the child's parent first.

原因:图片资源少于4个,对应生成的ImageView也少于4个。

众所周知,ViewPager一般会维护2~3个页,如果只有3个ImageView,很可能出现这种情况,在生成完3个Page页后并准备生成第4个页面时,本应该移除的最前面的页面还未被移除,系统就会报异常并且给你这样一个提示:You must call removeView() on the child's parent first(意思是让你先将最前面页的子View从最前面页移除掉,再将该子View添加到第4页中)。

解决办法:在只有1张图片时,不能滑动,暂不处理;如果有2~3张图片时,递归增加至大于等于4个ImageView为止(下方为小编解决该问题的代码)。

 /**
  * 初始化ImageViews集合
  * @param imageIds
  */
 private void initImageViews(int[] imageIds) {

  ......

  // ImageViews集合中的图片个数在[2,3]时会存在问题,递归再次填充一遍
  if(mImageViews.size() > 1 && mImageViews.size() <4){
   initImageViews(imageIds);
  }
 }

2. 滑动效果出现混乱(后面会附上混乱的效果图)

原因:ViewPager源码本身存在问题 - 数据范围越界问题。

小编的获取ViewPager页面数量的方法是这样写的:

 @Override
 public int getCount() {
  return mImageViews.size() <=1 &#63; mImageViews.size() : Short.MAX_VALUE;
 }

小于1时,页面没有滑动,不需要扩充页面数量;

大于1时,取Short取值范围的最大值32767(我们会有3W多页面,但不会同时存在,因为ViewPager最多维持3个页面)

小编这里用的是Short,但一开始从网上找的相似实现全是使用的Integer(Integer.MAX_VALUE = 2147483647, 也就是我们的ViewPager将会有大概21亿个页面),如果使用Integer,比较细心的朋友会发现滑动经常出现混乱。

页面反向回弹Bug


我们松手时,页面出现反向回弹(1~2页),这和我们期望的滑动效果不一致。

这是其中一种Bug,还有一些不太好说明的滑动Bug,小编就用“滑动混乱”这个名词进行解释了...

解决办法:缩小页面数量(小编使用的Short代替Integer减少了页面)。

具体的无Bug的临界值,有兴趣的小伙伴可以去实验,小编的测试结果如下:

800万以内:基本无滑动Bug;

1000万左右:开始出现当前页面定位不准确的Bug,但还未出现反向回弹Bug。

总结

以上就是关于Android使用ViewPager实现无限滑动效果的全部内容,希望这篇文章对大家开发的时候能有所帮助,如果有疑问可以留言交流。


推荐阅读
  • JobScheduler5.0源码分析
    0.JobScheduler执行代码mJobScheduler(JobScheduler)getSystemService(Context.JOB_SCHEDULER_SERVICE); ... [详细]
  • 获取年月日,之前的日期不能选择日历cCalendar.getInstance();获取系统的工具类【可以获取时间】DatePickerDialogdate ... [详细]
  • React Native 开发者如何高效替换 Android 图标与布局资源
    针对未接触过 Android 开发的 React Native 开发者,本文提供了详细的指南,帮助他们了解如何轻松替换 Android 应用中的图标和布局资源,包括对 APK 结构的基本认识及多种替换方法。 ... [详细]
  • Hibernate入门指南:单表数据库操作详解
    本文介绍了Hibernate作为全面的ORM框架的基础知识,并详细讲解了在MyEclipse环境中配置Hibernate以及进行基本的数据库单表操作的方法,包括增删改查等常见操作。 ... [详细]
  • 1.选择一个翻译页面,我选择的是有道词典(http:dict.youdao.com)2.随便输入一个英语单词进行翻译,然后查看源文件,找到 ... [详细]
  • 深入理解SAP Fiori及其核心概念
    本文详细介绍了SAP Fiori的基本概念、发展历程、核心特性、应用类型、运行环境以及开发工具等,旨在帮助读者全面了解SAP Fiori的技术框架和应用场景。 ... [详细]
  • Python安全实践:Web安全与SQL注入防御
    本文旨在介绍Web安全的基础知识,特别是如何使用Python和相关工具来识别和防止SQL注入攻击。通过实际案例分析,帮助读者理解SQL注入的危害,并掌握有效的防御策略。 ... [详细]
  • 本文总结了几个常用的Android开发技巧,包括检测设备上是否安装特定应用、获取应用的版本名称、设置状态栏透明以及如何从一个应用跳转至另一个应用的方法。 ... [详细]
  • 这个报错出现在userDao里面,sessionfactory没有注入。解决办法:spring整合Hibernate使用test测试时要把spring.xml和spring-hib ... [详细]
  • Android开发经验分享:优化用户体验的关键因素
    随着Android市场的不断扩展,用户对于移动应用的期望也在不断提高。本文探讨了在Android开发中如何优化用户体验,以及为何用户体验的重要性超过了技术本身。 ... [详细]
  • 解析 HTTP 头 'Vary: Accept-Encoding' 的作用与重要性
    本文详细探讨了 'Vary: Accept-Encoding' HTTP 头的作用,即指导缓存系统(如代理服务器和 CDN)根据不同的编码需求存储和提供适当的资源版本,确保不同类型的客户端能够接收到适合自己的内容。 ... [详细]
  • 拖拉切割直线 ... [详细]
  • 本文介绍了在Android Studio中通过代码和配置文件两种方法来移除Activity的标题栏,并讨论了当Activity继承自AppCompatActivity时的特殊处理方法。 ... [详细]
  • 本文介绍了QuantLib库的基本使用方法,重点探讨了日期(Date)和日历(Calendar)类在金融计算中的作用与实现。 ... [详细]
  • 尊敬的同行们:厦门谷京房产网作为一家新兴且快速发展的房地产网站,近期遭遇了来自百度乐居的强力冲击,导致公司面临前所未有的挑战。 ... [详细]
author-avatar
手机用户2602917665
这个家伙很懒,什么也没留下!
PHP1.CN | 中国最专业的PHP中文社区 | DevBox开发工具箱 | json解析格式化 |PHP资讯 | PHP教程 | 数据库技术 | 服务器技术 | 前端开发技术 | PHP框架 | 开发工具 | 在线工具
Copyright © 1998 - 2020 PHP1.CN. All Rights Reserved | 京公网安备 11010802041100号 | 京ICP备19059560号-4 | PHP1.CN 第一PHP社区 版权所有