ViewPager实现循环轮播图

本次做的是使用view pager实现循环轮播图,先展示效果图

实现的目标如下:

1、图片可以自动变换

2、“无限循环”

3、图片下方用小圆点来展示对应的位置

实现思路:

1、建立布局

2、设置适配器

3、实习vew pager基本功能,即手动滑动

4、实现view pager滑动时改变时改变对应小圆点的状态(选中&未选中)

5、实现viewpager内容自动滑动

第一部分:建立布局

<?xml version="1.0" encoding="utf-8"?>
<RelativeLayout 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="com.example.count.count.Other_35">
<android.support.v4.view.ViewPager
    android:id="@+id/vp_Other35_one"
    android:layout_width="match_parent"
    android:layout_height="200dp">

</android.support.v4.view.ViewPager>
    <LinearLayout
        android:id="@+id/ll_Other35_one"
        android:layout_alignBottom="@id/vp_Other35_one"
        android:orientation="horizontal"
        android:gravity="center_horizontal"
        android:layout_width="match_parent"
        android:layout_height="wrap_content">
            <ImageView
                android:layout_width="wrap_content"
                android:layout_height="match_parent"
                android:src="@drawable/point_select"
                android:padding="5dp"
                />
            <ImageView
                android:layout_width="wrap_content"
                android:layout_height="match_parent"
                android:src="@drawable/point_normal"
                android:padding="5dp"
                />
            <ImageView
                android:layout_width="wrap_content"
                android:layout_height="match_parent"
                android:src="@drawable/point_normal"
                android:padding="5dp"
                />
            <ImageView
                android:layout_width="wrap_content"
                android:layout_height="match_parent"
                android:src="@drawable/point_normal"
                android:padding="5dp"
                />
        <ImageView
            android:layout_width="wrap_content"
            android:layout_height="match_parent"
            android:src="@drawable/point_normal"
            android:padding="5dp"
            />
    </LinearLayout>
</RelativeLayout>
效果图:


值得注意的是,在这里我们预先把小圆点的布局给建立完成,通过代码改变它的状态

第二部分:设置适配器

代码:

package com.example.count.count;

import android.support.v4.view.PagerAdapter;
import android.util.Log;
import android.view.View;
import android.view.ViewGroup;

import java.util.List;

/**
 * Created by wei on 2017/10/12.
 */

public class MyPagerAdapter extends PagerAdapter {
    //视图集合
    private List<View> viewList;
    public MyPagerAdapter(List<View> viewList)
    {
        this.viewList=viewList;
    }
    //返回条目总数,因为是轮播图,所以返回的值应该是一个极大的值
    @Override
    public int getCount() {
        return Integer.MAX_VALUE;
    }
    //判断view是否为新的条目
    @Override
    public boolean isViewFromObject(View view, Object object) {
        return view==object;
    }
    //返回需要加载的视图
    @Override
    public Object instantiateItem(ViewGroup container, int position) {

        /*
        这里用position%viewList.size(),意思是因为向由滑动的次数已经是非常大了,
        但是实际项目中的轮播图却远远没有这么多,所以我们对我们当前需要加载的position进行取余
        操作,例如这次轮播图的数量是5,所以position的有效范围应该是0-4,超过这些范围的其实是这些范围
        的倍数,我们进行取余后正好得到0-4,就可以将这些正确的布局加载进去
        * */
        int newPosition=position % viewList.size();
        Log.d("Other_35","我加载的是第"+newPosition+"项");
        //得到有效的位置后在获得对应的图片
        View newView=viewList.get(newPosition);
        //将图片存入viewGroup中
        container.addView(newView);
        return newView;
    }
    //销毁视图
    @Override
    public void destroyItem(ViewGroup container, int position, Object object) {
        /*
        因为需求是实现轮播图,那么图片应该是可以无限循环的,但是我们已知我们的图片只有五张
        为了实现这个功能,我们可以把viewpager的初始项设置为5000000,虽然并没有实现真正意义上的
        无限循环,但是也足以满足用户的需求;那么就衍生出一个问题,我们知道viewList.Size()的值是
        5,而此时position的值应该是4999999,所以会曝出数组越界的错误,我们需要将position的值进行
        处理才可以用
        * */
        int newPosition=position % viewList.size();
        Log.d("Other_35","viewList.size的值是"+viewList.size());
        Log.d("Other_35", "我删除的是viewList中的第"+position+"项");
        container.removeView(viewList.get(newPosition));
    }
}

