android开发游记:自定义实现图片轮播器和启动页面滚动
来源:互联网 发布:mac百度云不好用 编辑:程序博客网 时间:2024/06/07 00:20
图片轮播器是一种交互很好的广告推送的组件,既完成了我们向用户推送信息的目的,同时形式还很优雅,在app中都有使用到,但是android的源生组件中并没有轮播器,这样我们就需要自定义来实现一个了。
先上效果图,分为自动滚动和手动滚动:
首先新建一个布局文件,添加以下代码:
<RelativeLayout xmlns:android="http://schemas.android.com/apk/res/android" android:layout_width="match_parent" android:layout_height="match_parent" > <android.support.v4.view.ViewPager android:id="@+id/viewPager" android:layout_width="match_parent" android:layout_height="match_parent" android:background="@color/white" /> <LinearLayout android:id="@+id/dotLayout" android:layout_width="match_parent" android:layout_height="wrap_content" android:layout_alignParentBottom="true" android:layout_marginBottom="20dp" android:gravity="center" android:orientation="horizontal" android:padding="8dp" > <View android:id="@+id/v_dot1" android:layout_width="8dp" android:layout_height="8dp" android:background="@drawable/shape_oval_dot_orage" /> <View android:id="@+id/v_dot2" android:layout_width="8dp" android:layout_height="8dp" android:layout_marginLeft="25dp" android:background="@drawable/shape_oval_dot_dark" /> </LinearLayout></RelativeLayout>
轮播器内部其实也是使用了viewPager,首先自定义一个PagerAdapter来初始化每页的View,其实每页只有一个ImageView:
/** * 填充ViewPager的页面适配器 * */ private class MyPagerAdapter extends PagerAdapter{ @Override public void destroyItem(View container, int position, Object object) { // TODO Auto-generated method stub //((ViewPag.er)container).removeView((View)object); ((ViewPager)container).removeView(imageViewsList.get(position)); } @Override public Object instantiateItem(ViewGroup container, int position) { ImageView imageView = imageViewsList.get(position); if (!StringUtil.isEmpty(imageUrls)) { if (imageUrls[0].contains("http")) { bitmapUtils.display(imageView, imageView.getTag().toString()); }else { imageView.setImageResource(Integer.parseInt(imageUrls[position])); } } imageView.setBackgroundResource(R.color.white); container.addView(imageView); return imageView; } @Override public int getCount() { // TODO Auto-generated method stub return imageViewsList.size(); }}
在instantiateItem中初始化这个ImageView并返回,这里我做了一些业务处理上的处理,我定义了2中传入图片的方式,如果请求到了一组图片就存放url,如果失败了那么现实默认的本地图片(以Resource方式存放),图片的集合存放的是URL还是Resource。不需要这样处理可以把这里的代码删掉就可以了。
然后给ViewPager设置一个监听器,监听到翻页事件:
private class MyPageChangeListener implements OnPageChangeListener{ boolean isAutoPlay = false; @Override public void onPageScrollStateChanged(int arg0) { // TODO Auto-generated method stub switch (arg0) { case 1:// 手势滑动,空闲中 isAutoPlay = false; break; case 2:// 界面切换中 isAutoPlay = true; break; case 0:// 滑动结束,即切换完毕或者加载完毕 if (isAutoPlay) { // 当前为最后一张,此时从右向左滑,则切换到第一张 if (viewPager.getCurrentItem() == viewPager.getAdapter().getCount() - 1 && !isAutoPlay) { viewPager.setCurrentItem(0); } // 当前为第一张,此时从左向右滑,则切换到最后一张 else if (viewPager.getCurrentItem() == 0 && !isAutoPlay) { viewPager.setCurrentItem(viewPager.getAdapter().getCount() - 1); } } break; } } @Override public void onPageScrolled(int arg0, float arg1, int arg2) { // TODO Auto-generated method stub } @Override public void onPageSelected(int pos) { // TODO Auto-generated method stub currentItem = pos; for(int i=0;i < dotViewsList.size();i++){ if(i == pos){ ((View)dotViewsList.get(pos)).setBackgroundResource(R.drawable.shape_oval_dot_orage); }else { ((View)dotViewsList.get(i)).setBackgroundResource(R.drawable.shape_oval_dot_dark); } } } }
在onPageScrollStateChanged方法中处理最后一张图片和第一张图片的特殊情况:
- 如果在第一张图片的位置往前翻页则跳到最后一页。
- 如果在最后一张图片往后翻页则跳到第一页
在onPageSelected方法中处理悬浮的小点点的热点效果,把当前页对应的小点点设置为热点显示高亮状态
定义一个initUI方法,在请求到图片之后调用以初始化控件:
/** * 初始化Views等UI */ private void initUI(Context context){ if(imageUrls == null || imageUrls.length == 0) return; LayoutInflater.from(context).inflate(R.layout.layout_slideshow, this, true); LinearLayout dotLayout = (LinearLayout)findViewById(R.id.dotLayout); dotLayout.removeAllViews(); // 热点个数与图片特殊相等 for (int i = 0; i < imageUrls.length; i++) { ImageView view = new ImageView(context); view.setTag(imageUrls[i]); view.setLayoutParams(new LayoutParams(LayoutParams.MATCH_PARENT, LayoutParams.MATCH_PARENT)); imageViewsList.add(view); ImageView dotView = new ImageView(context); LinearLayout.LayoutParams params = new LinearLayout.LayoutParams(LayoutParams.WRAP_CONTENT,LayoutParams.WRAP_CONTENT); params.leftMargin = 15; params.rightMargin = 15; dotLayout.addView(dotView, params); dotViewsList.add(dotView); } /////////首次进入的时候初始化点点 for(int i=0;i < dotViewsList.size();i++){ if(i == 0){ ((View)dotViewsList.get(0)).setBackgroundResource(R.drawable.shape_oval_dot_orage); }else { ((View)dotViewsList.get(i)).setBackgroundResource(R.drawable.shape_oval_dot_dark); } } ////////////////////////// if (imageViewsList.size()>0 && goListener!=null) { imageViewsList.get(imageViewsList.size()-1).setOnClickListener(goListener); } viewPager = (ViewPager) findViewById(R.id.viewPager); viewPager.setFocusable(true); viewPager.setAdapter(new MyPagerAdapter()); viewPager.setOnPageChangeListener(new MyPageChangeListener()); }
initUI方法中初始化了Viewpager也设置了Adapter,那么只要在获取到图片数据之后调用该方法就OK了
定义一个后台异步任务,用于从服务器获取图片集合,获取完成后调用initUI()方法:
/** * 异步任务,获取数据 * */ class GetListTask extends AsyncTask<String, Integer, Boolean> { @Override protected Boolean doInBackground(String... params) { try { // 这里一般调用服务端接口获取一组轮播图片,下面是从百度找的几个图片 imageUrls = new String[]{ "http://image.zcool.com.cn/59/54/m_1303967870670.jpg", "http://image.zcool.com.cn/47/19/1280115949992.jpg", "http://image.zcool.com.cn/59/11/m_1303967844788.jpg" }; return true; } catch (Exception e) { e.printStackTrace(); return false; } } @Override protected void onPostExecute(Boolean result) { super.onPostExecute(result); if (result) { initUI(context); } } }
这里就模拟了,写一组静态图片,需要请求服务器图片的在这里请求
然后再添加自动播放的功能,在初始化的时候创建一个异步任务,每隔一段时间,进行一次发生一个handler消息,handler接收到消息后进行翻页:
/** * 开始轮播图切换 */ private void startPlay(){ scheduledExecutorService = Executors.newSingleThreadScheduledExecutor(); scheduledExecutorService.scheduleAtFixedRate(new SlideShowTask(), 4, 4, TimeUnit.SECONDS); } /** *执行轮播图切换任务 * */ private class SlideShowTask implements Runnable{ @Override public void run() { // TODO Auto-generated method stub synchronized (viewPager) { currentItem = (currentItem+1)%imageViewsList.size(); handler.obtainMessage().sendToTarget(); } } } //Handler private Handler handler = new Handler(){ @Override public void handleMessage(Message msg) { super.handleMessage(msg); viewPager.setCurrentItem(currentItem); } };
然后设置一个标志位来决定是否需要自动轮播或者手动翻页,
需要手动翻页就调用startPlay(),不需要就跳过:
if(isAutoPlay){ startPlay();}
这样功能基本就完了,下面贴上完整代码:
/** * ViewPager实现的轮播图广告自定义视图,如京东首页的广告轮播图效果; * 既支持自动轮播页面也支持手势滑动切换页面 * * */public class SlideShowView extends FrameLayout { // 使用universal-image-loader插件读取网络图片,需要工程导入universal-image-loader-1.8.6-with-sources.jar// private ImageLoader imageLoader = ImageLoader.getInstance(); private BitmapUtils bitmapUtils; //轮播图图片数量 private final static int IMAGE_COUNT = 4; //自动轮播的时间间隔 private final static int TIME_INTERVAL = 5; //自动轮播启用开关 private final static boolean isAutoPlay = false; //跳转监听器 private OnClickListener goListener; //自定义轮播图的资源 private String[] imageUrls;// private int[] imageSrcs; //放轮播图片的ImageView 的list private List<ImageView> imageViewsList; //放圆点的View的list private List<View> dotViewsList; private ViewPager viewPager; //当前轮播页 private int currentItem = 0; //定时任务 private ScheduledExecutorService scheduledExecutorService; private Context context; //Handler private Handler handler = new Handler(){ @Override public void handleMessage(Message msg) { super.handleMessage(msg); viewPager.setCurrentItem(currentItem); } }; public SlideShowView(Context context) { this(context,null); } public SlideShowView(Context context, AttributeSet attrs) { this(context, attrs, 0); } public SlideShowView(Context context, AttributeSet attrs, int defStyle) { super(context, attrs, defStyle); if (!isInEditMode()) { this.context = context; this.bitmapUtils = BitmapHelp.getBitmapUtils(); this.bitmapUtils.configDefaultLoadingImage(R.drawable.none); this.bitmapUtils.configDefaultLoadFailedImage(R.drawable.none); initData(); // 一步任务获取图片 new GetListTask().execute(""); if(isAutoPlay){ startPlay(); } } } /** * 开始轮播图切换 */ private void startPlay(){ scheduledExecutorService = Executors.newSingleThreadScheduledExecutor(); scheduledExecutorService.scheduleAtFixedRate(new SlideShowTask(), 4, 4, TimeUnit.SECONDS); } /** * 停止轮播图切换 */ private void stopPlay(){ scheduledExecutorService.shutdown(); } /** * 初始化相关Data */ private void initData(){ imageViewsList = new ArrayList<ImageView>(); dotViewsList = new ArrayList<View>(); } /** * 初始化Views等UI */ private void initUI(Context context){ if(imageUrls == null || imageUrls.length == 0) return; LayoutInflater.from(context).inflate(R.layout.layout_slideshow, this, true); LinearLayout dotLayout = (LinearLayout)findViewById(R.id.dotLayout); dotLayout.removeAllViews(); // 热点个数与图片特殊相等 for (int i = 0; i < imageUrls.length; i++) { ImageView view = new ImageView(context); view.setTag(imageUrls[i]);// if(i==0)//给一个默认图// view.setBackgroundResource(R.drawable.defalt); view.setLayoutParams(new LayoutParams(LayoutParams.MATCH_PARENT, LayoutParams.MATCH_PARENT));// view.setScaleType(ScaleType.FIT_START); imageViewsList.add(view); ImageView dotView = new ImageView(context); LinearLayout.LayoutParams params = new LinearLayout.LayoutParams(LayoutParams.WRAP_CONTENT,LayoutParams.WRAP_CONTENT); params.leftMargin = 15; params.rightMargin = 15; dotLayout.addView(dotView, params); dotViewsList.add(dotView); } /////////首次进入的时候初始化点点 for(int i=0;i < dotViewsList.size();i++){ if(i == 0){ ((View)dotViewsList.get(0)).setBackgroundResource(R.drawable.shape_oval_dot_orage); }else { ((View)dotViewsList.get(i)).setBackgroundResource(R.drawable.shape_oval_dot_dark); } } ////////////////////////// if (imageViewsList.size()>0 && goListener!=null) { imageViewsList.get(imageViewsList.size()-1).setOnClickListener(goListener); } viewPager = (ViewPager) findViewById(R.id.viewPager); viewPager.setFocusable(true); viewPager.setAdapter(new MyPagerAdapter()); viewPager.setOnPageChangeListener(new MyPageChangeListener()); } public void setOnGolistener(OnClickListener goListener) { this.goListener = goListener; } /** * 填充ViewPager的页面适配器 * */ private class MyPagerAdapter extends PagerAdapter{ @Override public void destroyItem(View container, int position, Object object) { // TODO Auto-generated method stub //((ViewPag.er)container).removeView((View)object); ((ViewPager)container).removeView(imageViewsList.get(position)); } @Override public Object instantiateItem(ViewGroup container, int position) { ImageView imageView = imageViewsList.get(position); if (!StringUtil.isEmpty(imageUrls)) { if (imageUrls[0].contains("http")) { bitmapUtils.display(imageView, imageView.getTag().toString()); }else { imageView.setImageResource(Integer.parseInt(imageUrls[position])); } } imageView.setBackgroundResource(R.color.white); container.addView(imageView); return imageView; } @Override public int getCount() { // TODO Auto-generated method stub return imageViewsList.size(); } @Override public boolean isViewFromObject(View arg0, Object arg1) { // TODO Auto-generated method stub return arg0 == arg1; } @Override public void restoreState(Parcelable arg0, ClassLoader arg1) { // TODO Auto-generated method stub } @Override public Parcelable saveState() { // TODO Auto-generated method stub return null; } @Override public void startUpdate(View arg0) { // TODO Auto-generated method stub } @Override public void finishUpdate(View arg0) { // TODO Auto-generated method stub } } /** * ViewPager的监听器 * 当ViewPager中页面的状态发生改变时调用 * */ private class MyPageChangeListener implements OnPageChangeListener{ boolean isAutoPlay = false; @Override public void onPageScrollStateChanged(int arg0) { // TODO Auto-generated method stub switch (arg0) { case 1:// 手势滑动,空闲中 isAutoPlay = false; break; case 2:// 界面切换中 isAutoPlay = true; break; case 0:// 滑动结束,即切换完毕或者加载完毕 if (isAutoPlay) { // 当前为最后一张,此时从右向左滑,则切换到第一张 if (viewPager.getCurrentItem() == viewPager.getAdapter().getCount() - 1 && !isAutoPlay) { viewPager.setCurrentItem(0); } // 当前为第一张,此时从左向右滑,则切换到最后一张 else if (viewPager.getCurrentItem() == 0 && !isAutoPlay) { viewPager.setCurrentItem(viewPager.getAdapter().getCount() - 1); } } break; } } @Override public void onPageScrolled(int arg0, float arg1, int arg2) { // TODO Auto-generated method stub } @Override public void onPageSelected(int pos) { // TODO Auto-generated method stub currentItem = pos; for(int i=0;i < dotViewsList.size();i++){ if(i == pos){ ((View)dotViewsList.get(pos)).setBackgroundResource(R.drawable.shape_oval_dot_orage); }else { ((View)dotViewsList.get(i)).setBackgroundResource(R.drawable.shape_oval_dot_dark); } } } } /** *执行轮播图切换任务 * */ private class SlideShowTask implements Runnable{ @Override public void run() { // TODO Auto-generated method stub synchronized (viewPager) { currentItem = (currentItem+1)%imageViewsList.size(); handler.obtainMessage().sendToTarget(); } } } /** * 销毁ImageView资源,回收内存 * */ private void destoryBitmaps() { for (int i = 0; i < IMAGE_COUNT; i++) { ImageView imageView = imageViewsList.get(i); Drawable drawable = imageView.getDrawable(); if (drawable != null) { //解除drawable对view的引用 drawable.setCallback(null); } } } /** * 释放资源,在activity结束时请调用 */ public void destory() { stopPlay(); destoryBitmaps(); } public void setImageSrcs(int[] imageSrcs) { if (StringUtil.isEmpty(imageSrcs)) { return; } imageUrls = new String[imageSrcs.length]; for (int i = 0; i < imageSrcs.length; i++) { imageUrls[i] = imageSrcs[i]+""; } } public void setImageUrls(String[] imageUrls) { this.imageUrls = imageUrls; } /** * 异步任务,获取数据 * */ class GetListTask extends AsyncTask<String, Integer, Boolean> { @Override protected Boolean doInBackground(String... params) { try { // 这里一般调用服务端接口获取一组轮播图片,下面是从百度找的几个图片 imageUrls = new String[]{ "http://image.zcool.com.cn/59/54/m_1303967870670.jpg", "http://image.zcool.com.cn/47/19/1280115949992.jpg", "http://image.zcool.com.cn/59/11/m_1303967844788.jpg" }; return true; } catch (Exception e) { e.printStackTrace(); return false; } } @Override protected void onPostExecute(Boolean result) { super.onPostExecute(result); if (result) { initUI(context); } } }}
- android开发游记:自定义实现图片轮播器和启动页面滚动
- android开发游记:自定义图片裁剪组件
- android开发游记:viewpager关联tabs,自定义tabs实现翻页滚动效果
- android开发游记:酷炫的启动页面之如何实现两个ViewPager的联动
- Android自定义控件, 实现图片无限滚动
- android开发游记:仿支付宝余额数字累加滚动效果的实现
- android开发游记:仿支付宝余额数字累加滚动效果的实现
- android开发游记:仿支付宝余额数字累加滚动效果的实现
- Android开发技巧 图片滚动效果实现
- android开发游记:广告轮播器无限循环滚动 首尾无缝切换解决方案
- android开发游记:广告轮播器无限循环滚动 首尾无缝切换解决方案
- android自定义Gallery实现手动和自动循环滚动切换图片
- android自定义Gallery实现手动和自动循环滚动切换图片
- 页面实现图片滚动效果
- Android 自定义 HorizontalScrollView 实现图片左右滚动按钮控制
- Android 实现滚动图片
- android开发游记:textview超过长度点击展开自动滚动(在一个TextView中实现,不增加布局复杂度)
- android开发游记:textview超过长度点击展开自动滚动(在一个TextView中实现,不增加布局复杂度)
- 三星Galaxy Note5职场轻态度 对职场人士“减负”的启示
- Git的一些命令
- android底层开发入门(2)-git与repo
- 二叉树的实现
- PowerDesigner中导入MYSQL数据库结构的步骤
- android开发游记:自定义实现图片轮播器和启动页面滚动
- Android消息通信之无所不能的第三方开源项目EventBus
- 技能学习过程
- 多个文件预览
- json错误信息记录
- swift开发笔记14 - 解析json数据文件
- 欢迎使用CSDN-markdown编辑器
- 解决把listview放在ScrollView只显示一行的问题
- 开发第四天