描述
輪播圖,也有叫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() > ) {
iv = imgCache.remove();
} else {
iv = new ImageView(mContext);
}
iv.setScaleType(ScaleType.FIT_XY);
iv.setOnTouchListener(new OnTouchListener() {
private int downX = ;
private long downTime = ;
@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 < )) {//點選的條件
//輪播圖回調點選事件
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,);
}
}
public void stop() {
if (isRunning) {
mHandler.removeCallbacks(this);
isRunning = false;
}
}
@Override
public void run() {
if (isRunning) {
mViewPager.setCurrentItem(mViewPager.getCurrentItem() + );
mHandler.postDelayed(this,);
}
}
}
//開始輪播
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的高度是螢幕的/
ViewGroup.LayoutParams vParams = mViewPager.getLayoutParams();
vParams.height = (int) (DisplayUtil.getMobileHeight(mContext) * );
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 = ; i < mUrlList.size(); i++) {
dotIv = new ImageView(mContext);
if (i == ) {
dotIv.setBackgroundResource(R.mipmap.banner_dot_select);
} else {
dotIv.setBackgroundResource(R.mipmap.banner_dot_normal);
}
//設定點的間距
params.setMargins(,,DisplayUtil.dip2px(mContext,),);
dotIv.setLayoutParams(params);
//添加點到view上
mDotLl.addView(dotIv);
//添加到集合中,以便控制其切換
dotList.add(dotIv);
}
}
mAdapter = new MyAdapter();
mViewPager.setAdapter(mAdapter);
//設定viewpager初始位置,+10000就夠了
mViewPager.setCurrentItem(urlList.size() + );
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) ……
8. 源碼:
點選檢視源碼