前往小程序,Get更优阅读体验!
立即前往
首页
学习
活动
专区
工具
TVP
发布
社区首页 >专栏 >Android Viewpager实现无限循环轮播图

Android Viewpager实现无限循环轮播图

作者头像
砸漏
发布2020-11-04 15:38:22
3.6K0
发布2020-11-04 15:38:22
举报
文章被收录于专栏:恩蓝脚本恩蓝脚本

在网上找了很多viewpager实现图片轮播的,但是大多数通过以下方式在PagerAdapter的getCount()返回一个无限大的数,来实现 伪无限

代码语言:javascript
复制
@Override
  public int getCount() {
    return Integer.MAX_VALUE;//返回一个无限大的值,可以 无限循环
  }

虽然通过这种方式是能达到效果,但是从严格意义上来说并不是真正的无限。

假如有五张轮播图item的编号为(0,1,2,3,4) 要想实现 无限循环 我们在这五张的头部和尾部各加一张即(5+2)张,item编号为(0,1,2,3,4,5,6)其中编号为0,6的两张不做展示只是为了做循环轮播的铺垫,使得播放更加平滑。

1、当我们从编号为5 右滑的时候到了编号6 这时候就将当前页面设置为1

2、当我们从编号为1左滑的时候到了编号0 这时候就将当前页面设置为5

这么做之后就可以实现无限轮播 怎么保证从编号6跳转编号1的时候不出现页面停顿 突然跳到下一页的现象呢?

代码语言:javascript
复制
public Object instantiateItem (ViewGroup container, int position)

在指定的位置创建页面;适配器负责添加view到这个容器中,然而它只保证在finishUpdate(ViewGroup)返回时才完成。

代码语言:javascript
复制
public void destroyItem (ViewGroup container, int position, Object object)

删除指定位置的页面;适配器负责从view容器中删除view,然而它只保证在finishUpdate(ViewGroup)返回时才完成。

所以说 重点就在于finishUpdate(ViewGroup)这个方法 其实无论是创建view添加到容器中 还是 销毁view 都是在此方法结束之后执行的

换句话说 就是 我在这个方法里让页面完成从 编号5跳转到编号1 或者从编号1跳转到编号5,此方法完成时 视图还未完成创建或者 销毁 这样也就不会出现页面停顿 突然跳到下一页的现象。

代码语言:javascript
复制
@Override
  public void finishUpdate(ViewGroup container) {
    super.finishUpdate(container);
 
    int position = viewPager.getCurrentItem();
    
    if (position == 0) {
      position = simpleDraweeViewList.size() - 2;
      viewPager.setCurrentItem(position,false);
    } else if (position == simpleDraweeViewList.size() - 1) {
      position = 1;
      viewPager.setCurrentItem(position,false);
    }
  }

话不多说,上代码:

布局文件:

代码语言:javascript
复制
<?xml version="1.0" encoding="utf-8"? 
<android.support.constraint.ConstraintLayout xmlns:android="http://schemas.android.com/apk/res/android"
  xmlns:app="http://schemas.android.com/apk/res-auto"
  xmlns:tools="http://schemas.android.com/tools"
  android:layout_width="match_parent"
  android:layout_height="match_parent"
  tools:context=".MainActivity" 
 
  <FrameLayout
    android:id="@+id/frameLayout"
    android:layout_width="0dp"
    android:layout_height="200dp"
    app:layout_constraintEnd_toEndOf="parent"
    app:layout_constraintHorizontal_bias="0.0"
    app:layout_constraintStart_toStartOf="parent"
    app:layout_constraintTop_toTopOf="parent" 
 
    <android.support.v4.view.ViewPager
      android:id="@+id/viewPager"
      android:layout_width="match_parent"
      android:layout_height="match_parent"
      tools:layout_editor_absoluteX="8dp"
      tools:layout_editor_absoluteY="0dp" / 
 
    <LinearLayout
      android:layout_width="match_parent"
      android:layout_height="35dip"
      android:layout_gravity="bottom"
      android:background="#33000000"
      android:gravity="center_vertical"
      android:orientation="horizontal"
      android:weightSum="10" 
 
      <TextView
        android:id="@+id/tv_pager_title"
        android:layout_width="0dp"
        android:layout_height="35dip"
        android:layout_weight="8"
        android:gravity="center_vertical"
        android:paddingLeft="8dip"
        android:text="加载图片轮播失败"
        android:textColor="@android:color/white" / 
 
      <LinearLayout
        android:id="@+id/lineLayout_dot"
        android:layout_width="0dp"
        android:layout_height="match_parent"
        android:layout_marginRight="5dp"
        android:layout_weight="2"
        android:gravity="center|right"
        android:orientation="horizontal"
        android:paddingLeft="3dp"
        android:paddingRight="3dp" / 
 
    </LinearLayout 
 
  </FrameLayout 
 
