您的位置:首页 > 其它

ViewPager 无限滚动广告栏

2017-03-16 10:46 211 查看
现在很多App在进入的时候,都会在首页的顶部有一个广告栏,这两天跟着视频,我也学习了一把广告栏的制作,具体实现了以下的功能:

1.实现用户左右手动滑动

2.实现广告栏自动轮播

3.实现广告栏点击事件

4.无论是用户手动滑动还是广告栏自动轮播的时候,下方的指示点都会随之改变状态

5.实现用户点击或者拖拽时轮播停止,松手时继续轮播

先上3个效果gif吧:

第一个gif,展示的是功能1和2;



第二个gif,展示的是功能3;



第三个gif展示的是功能5;



那功能4,每个gif都可以看得到。

以上就是所有的效果,那么以下部分,是代码逻辑,我们一部分一部分粘贴出来,很多地方都已经写了非常详细的注释了:

先上布局文件,布局文件就非常简单,activity_main.xml:

<?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.honey.guanggaoview.MainActivity">

<android.support.v4.view.ViewPager
android:id="@+id/vp"
android:layout_width="match_parent"
android:layout_height="180dp"></android.support.v4.view.ViewPager>

<LinearLayout
android:la
4000
yout_width="match_parent"
android:layout_height="wrap_content"
android:layout_alignBottom="@+id/vp"
android:background="#44000000"
android:orientation="vertical"
android:padding="5dp">

<TextView
android:id="@+id/title"
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:layout_gravity="center" />

<LinearLayout
android:id="@+id/point_group"
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:layout_gravity="center"
android:orientation="horizontal"></LinearLayout>
</LinearLayout>
</RelativeLayout>


再上adapter,MyAdapter:
/**
* 功 能:
* 邮 件:honey618717@yeah.net
* 2017/3/16 by:honeyHan
*/

public class MyAdapter extends PagerAdapter {
private Context ctx;
private ArrayList<ImageView> imageViews = new ArrayList<>();
View.OnTouchListener myOnTouchListener;
View.OnClickListener myOnClickListener;

public MyAdapter(Context context, ArrayList<ImageView> imageViewsList, View.OnTouchListener onTouchListener, View.OnClickListener onClickListener) {
ctx = context;
imageViews = imageViewsList;
myOnTouchListener = onTouchListener;
myOnClickListener = onClickListener;
}

@Override
public int getCount() {
return Integer.MAX_VALUE;//这里设置一个最大的数值,用以实现广告栏无限滚动
}

/**
* 相当于listview适配器的getView()---创建某个页面
*
* @param container viewPager本身
* @param position 当前实例化页面的位置
* @return
*/
@Override
public Object instantiateItem(ViewGroup container, int position) {
int realPosition = position % imageViews.size();
ImageView imageView = imageViews.get(realPosition);
ViewParent vp = imageView.getParent();
if (vp != null) {
ViewGroup parent = (ViewGroup) vp;
parent.removeView(imageView);
}
container.addView(imageView);

imageView.setOnTouchListener(myOnTouchListener);

imageView.setTag(position);//设置一个tag用以标记位置
imageView.setOnClickListener(myOnClickListener);

return imageView;
}

/**
* 比较view和object是不是同一个参数
*
* @param view 某个页面
* @param object instantiateItem()返回的结果
* @return
*/
@Override
public boolean isViewFromObject(View view, Object object) {
if (view == object) {
return true;
} else {
return false;
}
}

/**
* 释放资源
*
* @param container viewPager
* @param position 要释放的位置
* @param object 要释放的页面
*/
@Override
public void destroyItem(ViewGroup container, int position, Object object) {
// container.removeView((View) object);
}
}
这里有一个值得注意的地方,就是instantiateItem()和destroyItem()这两个方法,为什么这么说呢,传统的写法是这样的(注意红色标注部分):
/**
* 相当于listview适配器的getView()---创建某个页面
*
* @param container viewPager本身
* @param position 当前实例化页面的位置
* @return
*/
@Override
public Object instantiateItem(ViewGroup container, int position) {
int realPosition = position % imageViews.size();
ImageView imageView = imageViews.get(realPosition);
container.addView(imageView);

imageView.setOnTouchListener(myOnTouchListener);

imageView.setTag(position);//设置一个tag用以标记位置
imageView.setOnClickListener(myOnClickListener);

return imageView;
}

/**
* 释放资源
*
* @param container viewPager
* @param position 要释放的位置
* @param object 要释放的页面
*/
@Override
public void destroyItem(ViewGroup container, int position, Object object) {
container.removeView((View) object);
}
看上面的代码,也是非常容易理解,该加的加,该释放资源的就去释放资源,蛮好的是吧,跑起项目来,左边的滑动也是没有问题的,但是,我在启动demo时,就立马往右滑动,得了,crash。查看报错发现,它说我正在试图把一个已经有父容器的View添加到另一个组件,在添加之前,应该把父容器给移除。上网百度了一番,发现也有小伙伴碰到了我这样的情况,那么根据他们的经验,我把这两个方法改造了一下,感谢那些小伙伴~那么改造之后的这两个方法如下:
/**
* 相当于listview适配器的getView()---创建某个页面
*
* @param container viewPager本身
* @param position 当前实例化页面的位置
* @return
*/
@Override
public Object instantiateItem(ViewGroup container, int position) {
int realPosition = position % imageViews.size();
ImageView imageView = imageViews.get(realPosition);
ViewParent vp = imageView.getParent();
if (vp != null) {
ViewGroup parent = (ViewGroup) vp;
parent.removeView(imageView);
}
container.addView(imageView);

imageView.setOnTouchListener(myOnTouchListener);

imageView.setTag(position);//设置一个tag用以标记位置
imageView.setOnClickListener(myOnClickListener);

return imageView;
}

/**
* 释放资源
*
* @param container viewPager
* @param position 要释放的位置
* @param object 要释放的页面
*/
@Override
public void destroyItem(ViewGroup container, int position, Object object) {
// container.removeView((View) object);
}

最后,在Activity中是这样使用的,MainActivity:
public class MainActivity extends AppCompatActivity {

@BindView(R.id.vp)
ViewPager vp;
@BindView(R.id.title)
TextView title;
@BindView(R.id.point_group)
LinearLayout pointGroup;

private ArrayList<ImageView> imageViews;//创建一个图片集合

private int[] imageViewsId = {//图片资源
R.drawable.timg,
R.drawable.timg2,
R.drawable.timg3
};

private String[] imageViewsTitle = {//标题资源
"小猪佩琪--1",
"小猪佩琪--2",
"小猪佩琪--3"
};

private int lastPosition = 0;//上一次选中的位置

private Handler handler = new Handler() {//利用handler来进行循环轮播,本质其实就是每2s就set下一个item
@Override
public void handleMessage(Message msg) {
super.handleMessage(msg);
int item = vp.getCurrentItem() + 1;
vp.setCurrentItem(item);

handler.sendEmptyMessageDelayed(0, 2000);//延迟2s发一次消息
}
};

private boolean isDragging = false;//判断ViewPager是否处于拖拽的状态

@Override
protected void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
setContentView(R.layout.activity_main);
ButterKnife.bind(this);

//准备数据
imageViews = new ArrayList<>();
for (int i = 0; i < imageViewsId.length; i++) {
//准备图片数据
ImageView imageView = new ImageView(this);
imageView.setBackgroundResource(imageViewsId[i]);
imageViews.add(imageView);

//添加指示点
ImageView point = new ImageView(this);
point.setBackgroundResource(R.drawable.point_selector);
LinearLayout.LayoutParams params = new LinearLayout.LayoutParams(8, 8);
if (i == 0) {//刚进入app时,默认第一个选中
point.setEnabled(true);//显示红色
title.setText(imageViewsTitle[0]);//设置最初启动应用时对应文本的信息
} else {
point.setEnabled(false);//显示灰色
params.leftMargin = 8;//除了第一个点 其他的点都距离左侧8个像素
}
point.setLayoutParams(params);//设置间距
pointGroup.addView(point);
}

vp.setAdapter(new MyAdapter(MainActivity.this, imageViews, new MyOnTouchListener(), new MyOnClickListener()));//绑定适配器
vp.addOnPageChangeListener(new MyPageChangeListener());

int item = Integer.MAX_VALUE / 2 - Integer.MAX_VALUE / 2 % imageViews.size();//要保证是imageViews的整数倍
vp.setCurrentItem(item);//设置中间位置,这样的设置,是为了让viewPager可以向左滑动,因为最初的时候,viewPager处于第0个页面是无法朝左滑动的,所以这里设置在中间,是取到imageViews的整数倍,让它处于整数倍的第0个

handler.sendEmptyMessageDelayed(0, 2000);//发消息开始广告轮询
}

