您的位置:首页 > 移动开发 > Android开发

Android之最简单的Banner实现

2016-12-16 15:31 337 查看
本文主要记录一些零碎的东西

最近项目里需要在首页做一个展示用的banner,基本需求就是可以滚动,可以点击

网上很多现成的,自己有思路,撸了一个简单的实现版本



使用ViewPager ,图片加载使用Glide
循环原理 :   4--1- 2- 3 -4--1  第一页左边增加最后一页,最后一页右边增加第一页
0  1  2  3  4  5
当选中新的界面上的第0页时,调到新的界面第4页;当选中新的界面上的第5页时,调到新的界面第1页.




代码比较简单

--有滑动界面指示器(右下角小圆点)
--支持自定义自动滑动的时间间隔
--支持自动滑动
--支持手势滑动,取消自动滑动,无手势3秒后,如设置了自动滑动,继续自动滑动
--支持item点击


只有一个文件 BannerView

import android.content.Context;
import android.os.Handler;
import android.os.Looper;
import android.support.v4.view.PagerAdapter;
import android.support.v4.view.ViewPager;
import android.util.AttributeSet;
import android.util.Log;
import android.view.Gravity;
import android.view.MotionEvent;
import android.view.View;
import android.view.ViewGroup;
import android.widget.FrameLayout;
import android.widget.ImageView;
import android.widget.LinearLayout;
import android.widget.TextView;

import com.bumptech.glide.Glide;

import java.util.ArrayList;
import java.util.List;

/**
* 循环 banner    3- 1-2-3 -1
* Created by slack on 2016/12/9 18:46.
* 如何区分是手动 还是 自动
*/

