自动滑动广告栏是比较常用的功能之一,方法一是使用的是一个第三方工具AutoScrollViewPager,方法二使用的是自定义控件实现需要的要求.
1.AutoScrollViewPager
第三方库,github地址:
https://github.com/Trinea/android-auto-scroll-view-pager
直接使用在线导包:
compile('cn.trinea.android.view.autoscrollviewpager:android-auto-scroll-view-pager:1.1.2') {
exclude module: 'support-v4'
}
开始使用:
①在布局中使用控件
<?xml version="1.0" encoding="utf-8"?>
<RelativeLayout
xmlns:android="http://schemas.android.com/apk/res/android"
xmlns:tools="http://schemas.android.com/tools"
android:id="@+id/activity_main"
android:layout_width="match_parent"
android:layout_height="match_parent"
tools:context="com.simon.autobanner.MainActivity">
<cn.trinea.android.view.autoscrollviewpager.AutoScrollViewPager
android:id="@+id/main_autoscrollviewpager"
android:layout_width="match_parent"
android:layout_height="175dp"/>
</RelativeLayout>
②创建Adapter,继承PagerAdapter
因为这个控件是ViewPager,要用到Adapter(适配器)来展现数据
Activity代码
public class MainActivity extends AppCompatActivity {
private AutoScrollViewPager mAutoscrollViewPager;
private MyViewPagerAdapter mMyViewPagerAdapter;
private ArrayList<ImageView> mImageViews;
@Override
protected void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
setContentView(R.layout.activity_main);
initData();
initView();
}
private void initData() {
//模拟广告图片,一般是从网络后台获取
mImageViews = new ArrayList<>();
ImageView img1 = new ImageView(this);
img1.setScaleType(ImageView.ScaleType.FIT_XY);
img1.setImageResource(R.mipmap.mao1);
mImageViews.add(img1);
ImageView img2= new ImageView(this);
img2.setScaleType(ImageView.ScaleType.FIT_XY);
img2.setImageResource(R.mipmap.mao2);
mImageViews.add(img2);
ImageView img3 = new ImageView(this);
img3.setScaleType(ImageView.ScaleType.FIT_XY);
img3.setImageResource(R.mipmap.mao3);
mImageViews.add(img3);
ImageView img4 = new ImageView(this);
img4.setScaleType(ImageView.ScaleType.FIT_XY);
img4.setImageResource(R.mipmap.mao4);
mImageViews.add(img4);
}
private void initView() {
//找到控件id
mAutoscrollViewPager = (AutoScrollViewPager) findViewById(R.id.main_autoscrollviewpager);
//new出Adapter
mMyViewPagerAdapter = new MyViewPagerAdapter(this);
//传入数据
mMyViewPagerAdapter.setDatas(mImageViews);
//绑定ViewPager和adapter
mAutoscrollViewPager.setAdapter(mMyViewPagerAdapter);
//启动自动滑动
mAutoscrollViewPager.startAutoScroll();
}
}
adapter代码
public class MyViewPagerAdapter extends PagerAdapter {
private final Context context;
private ArrayList<ImageView> mDatas;
public MyViewPagerAdapter(Context context) {
this.context = context;
}
public void setDatas(ArrayList<ImageView> imageViews){
mDatas=imageViews;
}
@Override
public int getCount() {
return mDatas.size();
}
@Override
public boolean isViewFromObject(View view, Object object) {
return view == object;
}
//还需要重写两个方法instantiateItem和destroyItem
//将某一项视图添加ViewPager中
@Override
public Object instantiateItem(ViewGroup container, int position) {
ImageView imageView = mDatas.get(position);
container.addView(imageView);
//返回图片视图
return imageView;
}
//将某一项视图从ViewPager中销毁
@Override
public void destroyItem(ViewGroup container, int position, Object object) {
ImageView imageView = mDatas.get(position);
container.removeView(imageView);
}
}
③添加指示器
/***
* 初始化指示器
*/
private void initAdBannerIndicator(int size) {
//1.做一个for循环
//2.创建图片控件 要设置宽高 绑定shapDrawable 添加到容器中
//3.默认让第一个选中
for (int i = 0; i < size; i++) {
ImageView iv = new ImageView(this);
LinearLayout.LayoutParams params = new LinearLayout.LayoutParams(15, 15);//px
params.setMargins(20, 0, 0, 0);
iv.setLayoutParams(params);
iv.setBackgroundResource(R.drawable.ad_indicator_bg);
mAdIndicator.addView(iv);
}
//启动时默认为第一个
changeAdIndicator(0);
}
/**
* 修改广告栏的指示器
*/
private void changeAdIndicator(int position) {
int childCount = mAdIndicator.getChildCount();
for (int i = 0; i < childCount; i++) {
//getChildAt 获取某个容器内部的位置为i的子控件
mAdIndicator.getChildAt(i).setSelected(i == position);
}
}
要让指示器随着广告的变化而变化,要给ViewPager设置监听器,获取ViewPager当前位置,然后修改指示器,从而达到效果
//找到指示器的容器id
mAdIndicator = (LinearLayout) findViewById(R.id.ad_indicator);
initAdBannerIndicator(mImageViews.size());
//设置监听器
mAutoscrollViewPager.addOnPageChangeListener(new ViewPager.OnPageChangeListener() {
@Override
public void onPageScrolled(int position, float positionOffset, int positionOffsetPixels) {
}
@Override
public void onPageSelected(int position) {
changeAdIndicator(position);
}
@Override
public void onPageScrollStateChanged(int state) {
}
});
但是这里还有一点小问题,就是从最后一页返回第一页时,效果不太好,可以通过重写某个方法达到想要的效果,原理与下面的方法相同,所以这里就不重复了.
④其他属性设置
setInterval(long) 设置自动滚动的间隔时间,单位为毫秒
setDirection(int) 设置自动滚动的方向,默认向右
setCycle(boolean) 是否自动循环轮播,默认为true
setScrollDurationFactor(double) 设置ViewPager滑动动画间隔时间的倍率,达到减慢动画或改变动画速度的效果
setStopScrollWhenTouch(boolean) 当手指碰到ViewPager时是否停止自动滚动,默认为true
setSlideBorderMode(int) 滑动到第一个或最后一个Item的处理方式,支持没有任何操作、轮播以及传递到父View三种模式
setBorderAnimation(boolean) 设置循环滚动时滑动到从边缘滚动到下一个是否需要动画,默认为true
2.自定义广告轮播控件
采用自定义控件的方法,做出一个能达到想要的效果的广告轮播控件
①创建一个新的类BannerScrollView,继承RelativeLayout
实现构造方法,并模拟了数据
public BannerScrollView(Context context) {
super(context);
}
public BannerScrollView(Context context, AttributeSet attrs) {
super(context, attrs);
initData();
initView();
}
private void initView() {
//因为是继承了系统的控件,所以在加载布局的时候需要与父布局绑定
View view = View.inflate(getContext(), R.layout.view_banner, this);
mBannerVp = (ViewPager) view.findViewById(R.id.banner_vp);
mBannerRl = (RelativeLayout) view.findViewById(R.id.banner_rl);
mBannerTvTitle = (TextView) view.findViewById(R.id.banner_tv_title);
mBannerLlIndicator = (LinearLayout) view.findViewById(R.id.banner_ll_indicator);
//创建adapter
mBannerScrollAdapter = new BannerScrollAdapter();
mBannerScrollAdapter.setDatas(mImageViews);
//绑定ViewPager和adapter
mBannerVp.setAdapter(mBannerScrollAdapter);
}
private void initData() {
mImageViews = new ArrayList<>();
//根据业务需求,把传进来的数据进行网络请求,再转为图片格式放入imageView
//现在只能模拟数据,直接放入图片
ImageView img1 = new ImageView(getContext());
img1.setScaleType(ImageView.ScaleType.FIT_XY);
img1.setImageResource(R.mipmap.mao1);
mImageViews.add(img1);
ImageView img2 = new ImageView(getContext());
img2.setScaleType(ImageView.ScaleType.FIT_XY);
img2.setImageResource(R.mipmap.mao2);
mImageViews.add(img2);
ImageView img3 = new ImageView(getContext());
img3.setScaleType(ImageView.ScaleType.FIT_XY);
img3.setImageResource(R.mipmap.mao3);
mImageViews.add(img3);
ImageView img4 = new ImageView(getContext());
img4.setScaleType(ImageView.ScaleType.FIT_XY);
img4.setImageResource(R.mipmap.mao4);
mImageViews.add(img4);
}
②创建适配器adapter
public class BannerScrollAdapter extends PagerAdapter {
private ArrayList<ImageView> mBannerImg;
public void setDatas(ArrayList<ImageView> bannerImg) {
mBannerImg = bannerImg;
}
@Override
public int getCount() {
//把数量写成integer的最大值,这就能实现无限播放了
return Integer.MAX_VALUE;
// return mBannerImg.size();
}
@Override
public boolean isViewFromObject(View view, Object object) {
return view == object;
}
@Override
public Object instantiateItem(ViewGroup container, int position) {
//防止数引越界
position = position % mBannerImg.size();
ImageView imageView = mBannerImg.get(position);
container.addView(imageView);
return imageView;
}
@Override
public void destroyItem(ViewGroup container, int position, Object object) {
position = position%mBannerImg.size();
ImageView imageView = mBannerImg.get(position);
container.removeView(imageView);
}
}
现在已经实现了ViewPager的效果,而且能够无限滑动
③让广告自动轮播
让广告自动轮播的方法不只一种,我这里用的是Handler发送延迟消息,来进行轮播
Handler mHandler = new Handler() {
@Override
public void handleMessage(Message msg) {
//① int position = msg.what;
②int position=mBannerVp.getCurrentItem();
position++;
mBannerVp.setCurrentItem(position);
sendEmptyMessageDelayed(position, 2000);
}
};
这里有一个bug,①中position值是从handler发送过来的mBannerVp.getCurrentItem(),但是如果使用这个值的话,当广告栏往回滑的时候就会报错,而使用②中再次获取mBannerVp.getCurrentItem()值后就可以正常运行.
经过打印log得知,①中的数据不是期望的值,具体的原因可能需要查看源代码才能知道.
④添加ViewPager的触摸事件
现在已经实现了广告的轮播效果,但是现在的代码还有很多的问题
1.当你想手动滑动广告的时候,广告还是会自动轮播.
2.当你往回滑时,程序会报错,而且错误不只是一个.
给ViewPager添加触摸事件可以暂时解决这两个问题,让程序能进行下去,但是有时还是会报错,暂时还没找到原因.
mBannerVp.setOnTouchListener(new OnTouchListener() {
@Override
public boolean onTouch(View v, MotionEvent event) {
int action = event.getAction();
switch (action) {
//当按下时,停止给handler发送消息
case MotionEvent.ACTION_DOWN:
mHandler.removeCallbacksAndMessages(null);
break;
//当松开或者手指已经离开ViewPager范围后,会重新发送消息,继续轮播
case MotionEvent.ACTION_CANCEL:
case MotionEvent.ACTION_UP:
mHandler.sendEmptyMessageDelayed(mBannerVp.getCurrentItem(), 1000);
break;
}
return false;
}
});
效果:
⑤最后加上指示器
//初始化指示器
private void initDot() {
LinearLayout.LayoutParams layoutParams = new LinearLayout.LayoutParams(ViewGroup.LayoutParams.WRAP_CONTENT, ViewGroup.LayoutParams.WRAP_CONTENT);
layoutParams.setMargins(0, 0, 8, 0);
for (int i = 0; i < mImageViews.size(); i++) {
ImageView imageView = new ImageView(getContext());
imageView.setImageResource(R.drawable.bg_dot_selected);
mBannerLlIndicator.addView(imageView, layoutParams);
}
//从第一个开始
selectDot(0);
}
//改变指示器的显示,显示当前位置
private void selectDot(int position) {
int size = mImageViews.size();
position = position % size;
for (int i = 0; i < size; i++) {
ImageView childAt = (ImageView) mBannerLlIndicator.getChildAt(i);
if (position == i) {
childAt.setImageResource(R.drawable.bg_dot);
} else {
childAt.setImageResource(R.drawable.bg_dot_selected);
}
}
}
//设置ViewPager的监听器,监听当前pager的位置,并修改指示器位置
mBannerVp.setOnPageChangeListener(new ViewPager.OnPageChangeListener() {
@Override
public void onPageScrolled(int position, float positionOffset, int positionOffsetPixels) {
}
@Override
public void onPageSelected(int position) {
selectDot(position);
}
@Override
public void onPageScrollStateChanged(int state) {
}
});
完成,最终效果如图: