欢迎您访问程序员文章站本站旨在为大家提供分享程序员计算机编程知识!
您现在的位置是: 首页  >  移动技术

Android Viewpager实现无限循环轮播图

程序员文章站 2022-05-16 12:34:07
在网上找了很多viewpager实现图片轮播的,但是大多数通过以下方式在pageradapter的getcount()返回一个无限大的数,来实现 伪无限 @ove...

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

@override
  public int getcount() {
    return integer.max_value;//返回一个无限大的值,可以 无限循环
  }

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

Android Viewpager实现无限循环轮播图

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

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

Android Viewpager实现无限循环轮播图

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

Android Viewpager实现无限循环轮播图

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

public object instantiateitem (viewgroup container, int position)

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

public void destroyitem (viewgroup container, int position, object object)

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

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

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

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

话不多说,上代码:

布局文件:

<?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:

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);
  }*/
}
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:

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:

<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:

<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>

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

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