public class BannerView extends FrameLayout implements View.OnClickListener {

private ViewPager mViewPager;
private List<String> mFilePathList;
private ImageView mImageView;
private List<ImageView> mImageList = new ArrayList<>();
// test
//    private List<TextView> mImageList = new ArrayList<>();
//    private TextView mImageView;

private int mCurrentPosition;
private Handler mHandler;
private int DEFAULT_INTERVAL = 1500;
private int DEFAULT_WAIT_TIME = 3000; // 3s 后用户没有点击,继续自动滑动
private long mTouchTime;

private boolean auto = false;
private OnItemClickListener mOnItemClickListener;

private LinearLayout mPointContainer; // 存放点的容器
private int mPointDrawableId = R.drawable.selector_banner_point; // 点的drawable资源id
private ImageView mPoint;

public BannerView(Context context) {
this(context, null);
}

public BannerView(Context context, AttributeSet attrs) {
this(context, attrs, 0);
}

public BannerView(Context context, AttributeSet attrs, int defStyleAttr) {
super(context, attrs, defStyleAttr);
mHandler = new Handler(Looper.getMainLooper());
initView();
}

public BannerView setOnItemClickListener(OnItemClickListener l) {
mOnItemClickListener = l;
return this;
}

/**
* 设置数据,初始化view部分
*
* @param list imageUri 使用Glide 加载
* @return
*/
public BannerView setBannerData(List<String> list) {
mFilePathList = list;
if (list.size() > 1) {
for (int i = 0; i < list.size(); i++) {
//            mImageView = new ImageView(getContext());
createNewView(list.get(i));
// point
mPoint = new ImageView(getContext());
mPoint.setImageResource(mPointDrawableId);
mPoint.setEnabled(false);
mPoint.setPadding(10, 0, 10, 0);
mPointContainer.addView(mPoint);
}
// 第一页加在最后
createNewView(list.get(0), -1);
// 最后一页加在第一页
createNewView(list.get(list.size() - 1), 0);

mCurrentPosition = 1;
mViewPager.setOffscreenPageLimit(2);
mViewPager.addOnPageChangeListener(pageChangeListener);

} else {
createNewView(list.get(0));
mCurrentPosition = 0;

mPoint = new ImageView(getContext());
mPoint.setImageResource(mPointDrawableId);
mPoint.setEnabled(true);
mPointContainer.addView(mPoint);
}
mViewPager.setAdapter(new InnerPagerAdapter());
mViewPager.setCurrentItem(mCurrentPosition);

return this;
}

/**
* 对应activity的生命周期
*
* @return
*/
public BannerView onResume() {
if (auto) {
mHandler.removeCallbacks(autoSmooth);
mHandler.post(autoSmooth);
}
return this;
}

public BannerView onPause() {
mHandler.removeCallbacks(autoSmooth);
mHandler.removeCallbacks(timeCount);
return this;
}

private void createNewView(String text) {
createNewView(text, -1);
}

private void createNewView(String url, int position) {
mImageView = new ImageView(getContext());
mImageView.setScaleType(ImageView.ScaleType.CENTER_CROP);
if (position == -1) {
mImageList.add(mImageView);
} else {
mImageList.add(position, mImageView);
}
mImageView.setOnClickListener(this);

Glide.with(getContext())
.load(url)
.placeholder(R.mipmap.empty)
.error(R.mipmap.error)
.into(mImageView);

//        mImageView = new TextView(getContext());
//        mImageView.setText(text);
//        if(position == -1) {
//            mImageList.add(mImageView);
//        }else {
//            mImageList.add(position,mImageView);
//        }
//        mImageView.setOnClickListener(this);
}

/**
* 时间间隔
*
* @param interval
*/
public BannerView setSmoothInterval(int interval) {
DEFAULT_INTERVAL = interval;
return this;
}

/**
* 自动滑动
*/
public void startSmoothAuto() {
if (mImageList.size() == 1) {
return;
}
auto = true;
mHandler.postDelayed(autoSmooth, DEFAULT_INTERVAL);
}

Runnable autoSmooth = new Runnable() {
@Override
public void run() {
mCurrentPosition++;
mCurrentPosition = mCurrentPosition % mImageList.size();
mViewPager.setCurrentItem(mCurrentPosition);
mHandler.postDelayed(this, DEFAULT_INTERVAL);
}
};

Runnable timeCount = new Runnable() {
@Override
public void run() {
if (System.currentTimeMillis() - mTouchTime > DEFAULT_WAIT_TIME) {
mHandler.removeCallbacks(this);
mHandler.removeCallbacks(autoSmooth);
mHandler.post(autoSmooth);
return;
}
mHandler.postDelayed(this, DEFAULT_INTERVAL);
}
};

private void initView() {
mViewPager = new ViewPager(getContext());
addView(mViewPager);

mPointContainer = new LinearLayout(getContext());
mPointContainer.setPadding(0, 0, 80, 20);
mPointContainer.setGravity(Gravity.BOTTOM | Gravity.RIGHT);

addView(mPointContainer);
}

ViewPager.OnPageChangeListener pageChangeListener = new ViewPager.OnPageChangeListener() {
@Override
public void onPageScrolled(int position, float positionOffset, int positionOffsetPixels) {
//            Log.i("slack","onPageScrolled...");
}

@Override
public void onPageSelected(int position) {
//            Log.i("slack","onPageSelected...");
mCurrentPosition = position;
switchToPoint();
}

@Override
public void onPageScrollStateChanged(int state) {

if (state == ViewPager.SCROLL_STATE_IDLE && mImageList.size() > 1) {
if (mCurrentPosition == 0) {
mCurrentPosition = mImageList.size() - 2;
mViewPager.setCurrentItem(mCurrentPosition, false);
} else if (mCurrentPosition == (mImageList.size() - 1)) {
mCurrentPosition = 1;
mViewPager.setCurrentItem(mCurrentPosition, false);
}
//                Log.i("slack","onPageScrollStateChanged..." + mCurrentPosition);
}

}
};

/**
* point 假如有三个实际页面,0-2
*/
private void switchToPoint() {

if (mCurrentPosition == 0 || mCurrentPosition == mImageList.size() - 1) {
return;
}

for (int i = 0; i < mPointContainer.getChildCount(); i++) {
mPointContainer.getChildAt(i).setEnabled(false);
}

mPointContainer.getChildAt(mCurrentPosition - 1).setEnabled(true);
}

@Override
public void onClick(View view) {
//        Log.i("slack", "pos: " + mCurrentPosition);
if (mOnItemClickListener != null) {
mOnItemClickListener.onItemClick(mCurrentPosition - 1);
}
}

/**
* viewPager的适配器
*/
private class InnerPagerAdapter extends PagerAdapter {

@Override
public int getCount() {
return mImageList.size() > 1 ? mImageList.size() : 1;
}

@Override
public Object instantiateItem(ViewGroup container, final int position) {
container.addView(mImageList.get(position));
return mImageList.get(position);
}

@Override
public void destroyItem(ViewGroup container, int position, Object object) {
container.removeView((View) object);
}

@Override
public boolean isViewFromObject(View view, Object object) {
return view == object;
}

@Override
public int getItemPosition(Object object) {
return POSITION_NONE;
}
}

// ACTION_UP 滑动冲突,获取不到
@Override
public boolean onInterceptTouchEvent(MotionEvent ev) {
//        Log.i("slack","onInterceptTouchEvent..." + ev.toString());
if (auto) {
if (ev.getAction() == MotionEvent.ACTION_DOWN) {
mHandler.removeCallbacks(autoSmooth);
} else if (ev.getAction() == MotionEvent.ACTION_MOVE) {
mTouchTime = System.currentTimeMillis();
mHandler.postDelayed(timeCount, 100);
}
}
return super.onInterceptTouchEvent(ev);
}

public interface OnItemClickListener {
void onItemClick(int position);
}
}

