最近软件开发要做一个本地图片轮播的功能,主要实现一下功能:
(1)每隔特定时间(本例是4秒)自动展示一张新的图片;
(2)可以进行手势滑动(滑动过程中暂停自动播放计时);
(3)可以轮转显示,播放到最后一张或者滑动到最后一张,跳转到第一张。
效果图如下:
该项目demo源码的下载地址:
Android之本地图片轮播.zip
下面开始代码实现:
首先是主界面布局activity_main.xml(注:其中slideshowView我用了addView的方法添加进去,这里就不需要它的布局了,
而之后的slideshowView中的ChildViewPager我在布局文件里添加了。其实两种方法都一样的效果,看个人喜好。):
<?xml version="1.0" encoding="utf-8"?>
<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=".MainActivity">
<TextView
android:id="@+id/tv"
android:layout_width="fill_parent"
android:layout_height="60dp"
android:background="#05de38"
android:gravity="center"
android:text="本地图片轮播"
android:textColor="#ffffff"
android:textSize="23sp" />
<RelativeLayout
android:paddingTop="40dp"
android:paddingLeft="5dp"
android:paddingRight="5dp"
android:id="@+id/relativeLayout"
android:layout_below="@id/tv"
android:layout_width="fill_parent"
android:layout_height="300dp">
<!-- <SlideShowView
android:id="@+id/slideshowView"
android:layout_width="fill_parent"
android:layout_height="200dp"
android:layout_centerHorizontal="true"
/>-->
</RelativeLayout>
</RelativeLayout>
slideshowView的布局layout_slideshow.xml :
<?xml version="1.0" encoding="utf-8"?>
<RelativeLayout
xmlns:android="http://schemas.android.com/apk/res/android"
android:layout_width="match_parent"
android:layout_height="match_parent"
>
<com.android.imagecarousel.ChildViewPager
android:id="@+id/viewPager"
android:layout_width="match_parent"
android:layout_height="match_parent" />
<LinearLayout android:id="@+id/dotLayout"
android:layout_width="fill_parent"
android:layout_height="wrap_content"
android:layout_alignParentBottom="true"
android:padding="8dp"
android:gravity="right"
android:orientation="horizontal">
<View
android:id="@+id/v_dot1"
android:layout_width="5dp"
android:layout_height="5dp"
android:background="@drawable/dotshape" />
<View
android:id="@+id/v_dot2"
android:layout_width="5dp"
android:layout_height="5dp"
android:layout_marginLeft="5dp"
android:background="@drawable/dotshape2" />
<View
android:id="@+id/v_dot3"
android:layout_width="5dp"
android:layout_height="5dp"
android:layout_marginLeft="5dp"
android:background="@drawable/dotshape2" />
<View
android:id="@+id/v_dot4"
android:layout_width="5dp"
android:layout_height="5dp"
android:layout_marginLeft="5dp"
android:background="@drawable/dotshape2" />
</LinearLayout>
</RelativeLayout>
其中右下角的红点dotshape.xml :
<?xml version="1.0" encoding="utf-8"?>
<shape
xmlns:android="http://schemas.android.com/apk/res/android"
android:shape="oval"
android:useLevel="false">
<solid android:color="@color/red"/>
<stroke
android:width="1dp"
android:color="@color/red"/>
<size android:width="20dp"
android:height="20dp"/>
</shape>
其中右下角的白点dotshape2.xml :
<?xml version="1.0" encoding="utf-8"?>
<shape
xmlns:android="http://schemas.android.com/apk/res/android"
android:shape="oval"
android:useLevel="false">
<solid android:color="@color/white"/>
<stroke
android:width="1dp"
android:color="@color/white"/>
<size android:width="20dp"
android:height="20dp"/>
</shape>
主界面Java代码MainActivity.java :
package com.android.imagecarousel;
import android.app.Activity;
import android.support.v7.app.AppCompatActivity;
import android.os.Bundle;
import android.widget.RelativeLayout;
public class MainActivity extends Activity {
@Override
protected void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
setContentView(R.layout.activity_main);
//添加SlideShowView
RelativeLayout relativeLayout = (RelativeLayout) findViewById(R.id.relativeLayout);
SlideShowView slideShowView = new SlideShowView(this);
RelativeLayout.LayoutParams params1 = new RelativeLayout.LayoutParams(
RelativeLayout.LayoutParams.WRAP_CONTENT, RelativeLayout.LayoutParams.WRAP_CONTENT);
slideShowView.setLayoutParams(params1);
relativeLayout.addView(slideShowView);
}
}
自定义SlideShowView.java:
package com.android.imagecarousel;
import android.content.Context;
import android.os.Handler;
import android.os.Message;
import android.util.AttributeSet;
import android.view.LayoutInflater;
import android.view.View;
import android.widget.FrameLayout;
import android.widget.ImageView;
import android.support.v4.view.ViewPager;
import android.support.v4.view.ViewPager.OnPageChangeListener;
import java.lang.ref.WeakReference;
import java.util.ArrayList;
import java.util.List;
/**
* ViewPager实现的轮播图广告自定义视图,既支持自动轮播页面也支持手势滑动切换页面
*/
public class SlideShowView extends FrameLayout {
//自定义轮播图的资源ID
private int[] imagesResIds;
//存放轮播图片的ImageView的list
private List<ImageView> imageViewsList;
//放圆点的View的list
private List<View> dotViewsList;
//轮播图片的viewpager
private ViewPager viewPager;
//当前轮播页
private int currentItem ;
private ImageHandler handler = new ImageHandler(new WeakReference<SlideShowView>(this));
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);
initData();
initUI(context);
}
/**
* 初始化相关Data
*/
private void initData() {
//本地的四张广告图片
imagesResIds = new int[]{
R.drawable.ad1,
R.drawable.ad2,
R.drawable.ad3,
R.drawable.ad4,
};
imageViewsList = new ArrayList<ImageView>();
dotViewsList = new ArrayList<View>();
}
/**
* 初始化Views等UI
*/
private void initUI(Context context) {
LayoutInflater.from(context).inflate(R.layout.layout_slideshow, this, true);
for (int imageID : imagesResIds) {
ImageView view = new ImageView(context);
view.setImageResource(imageID);
view.setScaleType(ImageView.ScaleType.FIT_XY);
imageViewsList.add(view);
}
//轮播图片视图右下角的四个点
dotViewsList.add(findViewById(R.id.v_dot1));
dotViewsList.add(findViewById(R.id.v_dot2));
dotViewsList.add(findViewById(R.id.v_dot3));
dotViewsList.add(findViewById(R.id.v_dot4));
viewPager = (ViewPager) findViewById(R.id.viewPager);
viewPager.setFocusable(true);
//设置适配器
viewPager.setAdapter(new SlideShowPagerAdapter(imageViewsList));
//设置页面改变监听事件
viewPager.setOnPageChangeListener(new MyPageChangeListener());
viewPager.setCurrentItem(0);
//开始轮播效果
handler.sendEmptyMessageDelayed(ImageHandler.MSG_UPDATE_IMAGE, ImageHandler.MSG_DELAY);
}
/**
* ViewPager的监听器 ,当ViewPager中页面的状态发生改变时调用
*/
private class MyPageChangeListener implements OnPageChangeListener {
boolean isAutoPlay = false;
@Override
public void onPageScrollStateChanged(int arg0) {
switch (arg0) {
case ViewPager.SCROLL_STATE_DRAGGING:
isAutoPlay = false;
handler.sendEmptyMessage(ImageHandler.MSG_PAUSE_CAROUSEL);
break;
case ViewPager.SCROLL_STATE_IDLE:
// 当前为最后一张,此时从右向左滑,则切换到第一张
if (viewPager.getCurrentItem() == viewPager.getAdapter().getCount() - 1 && !isAutoPlay) {
viewPager.setCurrentItem(0);
}
// 当前为第一张,此时从左向右滑,则切换到最后一张
else if (viewPager.getCurrentItem() == 0 && !isAutoPlay) {
viewPager.setCurrentItem(viewPager.getAdapter().getCount() - 1 );
}
handler.sendEmptyMessageDelayed(ImageHandler.MSG_UPDATE_IMAGE, ImageHandler.MSG_DELAY);
break;
default:
isAutoPlay = true;
break;
}
}
@Override
public void onPageScrolled(int arg0, float arg1, int arg2) {
// TODO Auto-generated method stub
}
@Override
public void onPageSelected(int pos) {
handler.sendMessage(Message.obtain(handler, ImageHandler.MSG_PAGE_CHANGED, pos, 0));
currentItem = pos;
for (int i = 0; i < dotViewsList.size(); i++) {
if (i == pos) {
((View) dotViewsList.get(pos)).setBackgroundResource(R.drawable.dotshape);
} else {
((View) dotViewsList.get(i)).setBackgroundResource(R.drawable.dotshape2);
}
}
}
}
//Handler
private static class ImageHandler extends Handler{
//请求更新显示的View
protected static final int MSG_UPDATE_IMAGE = 1 ;
//暂停轮播
protected static final int MSG_PAUSE_CAROUSEL = 2 ;
//恢复轮播
protected static final int MSG_REGAIN_CAROUSEL = 3 ;
//当手动滑动时,记录新页号
protected static final int MSG_PAGE_CHANGED = 4;
//轮播间隔时间4秒
protected static final long MSG_DELAY = 4000;
//使用弱引用避免Handler泄露.
private WeakReference<SlideShowView> weakReference;
private int currentItem = 0;
protected ImageHandler(WeakReference<SlideShowView> wk){
weakReference = wk;
}
@Override
public void handleMessage(Message msg) {
super.handleMessage(msg);
SlideShowView slideShowView = weakReference.get();
if (slideShowView == null){
return ;
}
//检查消息队列并移除未发送的消息,避免消息出现重复
if (slideShowView.handler.hasMessages(MSG_UPDATE_IMAGE)){
slideShowView.handler.removeMessages(MSG_UPDATE_IMAGE);
}
switch (msg.what) {
case MSG_UPDATE_IMAGE:
currentItem++;
slideShowView.viewPager.setCurrentItem(currentItem);
//准备下次播放
slideShowView.handler.sendEmptyMessageDelayed(MSG_UPDATE_IMAGE, MSG_DELAY);
break;
case MSG_REGAIN_CAROUSEL:
slideShowView.handler.sendEmptyMessageDelayed(MSG_UPDATE_IMAGE, MSG_DELAY);
break;
case MSG_PAGE_CHANGED:
//记录当前的页号,避免播放的时候页面显示不正确。
currentItem = msg.arg1;
//若为最后一张,则从头开始
if(currentItem == 3){
currentItem = -1 ;
}
break;
case MSG_PAUSE_CAROUSEL:
slideShowView.handler.sendEmptyMessageDelayed(MSG_UPDATE_IMAGE, MSG_DELAY);
break;
default:
break;
}
}
}
}
用于显示图片的ViewPager,ChildViewPager.java:
package com.android.imagecarousel;
import android.content.Context;
import android.graphics.PointF;
import android.support.v4.view.ViewPager;
import android.util.AttributeSet;
import android.view.MotionEvent;
public class ChildViewPager extends ViewPager {
//触摸时按下的点
PointF downP = new PointF();
//触摸时当前的点
PointF curP = new PointF();
OnSingleTouchListener onSingleTouchListener;
public ChildViewPager(Context context, AttributeSet attrs) {
super(context, attrs);
// TODO Auto-generated constructor stub
}
public ChildViewPager(Context context) {
super(context);
// TODO Auto-generated constructor stub
}
@Override
public boolean onInterceptTouchEvent(MotionEvent arg0) {
// TODO Auto-generated method stub
//当拦截触摸事件到达此位置的时候,返回true,
//说明将onTouch拦截在此控件,进而执行此控件的onTouchEvent
return true;
}
@Override
public boolean onTouchEvent(MotionEvent arg0) {
// TODO Auto-generated method stub
//每次进行onTouch事件都记录当前的按下的坐标
curP.x = arg0.getX();
curP.y = arg0.getY();
if(arg0.getAction() == MotionEvent.ACTION_DOWN){
//记录按下时候的坐标
downP.x = arg0.getX();
downP.y = arg0.getY();
//通知父ViewPager现在进行的是本控件的操作,不要对此操作进行干扰
getParent().requestDisallowInterceptTouchEvent(true);
}
if(arg0.getAction() == MotionEvent.ACTION_MOVE){
//通知父ViewPager现在进行的是本控件的操作,不要对此操作进行干扰
getParent().requestDisallowInterceptTouchEvent(true);
}
if(arg0.getAction() == MotionEvent.ACTION_UP){
//在up时判断是否按下和松手的坐标为一个点,如果是一个点,将执行点击事件
if(downP.x==curP.x && downP.y==curP.y){
onSingleTouch();
return true;
}
}
return super.onTouchEvent(arg0);
}
/**
* 单击
*/
public void onSingleTouch() {
if (onSingleTouchListener!= null) {
onSingleTouchListener.onSingleTouch();
}
}
/**
* 创建点击事件接口
*/
public interface OnSingleTouchListener {
void onSingleTouch();
}
}
viewPager适配器,SlideShowPagerAdapter.java :
package com.android.imagecarousel;
import android.os.Parcelable;
import android.support.v4.view.PagerAdapter;
import android.support.v4.view.ViewPager;
import android.view.View;
import android.widget.ImageView;
import java.util.List;
/**
* 显示广告图片的viewPager适配器
*/
public class SlideShowPagerAdapter extends PagerAdapter {
//放轮播图片的ImageView 的list
public List<ImageView> imageViewsList;
public SlideShowPagerAdapter(List<ImageView> imageViewsList) {
this.imageViewsList = imageViewsList;
}
@Override
public void destroyItem(View container, int position, Object object) {
((ViewPager)container).removeView(imageViewsList.get(position));
}
@Override
public Object instantiateItem(View container, int position) {
((ViewPager)container).addView(imageViewsList.get(position));
return imageViewsList.get(position);
}
@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;
}
}
在开发过程中,我参考了这个
http://www.it165.net/pro/html/201406/16227.html ,但手势滑动时自动轮播还在计时,会出现闪变的状况,而且定时任务中使用了TimeUnit.SECONDS,时间不能很好的进行控制和调整。然后又参考了http://blog.csdn.net/dyllove98/article/details/41013883进行了修改和调整。在此感谢两位前辈的博文。
该项目demo源码的下载地址:
Android之本地图片轮播.zip