</android.support.constraint.ConstraintLayout 

最主要的PagerAdapter:

代码语言:javascript
复制
import android.content.Context;
import android.support.v4.view.PagerAdapter;
import android.support.v4.view.ViewPager;
import android.util.Log;
import android.view.View;
import android.view.ViewGroup;
 
import com.facebook.drawee.view.SimpleDraweeView;
 
import java.util.List;
 
public class ImagesPagerAdapter extends PagerAdapter {
  private List<SimpleDraweeView  simpleDraweeViewList;
  private ViewPager viewPager;
  private Context context;
 
  private SimpleDraweeView simpleDraweeView;
 
  public ImagesPagerAdapter(List<SimpleDraweeView  simpleDraweeViewList, ViewPager viewPager, Context context) {
    this.simpleDraweeViewList = simpleDraweeViewList;
    this.viewPager = viewPager;
    this.context = context;
  }
 
  @Override
  public int getCount() {
 return simpleDraweeViewList.size();
  }
 
  //删除指定位置的页面;适配器负责从view容器中删除view,然而它只保证在finishUpdate(ViewGroup)返回时才完成。
  @Override
  public void destroyItem(ViewGroup container, int position, Object object) {
    // 把ImageView从ViewPager中移除掉
    viewPager.removeView(simpleDraweeViewList.get(position));
    //super.destroyItem(container, position, object);
  }
 
  //是否获取缓存
  @Override
  public boolean isViewFromObject(View view, Object object) {
    return view == object;
  }
 
 
  //实例化Item
  //在指定的位置创建页面;适配器负责添加view到这个容器中,然而它只保证在finishUpdate(ViewGroup)返回时才完成。
  @Override
  public Object instantiateItem(ViewGroup container, int position) {
    simpleDraweeView = simpleDraweeViewList.get(position);
    viewPager.addView(simpleDraweeView);
    return simpleDraweeView;
  }
 
  @Override
  public int getItemPosition(Object object) {
    return POSITION_NONE;
  }
 
