循环轮播图 男娘i 2022-08-05 02:24 172阅读 0赞 循环轮播图,想必大家都在很多app山看到过,但是具体怎么实现呢?今天小弟就跟大家一种通过组合自定义view来实现的方法。 先看一张效果图: ![Center][] 再看一下结构 ![Center 1][] 现在开始正式讲解如何实现这个轮播图的自定义,首先定义一下轮播图的布局文件:shuffling\_picture.xml; <RelativeLayout xmlns:android="http://schemas.android.com/apk/res/android" xmlns:tools="http://schemas.android.com/tools" android:layout\_width="match\_parent" android:layout\_height="match\_parent" tools:context="com.example.lunbo.MainActivity" > <android.support.v4.view.ViewPager android:id="@+id/shuffling\_viewpage" android:layout\_width="match\_parent" android:layout\_height="match\_parent" android:layout\_centerHorizontal="true" /> <LinearLayout android:id="@+id/shuffling\_point\_layout" android:layout\_width="wrap\_content" android:layout\_height="wrap\_content" android:layout\_alignParentBottom="true" android:layout\_centerHorizontal="true" android:layout\_marginBottom="5dip" android:orientation="horizontal" > </LinearLayout> </RelativeLayout> 主要由一个ViewPage和一个LinearLagyout组成,其中ViewPage是用来放要轮播的图片,LineartLayout是用来动态的仿下面的小点,多少张图片就对应多少个点。 接下来看看自定义view的自定义属性文件:attrs.xml; <?xml version="1.0" encoding="utf-8"?> <resources> <declare-styleable name="ShufflingPicture"> <attr name="pointDrawbleNormal" format="reference"/> <attr name="pointDrawbleSelect" format="reference"/> </declare-styleable> </resources> 在这里我主要自定义了两个属性,一个是用来放小点的正常状态时的图片,一个是用来放小点的选择状态时的图片,可能有人会说为什么不用selector来放图片?起初我是用selector来的,但是出现了一些图片显示不出来的问题,所以我就暂时用了这种。 接下来我们再来看看最主要的部分,自定义的轮播图:ShufflingPicture; package com.demo.shufflingpicture; import java.util.LinkedList; import android.content.Context; import android.content.res.TypedArray; import android.graphics.drawable.Drawable; import android.os.Handler; import android.support.v4.view.PagerAdapter; import android.support.v4.view.ViewPager; import android.support.v4.view.ViewPager.OnPageChangeListener; import android.util.AttributeSet; import android.view.Gravity; import android.view.LayoutInflater; import android.view.MotionEvent; import android.view.View; import android.view.View.OnTouchListener; import android.view.ViewGroup; import android.widget.ImageView; import android.widget.LinearLayout; import android.widget.RelativeLayout; /\*\* \* 轮播图 \* \* @author fuxingkai \* \*/ public class ShufflingPicture extends RelativeLayout implements OnPageChangeListener, OnTouchListener \{ private Context context; private ViewPager imageViewPager; private AdapterCycle pagerAdapter; private LinearLayout pointLinearLayout; private LinkedList<View> views; private ImageView\[\] points; private Drawable pointDrawableNoraml; private Drawable pointDrawableSelect; private boolean isPlay = true; private boolean left = false; private boolean right = false; private boolean isScrolling = false; private int currentIndex = 0; private int pointIndex = 1; private int lastValue = -1; private ChangeViewCallback changeViewCallback = null; public ShufflingPicture(Context context) \{ super(context); this.context = context; initView(); \} public ShufflingPicture(Context context, AttributeSet attrs) \{ super(context, attrs); this.context = context; initView(); TypedArray a = context.obtainStyledAttributes(attrs, R.styleable.ShufflingPicture); pointDrawableNoraml = a .getDrawable(R.styleable.ShufflingPicture\_pointDrawbleNormal); pointDrawableSelect = a .getDrawable(R.styleable.ShufflingPicture\_pointDrawbleSelect); if (pointDrawableNoraml == null) \{ pointDrawableNoraml = getResources().getDrawable( R.drawable.point\_normal); \} ; if (pointDrawableSelect == null) \{ pointDrawableSelect = getResources().getDrawable( R.drawable.point\_select); \} a.recycle(); \} private void initView() \{ LayoutInflater.from(context).inflate(R.layout.shuffling\_picture, this); imageViewPager = (ViewPager) findViewById(R.id.shuffling\_viewpage); pointLinearLayout = (LinearLayout) findViewById(R.id.shuffling\_point\_layout); \} private void setViewPageAdapter(AdapterCycle pagerAdapter) \{ this.pagerAdapter = pagerAdapter; imageViewPager.setOnPageChangeListener(this); imageViewPager.setAdapter(pagerAdapter); imageViewPager.setOffscreenPageLimit(views.size()); imageViewPager.setCurrentItem(1); imageViewPager.setOnTouchListener(this); startShuffling(); \}; public void setViews(LinkedList<View> listViews) \{ views = listViews; initPoints(); setViewPageAdapter(new AdapterCycle(context, views)); \} // 实现ViewPager.OnPageChangeListener接口 @Override public void onPageSelected(int position) \{ if (pagerAdapter.getCount() > 1) \{ // 多于1,才会循环跳转 if (position < 1) \{ // 首位之前,跳转到末尾(N) position = views.size(); // 注意这里是mList,而不是mViews imageViewPager.setCurrentItem(position, false); \} else if (position > views.size()) \{ // 末位之后,跳转到首位(1) imageViewPager.setCurrentItem(1, false); // false:不显示跳转过程的动画 position = 1; \} else \{ setCurDot(position - 1); \} \} \} private Handler handler = new Handler(); private Runnable runnable = new Runnable() \{ @Override public void run() \{ if (isPlay) \{ if (pointIndex < views.size() + 1) \{ pointIndex++; \} else \{ pointIndex = 0; \} imageViewPager.setCurrentItem(pointIndex); if (pointIndex < 1) \{ // 首位之前,跳转到末尾(N) pointIndex = views.size(); // 注意这里是mList,而不是mViews imageViewPager.setCurrentItem(pointIndex, true); \} else if (pointIndex > views.size()) \{ // 末位之后,跳转到首位(1) imageViewPager.setCurrentItem(1, false); // false:不显示跳转过程的动画 pointIndex = 1; \} else \{ setCurDot(pointIndex - 1); \} \} handler.postDelayed(this, 2000); \} \}; private void startShuffling() \{ handler.postDelayed(runnable, 2000); \}; private void initPoints() \{ points = new ImageView\[views.size()\]; // 动态添加小点 for (int i = 0; i < views.size(); i++) \{ LinearLayout.LayoutParams llp = new LinearLayout.LayoutParams( LayoutParams.WRAP\_CONTENT, LayoutParams.WRAP\_CONTENT); ImageView point\_view = new ImageView(context);// ne 一个ImageView point\_view.setPadding(10, 5, 10, 5); point\_view.setClickable(true); llp.gravity = Gravity.CENTER\_VERTICAL; point\_view.setImageDrawable(pointDrawableNoraml);// 设置资源 pointLinearLayout.addView(point\_view, llp); // 最后一步,添加控件到布局中 \} // 循环取得小点图片 for (int i = 0; i < views.size(); i++) \{ // 得到一个LinearLayout下面的每一个子元素 points\[i\] = (ImageView) pointLinearLayout.getChildAt(i); // 默认都设为灰色 points\[i\].setEnabled(true); // 给每个小点设置监听 points\[i\].setOnClickListener(new OnClickListener() \{ @Override public void onClick(View v) \{ int positions = (Integer) v.getTag(); setCurView(positions + 1); setCurDot(positions); pointIndex = positions; \} \}); // 设置位置tag,方便取出与当前位置对应 points\[i\].setTag(i); \} // 当只有一张图片的时候,隐藏那个小点 if (views.size() > 1) \{ pointLinearLayout.setVisibility(View.VISIBLE); \} else \{ pointLinearLayout.setVisibility(View.GONE); \} currentIndex = 0; // 设置为白色,即选中状态 points\[0\].setEnabled(false); points\[0\].setImageDrawable(pointDrawableSelect); \} protected void setCurDot(int position) \{ if (position < 0 || position > views.size() - 1 || currentIndex == position) \{ return; \} points\[position\].setEnabled(false); points\[position\].setImageDrawable(pointDrawableSelect);// 设置资源 points\[currentIndex\].setEnabled(true); points\[currentIndex\].setImageDrawable(pointDrawableNoraml); currentIndex = position; \} protected void setCurView(int position) \{ if (position < 0) \{ return; \} imageViewPager.setCurrentItem(position); \} @Override public void onPageScrolled(int position, float positionOffset, int positionOffsetPixels) \{ if (isScrolling) \{ if (lastValue > positionOffsetPixels) \{ // 递减,向右侧滑动 right = true; left = false; \} else if (lastValue < positionOffsetPixels) \{ // 递减,向右侧滑动 right = false; left = true; \} else if (lastValue == positionOffsetPixels) \{ right = left = false; \} \} lastValue = positionOffsetPixels; \} @Override public void onPageScrollStateChanged(int state) \{ if (state == 1) \{ isScrolling = true; \} else \{ isScrolling = false; \} if (state == 2) \{ if (changeViewCallback != null) \{ changeViewCallback.changeView(left, right); \} right = left = false; \} \} @Override public boolean onTouch(View v, MotionEvent event) \{ switch (event.getAction()) \{ case MotionEvent.ACTION\_DOWN: isPlay = false; break; case MotionEvent.ACTION\_UP: isPlay = true; if (right) \{ pointIndex = currentIndex; \} if (left) \{ pointIndex = currentIndex + 1; \} break; default: break; \} return false; \} /\*\* \* 得到是否向右侧滑动 \* \* @return true 为右滑动 \*/ public boolean getMoveRight() \{ return right; \} /\*\* \* 得到是否向左侧滑动 \* \* @return true 为左做滑动 \*/ public boolean getMoveLeft() \{ return left; \} /\*\* \* 滑动状态改变回调 \* \* @author fuxingkai \* \*/ public interface ChangeViewCallback \{ /\*\* \* 切换视图 ?决定于left和right 。 \* \* @param left \* @param right \*/ public void changeView(boolean left, boolean right); \} /\*\* \* set ... \* \* @param callback \*/ public void setChangeViewCallback(ChangeViewCallback callback) \{ changeViewCallback = callback; \} public class AdapterCycle extends PagerAdapter \{ private LinkedList<View> mViews; // 新view集合 public AdapterCycle(Context context, LinkedList<View> mOldViews) \{ if (mOldViews != null) \{ // 无论是否多于1个,都要初始化第一个(index:0) mViews = new LinkedList<View>(); final ImageView view = (ImageView) mOldViews.get(mOldViews .size() - 1); ImageView imageView = new ImageView(context); imageView.setImageDrawable(view.getDrawable()); mViews.add(imageView); // 注意,如果不只1个,mViews比mList多两个(头尾各多一个) // 假设:mList为mList\[0~N-1\], mViews为mViews\[0~N+1\] // mViews\[0\]放mList\[N-1\], mViews\[i\]放mList\[i-1\], // mViews\[N+1\]放mList\[0\] // mViews\[1~N\]用于循环;首位之前的mViews\[0\]和末尾之后的mViews\[N+1\]用于跳转 // 首位之前的mViews\[0\],跳转到末尾(N);末位之后的mViews\[N+1\],跳转到首位(1) if (mOldViews.size() > 1) \{ // 多于1个要循环 for (int i = 0; i < mOldViews.size(); i++) \{ // 中间的N个(index:1~N) final View view1 = mOldViews.get(i); mViews.add(view1); \} // 最后一个(index:N+1) final ImageView view2 = (ImageView) mOldViews.get(0); ImageView imageView1 = new ImageView(context); imageView.setImageDrawable(view2.getDrawable()); mViews.add(imageView1); \} \} \} @Override public int getCount() \{ return mViews.size(); \} @Override public boolean isViewFromObject(View view, Object object) \{ return view == object; \} @Override public void destroyItem(ViewGroup container, int position, Object object) \{ ((ViewPager) container).removeView(mViews.get(position)); \} @Override public Object instantiateItem(ViewGroup container, int position) \{ View view = mViews.get(position); container.addView(view); return view; \} \} \} 首先是继承一个RelativeLayout类,然后实现他的OnPageChangeListener, OnTouchListener这两个监听。然后在构造函数中调用initView()方法,初始化轮播图里面的view ![Center 2][] 把刚才写的自定义轮播图的布局加载进来。 ![Image 1][] ![Center 3][] 然后初始化小点的两个状态对应的图片,记得recycle掉。 通过setViews方法,把要轮播的图片加载进来 public void setViews(LinkedList<View> listViews) \{ views = listViews; initPoints(); setViewPageAdapter(new AdapterCycle(context, views)); \} 然后在这里面初始化小点 private void initPoints() \{ points = new ImageView\[views.size()\]; // 动态添加小点 for (int i = 0; i < views.size(); i++) \{ LinearLayout.LayoutParams llp = new LinearLayout.LayoutParams( LayoutParams.WRAP\_CONTENT, LayoutParams.WRAP\_CONTENT); ImageView point\_view = new ImageView(context);// ne 一个ImageView point\_view.setPadding(10, 5, 10, 5); point\_view.setClickable(true); llp.gravity = Gravity.CENTER\_VERTICAL; point\_view.setImageDrawable(pointDrawableNoraml);// 设置资源 pointLinearLayout.addView(point\_view, llp); // 最后一步,添加控件到布局中 \} // 循环取得小点图片 for (int i = 0; i < views.size(); i++) \{ // 得到一个LinearLayout下面的每一个子元素 points\[i\] = (ImageView) pointLinearLayout.getChildAt(i); // 默认都设为灰色 points\[i\].setEnabled(true); // 给每个小点设置监听 points\[i\].setOnClickListener(new OnClickListener() \{ @Override public void onClick(View v) \{ int positions = (Integer) v.getTag(); setCurView(positions + 1); setCurDot(positions); pointIndex = positions; \} \}); // 设置位置tag,方便取出与当前位置对应 points\[i\].setTag(i); \} // 当只有一张图片的时候,隐藏那个小点 if (views.size() > 1) \{ pointLinearLayout.setVisibility(View.VISIBLE); \} else \{ pointLinearLayout.setVisibility(View.GONE); \} currentIndex = 0; // 设置为白色,即选中状态 points\[0\].setEnabled(false); points\[0\].setImageDrawable(pointDrawableSelect); \} 通过计算图片的个数,然后在pointLinearLayout里面add进对应的小点每个小点设置为可点击图片设置为正常状态的小点。然后循环读取每个小点,给他们设置点击事件通过settag方法来辨别小点,然后里面的setCurview方法是用来设置viewpage当前显示的是那个页面,setcurDot是用来设置当前小点显示的是哪个点,判断一下,如果只用一张图片,就不显示小点,设置当前第一个小点为选择状态。其中setcurView和setcurDot方法里面的东西很简单就不多说 protected void setCurDot(int position) \{ if (position < 0 || position > views.size() - 1 || currentIndex == position) \{ return; \} points\[position\].setEnabled(false); points\[position\].setImageDrawable(pointDrawableSelect);// 设置资源 points\[currentIndex\].setEnabled(true); points\[currentIndex\].setImageDrawable(pointDrawableNoraml); currentIndex = position; \} protected void setCurView(int position) \{ if (position < 0) \{ return; \} imageViewPager.setCurrentItem(position); \} 在上setViews里面还为viewpage设置了适配器setViewPageAdapter,其中AdapterCycle适配器主要功能为轮播的图片在viewpage里面显示的时候让他们达到循环的效果。如何让它达到这种效果呢,就是让viewpage显示的页面比预期的页面多两个页面,从网上盗用一张图片来讲可能大家比较清楚![Center 4][] 就是说如果是在预期第一个页面继续向左滑动,那显示的是最后一个页面;如果是在预期的最后一个页面继续向右滑动的话,那显示的就是第一页面。也就是说真是viewpage比我们看到页面多两个页面。那两个页面分别是第一个和最后一个。不太明白的朋友可以自己看着图片琢磨一下。所以我们在viewpage的适配器里面要为传过来的图片加上前后加上一张图片。下面就是添加的代码。 public AdapterCycle(Context context, LinkedList<View> mOldViews) \{ if (mOldViews != null) \{ // 无论是否多于1个,都要初始化第一个(index:0) mViews = new LinkedList<View>(); final ImageView view = (ImageView) mOldViews.get(mOldViews .size() - 1); ImageView imageView = new ImageView(context); imageView.setImageDrawable(view.getDrawable()); mViews.add(imageView); // 注意,如果不只1个,mViews比mList多两个(头尾各多一个) // 假设:mList为mList\[0~N-1\], mViews为mViews\[0~N+1\] // mViews\[0\]放mList\[N-1\], mViews\[i\]放mList\[i-1\], // mViews\[N+1\]放mList\[0\] // mViews\[1~N\]用于循环;首位之前的mViews\[0\]和末尾之后的mViews\[N+1\]用于跳转 // 首位之前的mViews\[0\],跳转到末尾(N);末位之后的mViews\[N+1\],跳转到首位(1) if (mOldViews.size() > 1) \{ // 多于1个要循环 for (int i = 0; i < mOldViews.size(); i++) \{ // 中间的N个(index:1~N) final View view1 = mOldViews.get(i); mViews.add(view1); \} // 最后一个(index:N+1) final ImageView view2 = (ImageView) mOldViews.get(0); ImageView imageView1 = new ImageView(context); imageView.setImageDrawable(view2.getDrawable()); mViews.add(imageView1); \} \} \} 然后为view怕个添加OnPageChangeListener和OnTouchListener监听,设置当前显示的是第二个页面。然后开启定时轮播。 ![Center 5][] 轮播的时候判断当前是否是轮播到了第一个,如果是第一个,就把viewpage设置显示到倒数第二个,如果轮播到倒数第一个,就把viewpage设置显示到第二个。如果不是第一个和倒数第一个的话,就设置当前小点的显示位置。同样在viewpage的onpageSelected方法里面也是 ![Center 6][] 考虑到当滑动的时候就不能让他自定轮播,所以在onTouch里面分别设置isPlay是否可以自定播放。 ![Center 7][] 同时如果手动滑动完之后要让自定滑动不错乱,所以定义了两个字段分别用来标识当前执行的向左还是向右滑动。然后为pointIndex分别赋不同的值 其中判断right和left是通过定义一个ChangeViewCallback接口来切换当前是right还是left的状态。主要代码如下: ![Center 8][] 自定义的轮播图主要部分基本讲完,现在我们开始调用。在activity里面通过为自定义的轮播图viewsetviews来开启轮播。 package com.demo.shufflingpicture; import java.util.LinkedList; import android.app.Activity; import android.os.Bundle; import android.view.LayoutInflater; import android.view.View; import android.widget.ImageView; public class MainActivity extends Activity \{ private ShufflingPicture shufflingPicture; private LinkedList<View> views; private LayoutInflater mInflater; // 用于解XML private int\[\] strings = new int\[\] \{ R.drawable.image\_1, R.drawable.image\_2, R.drawable.image\_3, R.drawable.image\_4 , R.drawable.image\_5\}; @Override protected void onCreate(Bundle savedInstanceState) \{ super.onCreate(savedInstanceState); setContentView(R.layout.activity\_main); initView(); \} private void initView() \{ mInflater = LayoutInflater.from(this); views = new LinkedList<View>(); for(int i=0;i<strings.length;i++)\{ ImageView view = (ImageView) mInflater.inflate( R.layout.imageview, null); view.setImageResource(strings\[i\]); views.add(view); \} shufflingPicture = (ShufflingPicture) findViewById(R.id.shuffling\_picture); shufflingPicture.setViews(views); \} \} activity的布局文件如下:activity\_main.xml <RelativeLayout xmlns:android="http://schemas.android.com/apk/res/android" xmlns:tools="http://schemas.android.com/tools" xmlns:my="http://schemas.android.com/apk/res/com.demo.shufflingpicture" android:layout\_width="match\_parent" android:layout\_height="match\_parent" tools:context="com.demo.shufflingpicture.MainActivity" > <com.demo.shufflingpicture.ShufflingPicture android:id="@+id/shuffling\_picture" android:layout\_width="match\_parent" android:layout\_height="match\_parent" my:pointDrawbleNormal="@drawable/point\_normal" my:pointDrawbleSelect="@drawable/point\_select" android:layout\_gravity="center\_vertical|center\_horizontal"/> </RelativeLayout> 主要就是为自定义的属性添加图片。 到这里,我们自定义轮播图view已经讲完,看不太懂的朋友可以问我,谢谢大家, 源码的下载地址:http://download.csdn.net/detail/kai\_1215/8759761 [Center]: /images/20220805/2e365294217d4b84967b4b2ae1514743.png [Center 1]: /images/20220805/3ed68b4dd89b4e729f6ba03e3cabaa38.png [Center 2]: /images/20220805/cec61b0ba34549bb98e80ed7785eb6de.png [Image 1]: [Center 3]: /images/20220805/dfe7399a912a4b4092372db3536b18f1.png [Center 4]: /images/20220805/8ba4943a9d1747ecb2f2aa571eec7a5e.png [Center 5]: /images/20220805/a14a13cf8ec84b29a45127991514c06d.png [Center 6]: /images/20220805/2a3d4c6b54684a169deffc49ca9135c6.png [Center 7]: /images/20220805/c43f4345935741f7b2f2b8878f06adc7.png [Center 8]: /images/20220805/c3f32a2388bf4bd999847dd2e2c7cd99.png
相关 android自动循环轮播图,android 轮播图无限循环,自动播放 在Fragment中添加Handler: private static class BannerHandler extends Handler \{ @Override 深藏阁楼爱情的钟/ 2022年10月16日 03:58/ 0 赞/ 179 阅读
相关 循环轮播图 循环轮播图,想必大家都在很多app山看到过,但是具体怎么实现呢?今天小弟就跟大家一种通过组合自定义view来实现的方法。 先看一张效果图: ![Center][] 男娘i/ 2022年08月05日 02:24/ 0 赞/ 173 阅读
相关 顶部轮播图(自动循环滚动) 1.MainActivity: public class MainActivity extends Activity { private View 骑猪看日落/ 2022年08月01日 00:17/ 0 赞/ 193 阅读
相关 轮播图 ![这里写图片描述][SouthEast] > html页面 <!DOCTYPE html> <html> <head> 布满荆棘的人生/ 2022年06月05日 09:07/ 0 赞/ 355 阅读
相关 轮播图 <html> <head> <meta name="viewport" id="viewport" content="width=device- 布满荆棘的人生/ 2022年05月29日 03:47/ 0 赞/ 280 阅读
相关 轮播图 废话不多说,直接上代码 <!DOCTYPE html> <html> <head lang="en"> <meta charset=" 淩亂°似流年/ 2022年05月23日 09:38/ 0 赞/ 318 阅读
相关 轮播图 本文转载至菜鸟教程,仅做笔记之用,方便自己学习 [菜鸟链接][Link 1] <!DOCTYPE html> <html> <head> 秒速五厘米/ 2021年12月10日 05:57/ 0 赞/ 510 阅读
相关 轮播图 setInterval setInterval() 方法可按照指定的周期(以毫秒计)来调用函数或计算表达式。 给需要轮播的图片在js里声明一个变量 以数组的类型 在H 男娘i/ 2021年11月17日 06:32/ 0 赞/ 439 阅读
相关 轮播图 方案1 初始化插件: slides是一款基于jQuery无缝轮播图插件,支持图内元素动画,可以自定义动画类型 html代码 <div class="fullS 末蓝、/ 2021年06月10日 20:38/ 0 赞/ 657 阅读
还没有评论,来说两句吧...