private class MyPageChangeListener implements ViewPager.OnPageChangeListener {
/**
* 当页面滚动的时候回调这个方法
*
* @param position 当前页面的位置
* @param positionOffset 滑动页面的百分比
* @param positionOffsetPixels 在屏幕上滑动的像素
*/
@Override
public void onPageScrolled(int position, float positionOffset, int positionOffsetPixels) {

}

/**
* 当某个页面被选中的时候回调
*
* @param position 被选中的位置
*/
@Override
public void onPageSelected(int position) {
int realPosition = position % imageViews.size();
pointGroup.getChildAt(lastPosition).setEnabled(false);//把上一个红色的设置为灰色
pointGroup.getChildAt(realPosition).setEnabled(true);//把当前被选中的设置为红色
lastPosition = realPosition;

title.setText(imageViewsTitle[realPosition]);//设置对应文本的信息
}

/**
* 当页面滚动状态变化的时候回调
* 静止-->滑动
* 滑动-->静止
*
* @param state
*/
@Override
public void onPageScrollStateChanged(int state) {
if (state == vp.SCROLL_STATE_DRAGGING) {//ViewPager处于拖拽状态时,取消广告轮播事件
isDragging = true;
handler.removeCallbacksAndMessages(null);
} else if (state == vp.SCROLL_STATE_IDLE && isDragging) {//ViewPager处于空闲状态
isDragging = false;
handler.removeCallbacksAndMessages(null);//发消息之前先移除旧的消息
handler.sendEmptyMessageDelayed(0, 2000);//开启广告轮播事件
}
}
}

private class MyOnTouchListener implements View.OnTouchListener {
@Override
public boolean onTouch(View view, MotionEvent motionEvent) {
switch (motionEvent.getAction()) {
case MotionEvent.ACTION_DOWN://当手指按下时,取消handler即取消广告轮播事件
handler.removeCallbacksAndMessages(null);//removeCallbacksAndMessages()的参数为null时,会把消息队列里所有的消息都移除
break;
case MotionEvent.ACTION_UP://手指离开时,在发消息开启广告轮播事件
handler.removeCallbacksAndMessages(null);
handler.sendEmptyMessageDelayed(0, 2000);
break;
}
return false;
}
}

private class MyOnClickListener implements View.OnClickListener {
@Override
public void onClick(View view) {
int position = (int) view.getTag() % imageViews.size();
String text = imageViewsTitle[position];
Toast.makeText(MainActivity.this, "" + text, Toast.LENGTH_LONG).show();
}
}
}
至于其他的point_selector、point_normal、point_choose等资源,均在源码当中,我就不一一贴出来了,有需要的小伙伴可以自行下载:点击下载源码
内容来自用户分享和网络整理,不保证内容的准确性,如有侵权内容,可联系管理员处理 点击这里给我发消息
标签: