目前很多APP中都有这个图片轮播的功能,项目中也时常会用到,图片轮播一般是在用户不主动进行切换的时候每隔一段时间进行自动切换,用户主动切换时停止自动切换,手指离开时重新计时开始轮播,下面我们就来实现这个功能,功能效果图如下:
实现原理:
- Handler.sendEmptyMessageDelayed(what, DELAYTIME);来进行自动轮播;
- 监听onTouch事件监听来控制开启和停止轮播;
- ImageLoader来加载网络图片显示;
1.在activity_main.xml中添加控件
<RelativeLayout xmlns:android="http://schemas.android.com/apk/res/android"
xmlns:tools="http://schemas.android.com/tools"
xmlns:CircleIndicator="http://schemas.android.com/apk/res-auto"
android:layout_width="match_parent"
android:layout_height="match_parent"
tools:context="${relativePackage}.${activityClass}" >
<RelativeLayout
android:layout_width="match_parent"
android:layout_height="180dp" >
<android.support.v4.view.ViewPager
android:id="@+id/banner_pager"
android:layout_width="wrap_content"
android:layout_height="match_parent" >
</android.support.v4.view.ViewPager>
<!-- 指示器 -->
<LinearLayout
android:id="@+id/banner_pointer_group"
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:layout_alignParentBottom="true"
android:layout_centerHorizontal="true"
android:layout_marginBottom="10dp"
android:orientation="horizontal" >
</LinearLayout>
</RelativeLayout>
</RelativeLayout>
2.新建实体类BannerEntity
public class BannerEntity implements Serializable
{
private static final long serialVersionUID = 3250428319336562246L;
private int id;
private String img;
private String url;
private String jumps;
public int getId()
{
return id;
}
public void setId(int id)
{
this.id = id;
}
public String getImg() {
return img;
}
public void setImg(String img) {
this.img = img;
}
public String getUrl() {
return url;
}
public void setUrl(String url) {
this.url = url;
}
public String getJumps() {
return jumps;
}
public void setJumps(String jumps) {
this.jumps = jumps;
}
@Override
public int hashCode() {
final int prime = 31;
int result = 1;
result = prime * result + id;
return result;
}
@Override
public boolean equals(Object obj) {
if (this == obj)
return true;
if (obj == null)
return false;
if (getClass() != obj.getClass())
return false;
BannerEntity other = (BannerEntity) obj;
if (id != other.id)
return false;
return true;
}
@Override
public String toString()
{
return "BannerEntity [img=" + img + ", id=" + id + ", url=" + url + ",jumps="+jumps + "]";
}
}
3.构建自己的PagerAdaper
代码中注释比较详细,有问题欢迎交流讨论。
public class AdatperBanner extends PagerAdapter implements ImageLoadingListener, OnPageChangeListener
{
/**
* 切换间隔时间
*/
private static final long DELAYTIME = 3000;
private static final int MSG_NEXT = 1;
/**
* 默认banner个数
*/
private static final int DEFAULT_COUNT = 1;
/**
* 无数据时默认指定一条数据
*/
private BannerEntity defaultBanner;
private Context context;
/**
* page切换时的监听
*/
private OnPageListener pageListener;
/**
* 数据源
*/
private List<BannerEntity> data = new ArrayList<BannerEntity>();
private ViewPager pager;
private Handler postHandler = new Handler()
{
public void handleMessage(android.os.Message msg)
{
if (pager != null)
{
int curPage = pager.getCurrentItem();
if (curPage == (getCount() - 1))
pager.setCurrentItem(0);
else
pager.setCurrentItem(++curPage);
}
cancelDelayPlay();
postHandler.sendEmptyMessageDelayed(MSG_NEXT, DELAYTIME);
};
};
public AdatperBanner(ViewPager pager)
{
this.pager = pager;
pager.setOnPageChangeListener(this);
defaultBanner = new BannerEntity();
}
public AdatperBanner(ViewPager pager, OnPageListener listener, Context context)
{
this(pager);
pageListener = listener;
this.context = context;
}
/**
* <添加数据,并刷新界面>
* @param data
* @see [类、类#方法、类#成员]
*/
public void setDataSource(List<BannerEntity> data)
{
this.data.clear();
if (data != null && !data.isEmpty())
this.data.addAll(data);
checkData();
notifyDataSetChanged();
pager.setCurrentItem(1);
startDelayPlay();
}
public void setDataSource(BannerEntity data)
{
if (data == null)
return;
this.data.clear();
this.data.add(data);
checkData();
notifyDataSetChanged();
}
/**
* 校验数据
* 备注:数据至少一个,如果数据源空,这里需要填补默认数据
*/
private void checkData()
{
if (data.isEmpty())
data.add(defaultBanner);
}
/**
* 开始自动切换
* @see [类、类#方法、类#成员]
*/
public void startDelayPlay()
{
//如果数据只有一个或者数据为null,跳出方法
if (data == null || data.size() < 2)
return;
cancelDelayPlay();
postHandler.sendEmptyMessageDelayed(MSG_NEXT, DELAYTIME);
}
/**
* 撤销自动切换
* @see [类、类#方法、类#成员]
*/
public void cancelDelayPlay()
{
if (postHandler != null)
postHandler.removeCallbacksAndMessages(null);
}
/**
* 重写getItemPosition()方法,当调用notifyDataSetChanged时,让getItemPosition方法人为的返回POSITION_NONE,从而达到强迫viewpager重绘所有item的目的。
* @see android.support.v4.view.PagerAdapter#getItemPosition(java.lang.Object)
*/
@Override
public int getItemPosition(Object object)
{
return PagerAdapter.POSITION_NONE;
}
@Override
public int getCount()
{
return ((data == null || data.isEmpty()) ? DEFAULT_COUNT : data.size()) + 2;
}
/**
* <获取实际的个数>
* @return
* @see [类、类#方法、类#成员]
*/
public int getActualCount()
{
return getCount() - 2;
}
/**
* <获取当前的position>
* @param position
* @return
* @see [类、类#方法、类#成员]
*/
public int getActualDataIndex(int position)
{
int tempos = position - 1;
if (position == 0)
tempos = data.size() - 1;
else if (position == getCount() - 1)
tempos = 0;
return tempos;
}
@Override
public boolean isViewFromObject(View view, Object object)
{
return view == object;
}
@Override
public Object instantiateItem(final ViewGroup container, int position)
{
ImageView img = (ImageView)LayoutInflater.from(container.getContext()).inflate(R.layout.ui_home_banner_adapter, null);
container.addView(img);
if (data != null && !data.isEmpty())
{
final BannerEntity item = data.get(getActualDataIndex(position));
if (item != null && !TextUtils.isEmpty(item.getImg()))
{
ImageLoader.getInstance().displayImage(item.getImg(), img);// 网络图片下载与显示
img.setOnClickListener(new OnClickListener()
{
@Override
public void onClick(View v)
{
String url = item.getUrl();
if (!TextUtils.isEmpty(url))
{
Toast.makeText(context, url, Toast.LENGTH_SHORT).show();
}
}
});
}
}
return img;
}
@Override
public void destroyItem(ViewGroup container, int position, Object object)
{
if (object instanceof ImageView)
container.removeView((ImageView)object);
}
@Override
public void onLoadingCancelled(String arg0, View arg1)
{
}
@Override
public void onLoadingComplete(String arg0, View arg1, Bitmap arg2)
{
}
@Override
public void onLoadingFailed(String arg0, View arg1, FailReason arg2)
{
}
@Override
public void onLoadingStarted(String arg0, View arg1)
{
}
@Override
public void onPageScrolled(int position, float positionOffset, int positionOffsetPixels)
{
}
@Override
public void onPageSelected(int position)
{
if (getCount() < 3)
return;
if (position == 0)
pager.setCurrentItem(getCount() - 2, false);
else if (position == getCount() - 1)
//如果是最大页数,切换到第一页
pager.setCurrentItem(1, false);
if (pageListener != null)
//更新指示器
// Toast.makeText(context, "position = "+getActualDataIndex(position), Toast.LENGTH_SHORT).show();
pageListener.onPageChanged(getActualDataIndex(position));
}
@Override
public void onPageScrollStateChanged(int state)
{
}
public interface OnPageListener
{
public void onPageChanged(int item);
}
}
注:适配器中新增了一个回调OnPageListener,用于更新指示器的位置
4.MainActivity关键代码
public class MainActivity extends Activity implements OnPageListener
{
private ViewPager viewPager;
/**
* 适配器
*/
private AdatperBanner bannerAdatper;
/**
* 模拟数据
*/
private static final String[] IMAGE_LIST = new String[] {"http://img2.3lian.com/2014/c7/25/d/65.jpg", "http://g.hiphotos.baidu.com/zhidao/pic/item/18d8bc3eb13533fa24dfa175aad3fd1f41345b7b.jpg",
"http://a2.att.hudong.com/76/83/300254181849132325832985580_950.jpg", "http://img2.3lian.com/2014/f4/77/d/68.jpg"};
private List<BannerEntity> listEntity = new ArrayList<BannerEntity>();
@Override
protected void onCreate(Bundle savedInstanceState)
{
super.onCreate(savedInstanceState);
setContentView(R.layout.activity_main);
initView();
initData();
}
private void initView()
{
viewPager = (ViewPager)findViewById(R.id.banner_pager);
bannerAdatper = new AdatperBanner(viewPager, this, this);
viewPager.setAdapter(bannerAdatper);
// 按下时不继续定时滑动,弹起时继续定时滑动
viewPager.setOnTouchListener(new View.OnTouchListener()
{
@Override
public boolean onTouch(View v, MotionEvent event)
{
switch (event.getAction())
{
case MotionEvent.ACTION_DOWN:
// 按住事件发生后执行代码的区域
case MotionEvent.ACTION_MOVE:
// 移动事件发生后执行代码的区域
bannerAdatper.cancelDelayPlay();
break;
case MotionEvent.ACTION_UP:
// 松开事件发生后执行代码的区域
bannerAdatper.startDelayPlay();
break;
default:
bannerAdatper.startDelayPlay();
break;
}
return false;
}
});
}
/**
* 初始化模拟数据
* @see [类、类#方法、类#成员]
*/
private void initData()
{
listEntity.clear();
for (int i = 0; i < 4; i++)
{
BannerEntity bannerEntity = new BannerEntity();
bannerEntity.setId(i);
bannerEntity.setImg(IMAGE_LIST[i]);
bannerEntity.setJumps("");
bannerEntity.setUrl("www.baidu.com");
listEntity.add(bannerEntity);
}
bannerAdatper.setDataSource(listEntity);
}
/**
* <动态添加指示器>
* @param currentIndex
* @see [类、类#方法、类#成员]
*/
private void updateBannerPoints(int currentIndex)
{
if (bannerAdatper == null)
return;
LinearLayout group = (LinearLayout)findViewById(R.id.banner_pointer_group);
if (null == group)
return;
int pointCount = group.getChildCount();
int deepCount = bannerAdatper.getActualCount() - pointCount;
//需要添加的话就添加指示器小点
if (deepCount > 0)
{
for (int i = 0; i < deepCount; i++)
{
ImageView iv = (ImageView)LayoutInflater.from(MainActivity.this).inflate(R.layout.ui_home_fragment_main_banner_point, group, false);
if (null != iv)
group.addView(iv);
}
}
else if (deepCount < 0)
{
for (int i = 0; i < Math.abs(deepCount); i++)
{
group.removeViewAt(i);
}
}
for (int i = 0; i < group.getChildCount(); i++)
{
View point = group.getChildAt(i);
if (i == currentIndex)
point.setSelected(true);
else
point.setSelected(false);
}
}
@Override
public void onPageChanged(int item)
{
updateBannerPoints(item);
}
}
——————–基本代码如上所述,各位看官可根据实际需求做适量修改!