如何单手撸一个Banner活动图

最近看到公司项目用的是一个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图 [尴尬]):

《如何单手撸一个Banner活动图》 Screenshot_20170119-200739.png

Done! 由于知识水平有限,欢迎各位同学指出”辣眼睛”之处,哈哈, 最后祝大家周末愉快!

    原文作者:lukUrself
    原文地址: https://www.jianshu.com/p/63801f2092e3
    本文转自网络文章,转载此文章仅为分享知识,如有侵权,请联系博主进行删除。
点赞