  //无论是创建view添加到容器中 还是 销毁view 都是在此方法结束之后执行的
 @Override
  public void finishUpdate(ViewGroup container) {
    super.finishUpdate(container);
 
    int position = viewPager.getCurrentItem();
    
    if (position == 0) {
      position = simpleDraweeViewList.size() - 2;
      viewPager.setCurrentItem(position,false);
    } else if (position == simpleDraweeViewList.size() - 1) {
      position = 1;
      viewPager.setCurrentItem(position,false);
    }
  }
 
 
 
/*  private int mChildCount = 0;
  @Override
  public void notifyDataSetChanged() {
    mChildCount = getCount();
    super.notifyDataSetChanged();
  }
  @Override
  public int getItemPosition(Object object) {
    if (mChildCount   0) {
      mChildCount--;
      Log.e("image","getItemPosition");
      return POSITION_NONE;
    }
    return super.getItemPosition(object);
  }*/
}
代码语言:javascript
复制
import android.app.Activity;
import android.content.Context;
import android.graphics.drawable.Drawable;
import android.support.v4.content.ContextCompat;
import android.support.v4.view.ViewPager;
import android.util.Log;
import android.view.View;
import android.view.ViewGroup;
import android.widget.LinearLayout;
import android.widget.TextView;
import com.facebook.drawee.view.SimpleDraweeView;
import java.util.ArrayList;
import java.util.List;
public class ImageCarousel {
private Context context;
private ViewPager viewPager;
private TextView tvTitle;
private LinearLayout dotsRoot;
private int time;
private List<View  dots;//小点
private int previousPosition = 1;//前一个被选中的position
private List<SimpleDraweeView  simpleDraweeViewList;
private String[] titles;//标题数组
private ImagesPagerAdapter adapter;
private AutoPlayThread autoPlayThread;
private volatile boolean isExit = true;
private static final int FIRST_PAGE = 1;
public ImageCarousel(Context context, ViewPager viewPager, TextView tvTitle,
List<View  dots, int time) {
this.context = context;
this.viewPager = viewPager;
this.tvTitle = tvTitle;
this.dots = dots;
this.time = time;
Log.e("image", "构造方法");
}
/**
* 传入数据
*
* @param simpleDraweeViewList SimpleDraweeView集合
* @param titles        标题数组
* @return this 本身
*/
public ImageCarousel init(List<SimpleDraweeView  simpleDraweeViewList, String[] titles) {
this.simpleDraweeViewList = simpleDraweeViewList;
this.titles = titles;
Log.e("image", "init");
autoPlayThread = new AutoPlayThread();
return this;
}
/**
* 重新加载,有待考验...
*
* @param simpleDraweeViewList SimpleDraweeView集合
* @param titles        标题数组
*/
public void reload(List<SimpleDraweeView  simpleDraweeViewList, String[] titles) {
init(simpleDraweeViewList, titles);
previousPosition = 0;
start();
}
/**
* 设置设配器,并实现轮播功能
*/
public void start() {
if (adapter != null) {
adapter = null;
}
adapter = new ImagesPagerAdapter(this.simpleDraweeViewList, viewPager, context);
viewPager.setAdapter(adapter);
viewPager.addOnPageChangeListener(new ViewPager.OnPageChangeListener() {
@Override
public void onPageScrolled(int position, float positionOffset, int positionOffsetPixels) {
}
//当被选择
@Override
public void onPageSelected(int position) {
int currentPosition = 1;
if (position == simpleDraweeViewList.size() - 1) {
// 设置当前值为1
currentPosition = FIRST_PAGE;
} else if (position == 0) {
// 如果索引值为0了,就设置索引值为倒数第二个
currentPosition = simpleDraweeViewList.size() - 2;
} else {
currentPosition = position;
}
// 把当前选中的点给切换了, 还有描述信息也切换
tvTitle.setText(titles[currentPosition]);//图片下面设置显示文本
//设置轮播点 可设置成传入的图
Log.d("dots", "previousPosition=" + previousPosition + " currentPosition=" + currentPosition);
dots.get(previousPosition-1).setBackgroundResource(R.drawable.ic_dot_focused);
dots.get(currentPosition-1).setBackgroundResource(R.drawable.ic_dot_normal);
// 把当前的索引赋值给前一个索引变量, 方便下一次再切换.
previousPosition = currentPosition;
}
@Override
public void onPageScrollStateChanged(int state) {
// SCROLL_STATE_IDLE :空闲状态 
// SCROLL_STATE_DRAGGING :滑动状态 
// SCROLL_STATE_SETTLING :滑动后滑翔的状态
if (state == ViewPager.SCROLL_STATE_DRAGGING) {
} else if(state == ViewPager.SCROLL_STATE_IDLE){
}
}
});
setFirstLocation();
//autoPlayThread.start();
}
/**
* 设置刚打开app时显示的图片和文字
*/
private void setFirstLocation() {
tvTitle.setText(titles[0]);
dots.get(0).setBackgroundResource(R.drawable.ic_dot_normal);
viewPager.setCurrentItem(1);
}
/**
* 设置是否轮播
*
* @param b
*/
private void setAutoPlay(boolean b) {
/*if (b && suspendRequested) {
autoPlayThread.requestResume();
} else if (!b){
autoPlayThread.requestSuspend();
}*/
}
public void stopAutoPlay() {
if (autoPlayThread != null) {
Log.e("thrad", "暂停");
isExit = true;
autoPlayThread.interrupt();
autoPlayThread = null;
}
}
/**
* 请求继续
*/
public void startAutoPlay() {
Log.e("thrad", "开始");
isExit = false;
autoPlayThread = null;
autoPlayThread = new AutoPlayThread();
autoPlayThread.start();
}
/**
* 自动播放线程,添加暂停和继续方法
*/
class AutoPlayThread extends Thread {
@Override
public synchronized void run() {
while (!isExit) {
try {
Thread.sleep(time);
} catch (InterruptedException e) {
Log.e("thrad", "强制请求退出线程");
break;
}
((Activity) context).runOnUiThread(new Runnable() {
@Override
public void run() {
viewPager.setCurrentItem(viewPager.getCurrentItem() + 1);
}
});
if (this.interrupted()) {
Log.e("thrad", "已经是停止状态了,我要退出了");
break;
}
}
}
}
}

mainActivity.java:

代码语言:javascript
复制
import android.app.Activity;
import android.content.Context;
import android.graphics.drawable.Drawable;
import android.net.Uri;
import android.support.v4.content.ContextCompat;
import android.support.v4.view.ViewPager;
import android.support.v7.app.AppCompatActivity;
import android.os.Bundle;
import android.view.View;
import android.view.ViewGroup;
import android.widget.AbsListView;
import android.widget.LinearLayout;
import android.widget.TextView;
import com.facebook.drawee.backends.pipeline.Fresco;
import com.facebook.drawee.backends.pipeline.PipelineDraweeController;
import com.facebook.drawee.drawable.ScalingUtils;
import com.facebook.drawee.generic.GenericDraweeHierarchy;
import com.facebook.drawee.generic.GenericDraweeHierarchyBuilder;
import com.facebook.drawee.view.SimpleDraweeView;
import com.facebook.imagepipeline.common.ResizeOptions;
import com.facebook.imagepipeline.request.ImageRequest;
import com.facebook.imagepipeline.request.ImageRequestBuilder;
import java.util.ArrayList;
import java.util.List;
public class MainActivity extends AppCompatActivity implements View.OnClickListener {
// 图片轮播控件
private ViewPager mViewPager;
private TextView mTvPagerTitle;
private LinearLayout mLineLayoutDot;
private ImageCarousel imageCarousel;
private List<View  dots;//小点
// 图片数据,包括图片标题、图片链接、数据、点击要打开的网站(点击打开的网页或一些提示指令)
private List<ImageInfo  imageInfoList;
@Override
protected void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
setContentView(R.layout.activity_main);
initView();
initEvent();
imageStart();
}
@Override
public void onClick(View v) {
}
/**
* 初始化事件
* 左右多添加一张图片
*/
private void initEvent() {
imageInfoList = new ArrayList< ();
imageInfoList.add(new ImageInfo(1, "图片5,公告5啦啦啦啦", "", "http://e.hiphotos.baidu.com/image/h%3D300/sign=73443062281f95cab9f594b6f9177fc5/72f082025aafa40fafb5fbc1a664034f78f019be.jpg", ""));
imageInfoList.add(new ImageInfo(2, "图片1,公告1啦啦啦啦", "", "http://d.hiphotos.baidu.com/image/pic/item/6159252dd42a2834a75bb01156b5c9ea15cebf2f.jpg", ""));
imageInfoList.add(new ImageInfo(3, "图片2,公告2啦啦啦啦", "", "http://c.hiphotos.baidu.com/image/h%3D300/sign=cfce96dfa251f3dedcb2bf64a4eff0ec/4610b912c8fcc3ce912597269f45d688d43f2039.jpg", ""));
imageInfoList.add(new ImageInfo(4, "图片3,公告3啦啦啦啦", "", "http://e.hiphotos.baidu.com/image/pic/item/6a600c338744ebf85ed0ab2bd4f9d72a6059a705.jpg", ""));
imageInfoList.add(new ImageInfo(5, "图片4,公告4啦啦啦啦", "", "http://b.hiphotos.baidu.com/image/h%3D300/sign=8ad802f3801001e9513c120f880e7b06/a71ea8d3fd1f4134be1e4e64281f95cad1c85efa.jpg", ""));
imageInfoList.add(new ImageInfo(6, "图片5,公告5啦啦啦啦", "", "http://e.hiphotos.baidu.com/image/h%3D300/sign=73443062281f95cab9f594b6f9177fc5/72f082025aafa40fafb5fbc1a664034f78f019be.jpg", ""));
imageInfoList.add(new ImageInfo(7, "图片1,公告1啦啦啦啦", "", "http://d.hiphotos.baidu.com/image/pic/item/6159252dd42a2834a75bb01156b5c9ea15cebf2f.jpg", ""));
}
/**
* 初始化控件
*/
private void initView() {
mViewPager = findViewById(R.id.viewPager);
mTvPagerTitle = findViewById(R.id.tv_pager_title);
mLineLayoutDot = findViewById(R.id.lineLayout_dot);
}
private void imageStart() {
//设置图片轮播
int[] imgaeIds = new int[]{R.id.pager_image1, R.id.pager_image2, R.id.pager_image3, R.id.pager_image4,
R.id.pager_image5, R.id.pager_image6, R.id.pager_image7, R.id.pager_image8};
String[] titles = new String[imageInfoList.size()];
List<SimpleDraweeView  simpleDraweeViewList = new ArrayList< ();
for (int i = 0; i < imageInfoList.size(); i++) {
titles[i] = imageInfoList.get(i).getTitle();
SimpleDraweeView simpleDraweeView = new SimpleDraweeView(this);
simpleDraweeView.setAspectRatio(1.78f);
// 设置一张默认的图片
GenericDraweeHierarchy hierarchy = new GenericDraweeHierarchyBuilder(this.getResources())
.setPlaceholderImage(ContextCompat.getDrawable(this, R.drawable.defult), ScalingUtils.ScaleType.CENTER_CROP).build();
simpleDraweeView.setHierarchy(hierarchy);
simpleDraweeView.setLayoutParams(new AbsListView.LayoutParams(AbsListView.LayoutParams.MATCH_PARENT, AbsListView.LayoutParams.WRAP_CONTENT));
//加载高分辨率图片;
ImageRequest imageRequest = ImageRequestBuilder.newBuilderWithSource(Uri.parse(imageInfoList.get(i).getImage()))
.setResizeOptions(new ResizeOptions(1280, 720))
.build();
PipelineDraweeController controller = (PipelineDraweeController) Fresco.newDraweeControllerBuilder()
//.setLowResImageRequest(ImageRequest.fromUri(Uri.parse(listItemBean.test_pic_low))) //在加载高分辨率图片之前加载低分辨率图片
.setImageRequest(imageRequest)
.setOldController(simpleDraweeView.getController())
.build();
simpleDraweeView.setController(controller);
simpleDraweeView.setId(imgaeIds[i]);//给view设置id
simpleDraweeView.setTag(imageInfoList.get(i));
simpleDraweeView.setOnClickListener(this);
titles[i] = imageInfoList.get(i).getTitle();
simpleDraweeViewList.add(simpleDraweeView);
}
dots = addDots(mLineLayoutDot, fromResToDrawable(this, R.drawable.ic_dot_focused), simpleDraweeViewList.size());
imageCarousel = new ImageCarousel(this, mViewPager, mTvPagerTitle, dots, 5000);
imageCarousel.init(simpleDraweeViewList, titles)
.startAutoPlay();
imageCarousel.start();
}
/**
* 动态添加一个点
*
* @param linearLayout 添加到LinearLayout布局
* @param backgount  设置
* @return 小点的Id
*/
private int addDot(final LinearLayout linearLayout, Drawable backgount) {
final View dot = new View(this);
LinearLayout.LayoutParams dotParams = new LinearLayout.LayoutParams(ViewGroup.LayoutParams.MATCH_PARENT,
ViewGroup.LayoutParams.WRAP_CONTENT);
dotParams.width = 16;
dotParams.height = 16;
dotParams.setMargins(4, 0, 4, 0);
dot.setLayoutParams(dotParams);
dot.setBackground(backgount);
dot.setId(View.generateViewId());
((Activity) this).runOnUiThread(new Runnable() {
@Override
public void run() {
linearLayout.addView(dot);
}
});
return dot.getId();
}
/**
* 资源图片转Drawable
*
* @param context 上下文
* @param resId  资源ID
* @return 返回Drawable图像
*/
public static Drawable fromResToDrawable(Context context, int resId) {
return ContextCompat.getDrawable(context, resId);
}
/**
* 添加多个轮播小点到横向线性布局
*
* @param linearLayout 线性横向布局
* @param backgount  小点资源图标
* @param number    数量
* @return 返回小点View集合
*/
private List<View  addDots(final LinearLayout linearLayout, Drawable backgount, int number) {
List<View  dots = new ArrayList< ();
for (int i = 2; i < number; i++) {  // 注意这里的 i 从 2 开始,只画出5个点
int dotId = addDot(linearLayout, backgount);
dots.add(findViewById(dotId));
}
return dots;
}
}

ic_dot_focused.xml:

代码语言:javascript
复制
<vector android:height="5dp" android:viewportHeight="24.0"
android:viewportWidth="24.0" android:width="5dp" xmlns:android="http://schemas.android.com/apk/res/android" 
<path android:fillColor="#c8ffffff" android:pathData="M12,12m-8,0a8,8 0,1 1,16 0a8,8 0,1 1,-16 0"/ 
</vector 

ic_dot_normal.xml:

代码语言:javascript
复制
<vector android:height="5dp" android:viewportHeight="24.0"
android:viewportWidth="24.0" android:width="5dp" xmlns:android="http://schemas.android.com/apk/res/android" 
<path android:fillColor="#c8fd8888" android:pathData="M12,12m-8,0a8,8 0,1 1,16 0a8,8 0,1 1,-16 0"/ 
</vector 

当然这里主要是实现真正的无限轮播,其中对于 用户手动滑动图片时需要暂停轮播没有做相关处理。

以上就是本文的全部内容,希望对大家的学习有所帮助。

本文参与 腾讯云自媒体分享计划,分享自作者个人站点/博客。
原始发表:2020-09-11 ,如有侵权请联系 cloudcommunity@tencent.com 删除

本文分享自 作者个人站点/博客 前往查看

如有侵权,请联系 cloudcommunity@tencent.com 删除。

本文参与 腾讯云自媒体分享计划  ,欢迎热爱写作的你一起参与!

评论
登录后参与评论
0 条评论
热度
最新
推荐阅读
相关产品与服务
容器服务
腾讯云容器服务(Tencent Kubernetes Engine, TKE)基于原生 kubernetes 提供以容器为核心的、高度可扩展的高性能容器管理服务,覆盖 Serverless、边缘计算、分布式云等多种业务部署场景,业内首创单个集群兼容多种计算节点的容器资源管理模式。同时产品作为云原生 Finops 领先布道者,主导开源项目Crane,全面助力客户实现资源优化、成本控制。
领券
问题归档专栏文章快讯文章归档关键词归档开发者手册归档开发者手册 Section 归档