第三部分:实现viewpager的基本功能

public void InitData()
{
    viewList=new ArrayList<View>();
    images=new int[]{R.drawable.image1,R.drawable.image2,R.drawable.image3,R.drawable.image4,R.drawable.image5};
    ViewGroup.LayoutParams layoutParams=new ViewGroup.LayoutParams(ViewGroup.LayoutParams.MATCH_PARENT,ViewGroup.LayoutParams.MATCH_PARENT);
    for (int i:images)
    {
        ImageView imageView=new ImageView(this);
        /*
        刚开始使用imageView.setImageResource(i)时,viewpager中显示的是原图的大小,造成很多空白
        采用imageView.setBackgroundResource(i);可以解决这个问题,具体原因未知
        * */
        imageView.setBackgroundResource(i);
        imageView.setLayoutParams(layoutParams);
        viewList.add(imageView);
    }
}
第四部分:实现小圆点的改变

public void InitPoint()
{
    //将轮播图的数量与小圆点数量进行匹配
    points=new ImageView[images.length];
    //这里通过ll_Other35_one.getChildCount()得到该布局下的控件数量 然后一一初始为未选中的状态
    for (int i=0;i<ll_Other35_one.getChildCount();i++)
    {
        points[i]= (ImageView) ll_Other35_one.getChildAt(i);
        points[i].setImageResource(R.drawable.point_normal);
    }
    //初始化第一个为选中状态
    Log.d("Other_35","currentPosition%images.length的值是"+currentPosition%images.length);
    points[currentPosition%images.length].setImageResource(R.drawable.point_select);
}
//动态改变小圆点的状态
public void SetCurrentPoint(int currentPosition)
{
    //首先先把所有的小圆点都设置为未选中
    for (int i=0;i<ll_Other35_one.getChildCount();i++)
    {
        points[i]= (ImageView) ll_Other35_one.getChildAt(i);
        points[i].setImageResource(R.drawable.point_normal);
    }
    //currentPosition的值应该在5000000左右 显然超过了points的数量 所以需要进行取余操作
    points[currentPosition%images.length].setImageResource(R.drawable.point_select);
}
第五部分:实现自动播放

class Start extends AsyncTask<Void,Void,Void>
{

    @Override
    protected Void doInBackground(Void... params) {
        try {
                //设置轮播图的更换时间
                Thread.sleep(1500);
        } catch (InterruptedException e) {
            e.printStackTrace();
        }
        return null;
    }

    @Override
    protected void onPostExecute(Void aVoid) {
              vp_Other35_one.setCurrentItem(vp_Other35_one.getCurrentItem()+1);
    }
}
其中值得注意的是:如果是正常的调用,只会执行一次,所以在这个函数中启动,每一次页面发生变化,都会调用启动

以此达到递归的作用

public void onPageSelected(int position) {
    Log.d("Other_35","当前轮播图处在的位置是"+currentPosition);
    SetCurrentPoint(position%images.length);
    //当界面发生改变的时候 就开启这个线程 到达递归调用的作用
    Start start= (Start) new Start().execute();
}
当然,如果只在这里启动是并不能一直运行的,因为程序一开始图片不会自己滑动,也就不会调用
onPageSelected(),所以还需要在数据初始完毕的时候,预先启动一次,像这样
protected void onCreate(Bundle savedInstanceState) {
    super.onCreate(savedInstanceState);
    setContentView(R.layout.activity_other_35);
    InitViews();
    InitData();
    InitPoint();
    InitAdapter();
    Start start= (Start) new Start().execute();
}
这样一来,程序一进去就会滑动一次,也就触发了onPageSelected这个函数,就实现了自动循环
全部代码如下:
package com.example.count.count;

import android.os.AsyncTask;
import android.os.Bundle;
import android.support.v4.view.PagerAdapter;
import android.support.v4.view.ViewPager;
import android.support.v7.app.AppCompatActivity;
import android.util.Log;
import android.view.View;
import android.view.ViewGroup;
import android.widget.ImageView;
import android.widget.LinearLayout;

import java.util.ArrayList;
import java.util.List;

