Android之最简单的Banner实现

本文主要记录一些零碎的东西

最近项目里需要在首页做一个展示用的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);
    }
}


  • 5
    点赞
  • 1
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值