如何单手撸一个Banner活动图
2017-01-19 本文已影响424人
lukUrself
最近看到公司项目用的是一个webView实现的Banner,个人觉得用户体验不怎么好,第一:用户点击banner图还可以轻微的上下滑动(难适配的原因);第二:用户息屏之后再打开,webView会闪一下,这个原因还没找到,知道的同学可以指教一下。这肯定不能忍,对不对!网上也有很多这方面的文章了吧,但那究竟是别人的,自己写的应该会更爽一些吧。
首先,分析下需求:
- 几张图片过一段时间就切换一次;
- 当触摸图片,图片暂停切换;
大概思路大家都想到用ViewPager去实现 --> ok,需求分析完毕。下面先编写XML:
<pre>
<RelativeLayout xmlns:android="http://schemas.android.com/apk/res/android"
xmlns:tools="http://schemas.android.com/tools"
android:layout_width="match_parent"
android:layout_height="200dp"
tools:context="test.nicely.com.application.MainActivity">
<android.support.v4.view.ViewPager
android:id="@+id/view_pager"
android:layout_width="match_parent"
android:layout_height="match_parent">
</android.support.v4.view.ViewPager>
<RelativeLayout
android:layout_width="match_parent"
android:layout_height="wrap_content"
android:layout_alignParentBottom="true"
android:background="#55000000"
android:padding="5dp">
<TextView
android:id="@+id/tv_img_desc"
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:layout_centerHorizontal="true"
android:text="banner"
android:textColor="#ffffff"
android:textSize="16sp"/>
// 小圆点的容器,用来动态添加
<LinearLayout
android:layout_centerVertical="true"
android:id="@+id/dot_container"
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:layout_alignParentRight="true"
android:layout_marginRight="8dp"
android:orientation="horizontal">
</LinearLayout>
</RelativeLayout>
</RelativeLayout>
</pre>
直接贴代码吧 ,毕竟Talk is cheap ,接下看MainActivity类的代码逻辑处理:
public class MainActivity extends AppCompatActivity implements ViewPager.OnPageChangeListener,
View.OnTouchListener {
private String[] arrUrl = {AppConstant.baseUrl + "teacher_1.png",
AppConstant.baseUrl + "teacher_2.png",
AppConstant.baseUrl + "teacher_3.png"};
// mock banner Title
private int[] resTxt = {R.string.title_1, R.string.title_2, R.string.title_3};
private ViewPager mViewPager;
private LinearLayout mDot_container;
private MyPagerAdapter mAdapter;
private TextView mTvImgDesc;
private int mPrePosition;
//private AutoCycleTask mAutoCycleTask;
@Override
protected void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
setContentView(R.layout.activity_main);
// 设置全透明的状态栏
CommonUtils.setTransparentStatus(this);
initView();
performDot();
performViewPager();
}
private void initView() {
mViewPager = (ViewPager) findViewById(R.id.view_pager);
mDot_container = (LinearLayout) findViewById(R.id.dot_container);
mTvImgDesc = (TextView) findViewById(R.id.tv_img_desc);
}
private void performDot() {
for (int i = 0; i < resTxt.length; i++) {
View dotView = new View(this);
dotView.setBackgroundResource(R.drawable.dot);
LinearLayout.LayoutParams params = new LinearLayout.LayoutParams(15, 15);
// 第一个原点不设置左边距
if (i != 0) {
params.leftMargin = 15;
}
dotView.setEnabled(false);
dotView.setLayoutParams(params);
mDot_container.addView(dotView);
}
}
private void performViewPager() {
if (mAdapter == null) {
mAdapter = new MyPagerAdapter(this, arrUrl);
}
mViewPager.setAdapter(mAdapter);
mViewPager.addOnPageChangeListener(this);
mViewPager.setOnTouchListener(this);
// Integer.MAX_VALUE / 2 有可能是任何item的位置 - 余数则让他和集合的pos=0的位置吻合
int item = Integer.MAX_VALUE / 2 - (Integer.MAX_VALUE / 2 % resTxt.length);
mViewPager.setCurrentItem(item);// 设置初始位置
// 将第一个圆点设置选中的颜色
mDot_container.getChildAt(mPrePosition).setEnabled(true);
mTvImgDesc.setText(resTxt[mPrePosition]);
// 实现 自动切换
autoCycle();
}
private void autoCycle() {
if (mAutoCycleTask == null) {
mAutoCycleTask = new AutoCycleTask();
}
mAutoCycleTask.start();
}
@Override
public void onPageScrolled(int position, float positionOffset, int positionOffsetPixels) {
Log.d("nicely","position===" + position + "positionOffset===" + positionOffset + "positionOffsetPixels===" + positionOffsetPixels);
}
@Override
public void onPageSelected(int position) {
int newPos = position % mDot_container.getChildCount();
mDot_container.getChildAt(mPrePosition).setEnabled(false);
mDot_container.getChildAt(newPos).setEnabled(true);
mTvImgDesc.setText(resTxt[newPos]);
mPrePosition = newPos;
}
@Override
public void onPageScrollStateChanged(int state) {
}
}
上面的逻辑也比较简单,简单梳理一下: 动态添加小圆点到线性布局当中;监听Viewpager选中的item动态切换小圆点的选中位置;再把PagerAdapter的subclass代码贴上来:
/*
* @项目名: Application
* @包名: test.nicely.com.application
* @文件名: MyPagerAdapter
* @创建者: lz
* @创建时间: 2017/1
* @描述: TODO
*/
public class MyPagerAdapter extends PagerAdapter {
private static final String TAG = "MyPagerAdapter";
private Context mContext;
private String[] mArrUrl;
public MyPagerAdapter(Context context, String[] arrUrl) {
mContext = context;
mArrUrl = arrUrl;
}
@Override
public int getCount() {
// return arrUrl.lenth;
// 循环用
return Integer.MAX_VALUE;
}
@Override
public boolean isViewFromObject(View view, Object object) {
return view == object;
}
@Override
public Object instantiateItem(ViewGroup container, int position) {
// position此时的总大小是Integer.MAX_VALUE,需要转换(position本来就跟自然数差1了)
// 循环用
position = position % mArrUrl.length;
ImageView imageView = new ImageView(mContext);
imageView.setScaleType(ImageView.ScaleType.FIT_XY);
// 使用picasso加载图片
Picasso.with(mContext).load(mArrUrl[position]).error(R.mipmap.error).into(imageView);
container.addView(imageView);
return imageView;
}
@Override
public void destroyItem(ViewGroup container, int position, Object object) {
container.removeView((View) object);
}
}
到此为止,就差我们想要的循环没有实现了.这里有些同学可能会在这里踩坑----> 高能预警!!!有些同学在这个方法里instantiateItem使用的是从外边传的View进来,这时候你一切换view ,就会报下边这个错误:
This view has a parent...
可能是大家对Viewpager不熟悉,加上自己的想当然所导致的哈,接下来我们就要实现动态切换了:实现这个定时器功能.
android中有许多方式,什么Timer ,alarmmanager,Handler等等.
我这里选择是Handler,ok,老套路,直接贴实现定时器逻辑代码(AutoCycleTask类是MainActivity的内部类),自定义了一个start()和stop()方法:
class AutoCycleTask extends Handler implements Runnable {
@Override
public void run() {
// 设置轮播下一图
int currentItem = mViewPager.getCurrentItem();
mViewPager.setCurrentItem(++currentItem);
postDelayed(this, 2000);
}
public void start() {
postDelayed(this, 2000);
}
public void stop() {
removeCallbacks(this);
}
}
接下来在界面销毁时,将handler消息队列中的消息移除:
@Override
protected void onDestroy() {
super.onDestroy();
mAutoCycleTask.removeCallbacksAndMessages(null);
mAutoCycleTask = null;
}
最后还差一个需求点没完成
- 当触摸图片,图片暂停切换.
这不就监听Viewpager的触摸事件就可以搞定了:
@Override
public boolean onTouch(View v, MotionEvent event) {
switch (event.getAction()) {
case MotionEvent.ACTION_DOWN:
mAutoCycleTask.stop();
break;
case MotionEvent.ACTION_MOVE:
mAutoCycleTask.stop();
break;
case MotionEvent.ACTION_UP:
mAutoCycleTask.start();
break;
}
return false;
}
贴上截图(简书暂时不会搞GIF图 [尴尬]):
Screenshot_20170119-200739.png