public class Other_35 extends AppCompatActivity implements ViewPager.OnPageChangeListener{
    private ViewPager vp_Other35_one;
    private List<View> viewList;
    private PagerAdapter myPagerAdapter;
    private LinearLayout ll_Other35_one;
    //记录轮播图当前的位置
    private int currentPosition;
    //存放小原点
    private ImageView[] points;
    //存放轮播图
    private int[]images;
    @Override
    protected void onCreate(Bundle savedInstanceState) {
        super.onCreate(savedInstanceState);
        setContentView(R.layout.activity_other_35);
        InitViews();
        InitData();
        InitPoint();
        InitAdapter();
        Start start= (Start) new Start().execute();
    }
    //初始化布局
    public void InitViews()
    {

        vp_Other35_one= (ViewPager) findViewById(R.id.vp_Other35_one);
        ll_Other35_one= (LinearLayout) findViewById(R.id.ll_Other35_one);

    }
    //初始化数据
    public void InitData()
    {
        viewList=new ArrayList<View>();
        images=new int[]{R.drawable.image1,R.drawable.image2,R.drawable.image3,R.drawable.image4,R.drawable.image5};
        ViewGroup.LayoutParams layoutParams=new ViewGroup.LayoutParams(ViewGroup.LayoutParams.MATCH_PARENT,ViewGroup.LayoutParams.MATCH_PARENT);
        for (int i:images)
        {
            ImageView imageView=new ImageView(this);
            /*
            刚开始使用imageView.setImageResource(i)时,viewpager中显示的是原图的大小,造成很多空白
            采用imageView.setBackgroundResource(i);可以解决这个问题,具体原因未知
            * */
            imageView.setBackgroundResource(i);
            imageView.setLayoutParams(layoutParams);
            viewList.add(imageView);
        }
    }
    //初始化适配器
    public void InitAdapter()
    {
        myPagerAdapter=new MyPagerAdapter(viewList);
        vp_Other35_one.setAdapter(myPagerAdapter);
        vp_Other35_one.setCurrentItem(5000000);
        //设置监听器
        vp_Other35_one.setOnPageChangeListener(this);
        //将当前位置的值进行初始
        currentPosition=5000000;
    }
    //初始化轮播图下的小圆点 currentPosition表示当前轮播图位置
    public void InitPoint()
    {
        //将轮播图的数量与小圆点数量进行匹配
        points=new ImageView[images.length];
        //这里通过ll_Other35_one.getChildCount()得到该布局下的控件数量 然后一一初始为未选中的状态
        for (int i=0;i<ll_Other35_one.getChildCount();i++)
        {
            points[i]= (ImageView) ll_Other35_one.getChildAt(i);
            points[i].setImageResource(R.drawable.point_normal);
        }
        //初始化第一个为选中状态
        Log.d("Other_35","currentPosition%images.length的值是"+currentPosition%images.length);
        points[currentPosition%images.length].setImageResource(R.drawable.point_select);
    }
    //动态改变小圆点的状态
    public void SetCurrentPoint(int currentPosition)
    {
        //首先先把所有的小圆点都设置为未选中
        for (int i=0;i<ll_Other35_one.getChildCount();i++)
        {
            points[i]= (ImageView) ll_Other35_one.getChildAt(i);
            points[i].setImageResource(R.drawable.point_normal);
        }
        //currentPosition的值应该在5000000左右 显然超过了points的数量 所以需要进行取余操作
        points[currentPosition%images.length].setImageResource(R.drawable.point_select);
    }

    @Override
    public void onPageScrolled(int position, float positionOffset, int positionOffsetPixels) {

    }

    @Override
    public void onPageSelected(int position) {
        Log.d("Other_35","当前轮播图处在的位置是"+currentPosition);
        SetCurrentPoint(position%images.length);
        //当界面发生改变的时候 就开启这个线程 到达递归调用的作用
        Start start= (Start) new Start().execute();
    }

    @Override
    public void onPageScrollStateChanged(int state) {

    }
    class Start extends AsyncTask<Void,Void,Void>
    {

        @Override
        protected Void doInBackground(Void... params) {
            try {
                    //设置轮播图的更换时间
                    Thread.sleep(1500);
            } catch (InterruptedException e) {
                e.printStackTrace();
            }
            return null;
        }

        @Override
        protected void onPostExecute(Void aVoid) {
                  vp_Other35_one.setCurrentItem(vp_Other35_one.getCurrentItem()+1);
        }
    }
}
总结与反思:
	1、线程并没有关闭,除非是activity已经destroy,不然图片会一直轮播下去
	2、并没有实现真正的无限循环,不过5000000*1.5秒=125000分钟=2083小时=86天,如果手机不充电的话,
电池早就挂了,所以并不用担心程序会因为运行到终点而报错
	3、各个部分的功能应该明确分开,一步步的完成,也就是说要尽量避免高耦合


评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值