本次做的是使用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 ListviewList; public MyPagerAdapter(List 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第四部分:实现小圆点的改变(); 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其中值得注意的是:如果是正常的调用,只会执行一次,所以在这个函数中启动,每一次页面发生变化,都会调用启动{ @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总结与反思: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 (); 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 { @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、各个部分的功能应该明确分开,一步步的完成,也就是说要尽量避免高耦合