测试代码
import android.support.v7.app.AppCompatActivity;
import android.os.Bundle;
import android.widget.Toast;

import java.util.ArrayList;
import java.util.List;

public class BannerActivity extends AppCompatActivity {

private BannerView mBannerView;
private List<String> mList;
@Override
protected void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
setContentView(R.layout.activity_banner);

mBannerView = (BannerView) findViewById(R.id.id_banner);

mList = new ArrayList<>();
mList.add("http://img1.imgtn.bdimg.com/it/u=2387069514,246472357&fm=23&gp=0.jpg");
mList.add("http://img3.duitang.com/uploads/item/201601/03/20160103103827_5XEts.thumb.700_0.jpeg");
mList.add("http://f2.dn.anqu.com/down/YjFkMw==/allimg/1301/60-130130114620.jpg");

mBannerView.setOnItemClickListener(new BannerView.OnItemClickListener() {
@Override
public void onItemClick(int position) {
Toast.makeText(BannerActivity.this,"Position " + position ,Toast.LENGTH_SHORT).show();
}
}).setBannerData(mList).setSmoothInterval(1500).startSmoothAuto();
}

@Override
protected void onResume() {
super.onResume();
mBannerView.onResume();
}

@Override
protected void onPause() {
super.onPause();
mBannerView.onPause();
}
}

附:
指示器圆点显示:drawable/selector_banner_point.xml
<?xml version="1.0" encoding="utf-8"?>
<selector xmlns:android="http://schemas.android.com/apk/res/android">
<item android:state_enabled="true">
<shape android:shape="oval">
<size android:width="6dp" android:height="6dp" />
<solid android:color="@android:color/white" />
</shape>
</item>
<item>
<shape android:shape="oval">
<size android:width="6dp" android:height="6dp" />
<solid android:color="#C6C6C6" />
</shape>
</item>
</selector>
Glide引入:dependencies { compile 'com.github.bumptech.glide:glide:3.5.2'}别忘了联网权限 AndroidManifest.xml<uses-permission android:name="android.permission.INTERNET"/>

---------更新------------------------
降低banner 自动滑动速度
import android.content.Context;
import android.os.Handler;
import android.os.Looper;
import android.support.v4.view.PagerAdapter;
import android.support.v4.view.ViewPager;
import android.util.AttributeSet;
import android.view.Gravity;
import android.view.MotionEvent;
import android.view.View;
import android.view.ViewGroup;
import android.view.animation.DecelerateInterpolator;
import android.view.animation.Interpolator;
import android.widget.FrameLayout;
import android.widget.ImageView;
import android.widget.LinearLayout;
import android.widget.Scroller;

import com.benqu.serverside.model.appsettings.ApiModelCarousel;
import com.benqu.wuta.R;
import com.benqu.wuta.WTController;
import com.benqu.wuta.utils.BannerUtil;

import java.lang.reflect.Field;
import java.util.ArrayList;
import java.util.List;

/** 首页 循环 banner    3- 1-2-3 -1
* Created by slack on 2016/12/14 17:41.
*/
public class BannerView extends FrameLayout implements View.OnClickListener {

private ViewPagerCustomDuration mViewPager;
private ImageView mImageView;
private List<ImageView> mImageList = new ArrayList<>();

private int mCurrentPosition;
private Handler mHandler;
private static final int DEFAULT_DELAY = 1000;
private int DEFAULT_INTERVAL = 1500;
private int DEFAULT_WAIT_TIME = 3000; // 3s 后用户没有点击,继续自动滑动
private long mTouchTime;

private boolean auto = false;
private OnItemClickListener mOnItemClickListener;

//    private LinearLayout mPointContainer; // 存放点的容器
//    private int mPointDrawableId = R.drawable.banner_point; // 点的drawable资源id
//    private ImageView mPoint;

private BannerUtil mBannerUtil = BannerUtil.util;

public BannerView(Context context) {
this(context, null);
}

public BannerView(Context context, AttributeSet attrs) {
this(context, attrs, 0);
}

public BannerView(Context context, AttributeSet attrs, int defStyleAttr) {
super(context, attrs, defStyleAttr);
mHandler = new Handler(Looper.getMainLooper());
initView();
}

public BannerView setOnItemClickListener(OnItemClickListener l) {
mOnItemClickListener = l;
return this;
}

/**
* 设置数据,初始化view部分
*
* @return
*/
public BannerView setBannerData(ApiModelCarousel carousel) {
if (carousel.itemList.size() > 1) {
for (int i = 0; i < carousel.itemList.size(); i++) {
//            mImageView = new ImageView(getContext());
createNewView(carousel.itemList.get(i));
// point
//                mPoint = new ImageView(getContext());
//                mPoint.setImageResource(mPointDrawableId);
//                mPoint.setEnabled(false);
//                mPoint.setPadding(10, 0, 10, 0);
//                mPointContainer.addView(mPoint);
}
// 第一页加在最后
createNewView(carousel.itemList.get(0));
// 最后一页加在第一页
createNewView(carousel.itemList.get(carousel.itemList.size() - 1), 0);

mCurrentPosition = 1;
mViewPager.setOffscreenPageLimit(2);
mViewPager.addOnPageChangeListener(pageChangeListener);

} else {
createNewView(carousel.itemList.get(0));
mCurrentPosition = 0;

//            mPoint = new ImageView(getContext());
//            mPoint.setImageResource(mPointDrawableId);
//            mPoint.setEnabled(true);
//            mPointContainer.addView(mPoint);
}
mViewPager.setAdapter(new InnerPagerAdapter());
mViewPager.setCurrentItem(mCurrentPosition);

return this;
}

/**
* 对应activity的生命周期
*
* @return
*/
public BannerView onResume() {
if (auto && mImageList != null && mImageList.size() > 1) {
mHandler.removeCallbacks(autoSmooth);
mHandler.postDelayed(autoSmooth,DEFAULT_DELAY);
}
return this;
}

public BannerView onPause() {
mHandler.removeCallbacks(autoSmooth);
mHandler.removeCallbacks(timeCount);
return this;
}

private void createNewView(ApiModelCarousel.ApiModelCarouselItem item) {
createNewView(item,-1);
}

private void createNewView(ApiModelCarousel.ApiModelCarouselItem item, int position) {
mImageView = new ImageView(getContext());
mImageView.setScaleType(ImageView.ScaleType.CENTER_CROP);
if (position == -1) {
mImageList.add(mImageView);
} else {
mImageList.add(position, mImageView);
}
mImageView.setOnClickListener(this);
mBannerUtil.showBannerImage(mImageView,item.getImgUrl());

}

/**
* 时间间隔
*
* @param interval
*/
public BannerView setSmoothInterval(int interval) {
DEFAULT_INTERVAL = interval;
return this;
}

/**
* 自动滑动
*/
public void startSmoothAuto() {
if (mImageList.size() == 1) {
return;
}
auto = true;
mHandler.postDelayed(autoSmooth, DEFAULT_DELAY);// delay 1s
}

Runnable autoSmooth = new Runnable() {
@Override
public void run() {
mCurrentPosition++;
mCurrentPosition = mCurrentPosition % mImageList.size();
mViewPager.setCurrentItem(mCurrentPosition,true);
mHandler.postDelayed(this, DEFAULT_INTERVAL);
}
};

Runnable timeCount = new Runnable() {
@Override
public void run() {
if (System.currentTimeMillis() - mTouchTime > DEFAULT_WAIT_TIME) {
mHandler.removeCallbacks(this);
mHandler.removeCallbacks(autoSmooth);
mHandler.post(autoSmooth);
return;
}
mHandler.postDelayed(this, DEFAULT_INTERVAL);
}
};

private void initView() {
//        mViewPager = new ViewPager(getContext());
mViewPager = new ViewPagerCustomDuration(getContext());
addView(mViewPager);

//        mPointContainer = new LinearLayout(getContext());
//        mPointContainer.setPadding(0, 0, 80, 20);
//        mPointContainer.setGravity(Gravity.BOTTOM | Gravity.RIGHT);
//
//        addView(mPointContainer);
}

ViewPager.OnPageChangeListener pageChangeListener = new ViewPager.OnPageChangeListener() {
@Override
public void onPageScrolled(int position, float positionOffset, int positionOffsetPixels) {
//            Log.i("slack","onPageScrolled...");
}

@Override
public void onPageSelected(int position) {
//            Log.i("slack","onPageSelected...");
mCurrentPosition = position;
switchToPoint();
}

@Override
public void onPageScrollStateChanged(int state) {

if (state == ViewPager.SCROLL_STATE_IDLE && mImageList.size() > 1) {
if (mCurrentPosition == 0) {
mCurrentPosition = mImageList.size() - 2;
mViewPager.setCurrentItem(mCurrentPosition, false);
} else if (mCurrentPosition == (mImageList.size() - 1)) {
mCurrentPosition = 1;
mViewPager.setCurrentItem(mCurrentPosition, false);
}
//                Log.i("slack","onPageScrollStateChanged..." + mCurrentPosition);
}

}
};

/**
* point 假如有三个实际页面,0-2
*/
private void switchToPoint() {

//        if (mCurrentPosition == 0 || mCurrentPosition == mImageList.size() - 1) {
//            return;
//        }
//
//        for (int i = 0; i < mPointContainer.getChildCount(); i++) {
//            mPointContainer.getChildAt(i).setEnabled(false);
//        }
//
//        mPointContainer.getChildAt(mCurrentPosition - 1).setEnabled(true);
}

@Override
public void onClick(View view) {
//        Log.i("slack", "pos: " + mCurrentPosition);
if (mOnItemClickListener != null) {
mOnItemClickListener.onItemClick(mImageList.size() > 1 ? mCurrentPosition - 1 : 0);
}
}

/**
* viewPager的适配器
*/
private class InnerPagerAdapter extends PagerAdapter {

@Override
public int getCount() {
return mImageList.size() > 1 ? mImageList.size() : 1;
}

@Override
public Object instantiateItem(ViewGroup container, final int position) {
container.addView(mImageList.get(position));
return mImageList.get(position);
}

@Override
public void destroyItem(ViewGroup container, int position, Object object) {
container.removeView((View) object);
}

@Override
public boolean isViewFromObject(View view, Object object) {
return view == object;
}

@Override
public int getItemPosition(Object object) {
return POSITION_NONE;
}
}

/**
* my ViewPager slow down zhe speed
*/
private class ViewPagerCustomDuration extends ViewPager {
private FixedSpeedScroller mScroller = null;

public ViewPagerCustomDuration(Context context) {
super(context);
init();
}

public ViewPagerCustomDuration(Context context, AttributeSet attrs) {
super(context, attrs);
init();
}

/*
* Override the Scroller instance with our own class so we can change the
* duration
*/
private void init() {
try {
Class<?> viewpager = ViewPager.class;
Field scroller = viewpager.getDeclaredField("mScroller");
scroller.setAccessible(true);
mScroller = new FixedSpeedScroller(getContext(),
new DecelerateInterpolator());
scroller.set(this, mScroller);
} catch (Exception ignored) {
}
}

/*
* Set the factor by which the duration will change
*/
public void setScrollDuration(int duration) {
mScroller.setScrollDuration(duration);
}

private class FixedSpeedScroller extends Scroller {

private int mDuration = 500;

public FixedSpeedScroller(Context context) {
super(context);
}

public FixedSpeedScroller(Context context, Interpolator interpolator) {
super(context, interpolator);
}

public FixedSpeedScroller(Context context, Interpolator interpolator, boolean flywheel) {
super(context, interpolator, flywheel);
}

@Override
public void startScroll(int startX, int startY, int dx, int dy, int duration) {
// Ignore received duration, use fixed one instead
super.startScroll(startX, startY, dx, dy, mDuration);
}

@Override
public void startScroll(int startX, int startY, int dx, int dy) {
// Ignore received duration, use fixed one instead
super.startScroll(startX, startY, dx, dy, mDuration);
}

public void setScrollDuration(int duration) {
mDuration = duration;
}
}
}

// ACTION_UP 滑动冲突,获取不到
@Override
public boolean onInterceptTouchEvent(MotionEvent ev) {
//        Log.i("slack","onInterceptTouchEvent..." + ev.toString());
if (auto) {
if (ev.getAction() == MotionEvent.ACTION_DOWN) {
mHandler.removeCallbacks(autoSmooth);
} else if (ev.getAction() == MotionEvent.ACTION_MOVE) {
mTouchTime = System.currentTimeMillis();
mHandler.postDelayed(timeCount, 100);
}
}
return super.onInterceptTouchEvent(ev);
}

public interface OnItemClickListener {
void onItemClick(int position);
}
}
内容来自用户分享和网络整理,不保证内容的准确性,如有侵权内容,可联系管理员处理 点击这里给我发消息
标签: