描述
轮播图,也有叫Banner图,基础上大部分项目都会用到,它可以在有限的屏幕上尽可能的展示比较多的资源,刚开始的时候知道用ViewPager做,最近的项目中将其封装成一个独立View,方便复用!
实现
1. 适配器
主要是利用ViewPager,其是support-v4中的一个类,主要用于左右滑屏,因为主要是显示图片,所以直接选用PagerAdapter作为适配器(其子类FragmentPagerAdapter可以和Fragment组合使用使用页面滑动);ViewPager有左右预加载的功能,这样的实现方式,不至于滑到下一页的时候,不至于出现空白;PagerAdapter主要需要实现4个方法,用于控制图片的显示和销毁,还有控制起无限循坏的条件 :
private class MyAdapter extends PagerAdapter {
//为了复用
private List<ImageView> imgCache = new ArrayList<ImageView>();
@Override
public int getCount() {
//无限滑动
return Integer.MAX_VALUE;
}
@Override
public boolean isViewFromObject(View view,Object o) {
return view == o;
}
@Override
public Object instantiateItem(ViewGroup container,final int position) {
ImageView iv;
//获取ImageView对象
if (imgCache.size() > 0) {
iv = imgCache.remove(0);
} else {
iv = new ImageView(mContext);
}
iv.setScaleType(ScaleType.FIT_XY);
iv.setOnTouchListener(new OnTouchListener() {
private int downX = 0;
private long downTime = 0;
@Override
public boolean onTouch(View v,MotionEvent event) {
switch (event.getAction()) {
case MotionEvent.ACTION_DOWN:
mAutoRollRunnable.stop();
//获取按下的x坐标
downX = (int) v.getX();
downTime = System.currentTimeMillis();
break;
case MotionEvent.ACTION_UP:
mAutoRollRunnable.start();
int moveX = (int) v.getX();
long moveTime = System.currentTimeMillis();
if (downX == moveX && (moveTime - downTime < 500)) {//点击的条件
//轮播图回调点击事件
headerViewClickListener.HeaderViewClick(position % mUrlList.size());
}
break;
case MotionEvent.ACTION_CANCEL://快速滑动不执行up
mAutoRollRunnable.start();
break;
}
return true;
}
});
//加载图片
Glide.with(mContext).load(mUrlList.get(position % mUrlList.size()))
.error(R.mipmap.ic_launcher).into(iv);
((ViewPager) container).addView(iv);
return iv;
}
@Override
public void destroyItem(ViewGroup container,int position,Object object) {
if (object != null && object instanceof ImageView) {
ImageView iv = (ImageView) object;
((ViewPager) container).removeView(iv);
imgCache.add(iv);
}
}
}
注意 :
(1) position % mUrlList.size(),因为getCount方法获取的是Integer.MAX_VALUE,所以这里所有的position都不是真正意义上的position;
(2) 之所以使用setOnTouchListener,没有用setOnClickListener主要是为了控制当手指触摸到轮播图上时停止轮播,过一定时间离开后继续轮播.
2. 自动轮播
每个一段时间做一个操作,有很多方式实现如Timer和TimerTask的组合,这里利用的是Handler的 boolean postDelayed(Runnable r,long delayMillis) 方法,此方法可以延时执行任务:
private class AutoRollRunnable implements Runnable {
// 标志
boolean isRunning = false;
public void start() {
if (!isRunning) {
isRunning = true;
mHandler.removeCallbacks(this);
mHandler.postDelayed(this,3000);
}
}
public void stop() {
if (isRunning) {
mHandler.removeCallbacks(this);
isRunning = false;
}
}
@Override
public void run() {
if (isRunning) {
mViewPager.setCurrentItem(mViewPager.getCurrentItem() + 1);
mHandler.postDelayed(this,3000);
}
}
}
//开始轮播
public void startRoll() {
mAutoRollRunnable.start();
}
// 停止轮播
public void stopRoll() {
mAutoRollRunnable.stop();
}
当页面离开时,停止轮播:
//停止轮播
@Override
protected void onDetachedFromWindow() {
super.onDetachedFromWindow();
stopRoll();
}
3. 控制Banner的高度
由于手机的屏幕大小分别很多,如果直接写死肯定不好,我的做法是让Banner占整个手机屏幕高度的1/4,这样的适配能满足现在需求:
//初始化view
private void initView() {
View.inflate(mContext,R.layout.view_header,this);
mViewPager = (ViewPager) findViewById(R.id.vp);
mDotLl = (LinearLayout) findViewById(R.id.ll_dot);
//让banner的高度是屏幕的1/4
ViewGroup.LayoutParams vParams = mViewPager.getLayoutParams();
vParams.height = (int) (DisplayUtil.getMobileHeight(mContext) * 0.25);
mViewPager.setLayoutParams(vParams);
}
其中的view_header如下:
<?xml version="1.0" encoding="utf-8"?>
<FrameLayout xmlns:android="http://schemas.android.com/apk/res/android"
android:layout_width="wrap_content"
android:layout_height="wrap_content" >
<android.support.v4.view.ViewPager
android:id="@+id/vp"
android:layout_width="match_parent"
android:layout_height="match_parent"
android:focusable="true"
android:focusableInTouchMode="true" />
<LinearLayout
android:id="@+id/ll_dot"
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:layout_gravity="bottom|right"
android:paddingRight="8dip"
android:layout_marginBottom="8dip"
android:gravity="center"
android:orientation="horizontal" >
</LinearLayout>
</FrameLayout>
4. 初始化Banner底部的点
这些点应该是有多少图片(图片链接),就应该有多少个点:
//设置数据
public void setImgUrlData(List<String> urlList) {
this.mUrlList = urlList;
if (mUrlList != null && !mUrlList.isEmpty()) {
//清空数据
dotList.clear();
mDotLl.removeAllViews();
ImageView dotIv;
LinearLayout.LayoutParams params = new LinearLayout.LayoutParams(LayoutParams.WRAP_CONTENT,LayoutParams.WRAP_CONTENT);
for (int i = 0; i < mUrlList.size(); i++) {
dotIv = new ImageView(mContext);
if (i == 0) {
dotIv.setBackgroundResource(R.mipmap.banner_dot_select);
} else {
dotIv.setBackgroundResource(R.mipmap.banner_dot_normal);
}
//设置点的间距
params.setMargins(0,0,DisplayUtil.dip2px(mContext,5),0);
dotIv.setLayoutParams(params);
//添加点到view上
mDotLl.addView(dotIv);
//添加到集合中,以便控制其切换
dotList.add(dotIv);
}
}
mAdapter = new MyAdapter();
mViewPager.setAdapter(mAdapter);
//设置viewpager初始位置,+10000就够了
mViewPager.setCurrentItem(urlList.size() + 10000);
startRoll();
}
5. 用法
在上面的 setImgUrlData 方法后面, 我是直接初始化并设置了Adapter,并直接让轮播图滚动了起来,这样只需要少量的代码就可以用了,或者直接在布局文件中使用 :
RollHeaderView rollHeaderView = new RollHeaderView(this);
rollHeaderView.setImgUrlData(imgUrlList);
rollHeaderView.setOnHeaderViewClickListener(new RollHeaderView.HeaderViewClickListener() {
@Override
public void HeaderViewClick(int position) {
Toast.makeText(MainActivity.this,"点击 : " + position,Toast.LENGTH_SHORT).show();
}
});
比起之前直接在Activity里面用ViewPager不知道简洁了多少倍!
6. 效果
7. 需改进
(1) 每次总是选中第一张图片和点;
(2) 可以加入文字信息说明;
(3) 不用xml,直接用代码写布局;
(4) ……