android ViewPager制作广告栏

本文介绍了如何使用Android的ViewPager组件来创建一个广告栏,包括用户可左右滑动切换、自动轮播、暂停播放等功能。通过结合RadioButton实现单选控制,但实际应用中通常省略此功能,改为使用图片作为圆点指示器。文章提到了实现自动切换的几种方法,并指出在手动滑动和自动播放同时存在时可能出现的问题。
摘要由CSDN通过智能技术生成

  我们常用的app中,首页多半都会展示广告的地方(特别是电商产品),比如下面这张图中被圈出的部分,就是我所说的广告栏


广告栏的需求就是:展示活动的广告图,

(1)用户可以左右滑动来选择;

(2)广告可以自动轮流播放,即过一定时间,展示下一张广告;

(3)当用户手指触摸到广告栏时,自动播放停止

(5)图片右下角的圆点和广告图播放位置显示一致,即:播放第一种,第一个圆点亮,其他都暗

(6)圆点可以点击,即:点第三个圆点,展示第三张广告图



实现

看到需求1,首先想到控件ViewPager,看到需求6,想到的是右下角的圆点是RadioButton,这样很容易就控制了单选。先满足这两个要求的实现吧!

广告栏的布局:

main_activity.xml

<?xml version="1.0" encoding="utf-8"?>
<RelativeLayout xmlns:android="http://schemas.android.com/apk/res/android"
    android:layout_width="wrap_content"
    android:layout_height="wrap_content"
    android:orientation="vertical">

    <android.support.v4.view.ViewPager
        android:id="@+id/viewpager"
        android:layout_width="match_parent"
        android:layout_height="400dp"
        android:background="#696969" />

    <include layout="@layout/radio_layout" />

</RelativeLayout>
radio_layout.xml就是单选按钮的布局:

<?xml version="1.0" encoding="utf-8"?>
<RadioGroup xmlns:android="http://schemas.android.com/apk/res/android"
    android:id="@+id/RadioGroup"
    android:layout_width="wrap_content"
    android:layout_height="wrap_content"
    android:layout_alignBottom="@+id/viewpager"
    android:layout_alignParentRight="true"
    android:layout_marginBottom="5dp"
    android:orientation="horizontal">

    <RadioButton
        android:id="@+id/radio1"
        android:layout_width="wrap_content"
        android:layout_height="wrap_content"
        android:button="@null"
        android:checked="true"
        android:drawableLeft="@drawable/radiobutton_selector"
        android:padding="2dp" />

    <RadioButton
        android:id="@+id/radio2"
        android:layout_width="wrap_content"
        android:layout_height="wrap_content"
        android:button="@null"
        android:drawableLeft="@drawable/radiobutton_selector"
        android:padding="2dp" />

    <RadioButton
        android:id="@+id/radio3"
        android:layout_width="wrap_content"
        android:layout_height="wrap_content"
        android:button="@null"
        android:drawableLeft="@drawable/radiobutton_selector"
        android:padding="2dp" />

    <RadioButton
        android:id="@+id/radio4"
        android:layout_width="wrap_content"
        android:layout_height="wrap_content"
        android:button="@null"
        android:drawableLeft="@drawable/radiobutton_selector"
        android:padding="2dp" />
</RadioGroup>

ViewPager的具体操作,比如初始化ViewPager,然后setAdapter这些就不说了。只要会使用ViewPager,需求1就做完了,不过为了讲下一点内容,我这里还是复制代码吧,
public class ViewPagerAdapter extends PagerAdapter {

   //界面列表  
    private List<View> views;  
      
    public ViewPagerAdapter (List<View> views){  
        this.views = views;  
    }  
    
    @Override  
    public int getCount() {  
        return views==null?0:views.size();
    }
     
    @Override
    public void destroyItem(View container, int position, Object arg2) {
        ((ViewPager)container).removeView(views.get(position));
    }

    @Override
    public Object instantiateItem(View container, int position) {
        ((ViewPager)container).addView(views.get(position), 0);
        return views.get(position);
    }
  
    @Override
    public boolean isViewFromObject(View arg0, Object arg1) {  
        return (arg0 == arg1);  
    }  
    
   @Override
//    public void destroyItem(ViewGroup container, int position, Object object) {
//        container.removeView((View) object);
//    }
//
//    @Override
//    public Object instantiateItem(ViewGroup container, int position) {
//        /**
//         * 设置具体需要填充的View对象
//         */
//        int i = position % views.size();
//        container.addView(views.get(i));
//        return views.get(i);
//    }
}
ViewPager的初始化,和setAdapter代码:
      views = new ArrayList<>();
      LinearLayout.LayoutParams mParams = new LinearLayout.LayoutParams(LinearLayout.LayoutParams.WRAP_CONTENT,
            LinearLayout.LayoutParams.WRAP_CONTENT);

      for (int i = 0; i < picPath.length; i++) {
         ImageView iv = new ImageView(this);
         iv.setLayoutParams(mParams);
         iv.setImageResource(pics[i]);
         iv.setScaleType(ScaleType.FIT_XY);
         views.add(iv);
      }
      vpAdapter = new ViewPagerAdapter(views);
      vp.setAdapter(vpAdapter);
      上面这种情况就是我们一般使用的ViewPager,我们的list有多少数据就传过去多少数据,在Adapter的getCount()方法里面,list.size()来决定我们ViewPager显示的数据的条数,这种情况下,当 你已经右滑到最后一张的时候,就不能再右滑动,左滑动到第一张的时候,就不能再向左滑动了。
      我们生活中,更多的是让用户可以循环滑动,向右边滑动到最后一张的时候,如果还 右滑,就显示第一张,也就是可以无限的左右滑动,左滑类似,滑动到第一张还滑动的话,就显示最后一张,然后一直循环。
      这种情况下,我第一想到的是监听ViewPager的滑动,结果它里面的方法不止调用一次,不好控制,最后参考网友的做法,主要在Adapter去控制

public class ViewPagerAdapter extends PagerAdapter {

   //界面列表  
    private List<View> views;  
      
    public ViewPagerAdapter (List<View> views){  
        this.views = views;  
    }  
    
    @Override  
    public int getCount() {  
        return Integer.MAX_VALUE; //设置成最大,使用户看不到边界  
//        return views==null?0:views.size();
    }
     
    @Override
    public void destroyItem(View container, int position, Object arg2) {
        ((ViewPager)container).removeView(views.get(position % views.size()));
//        ((ViewPager)container).removeView(views.get(position));
    }

    @Override
    public Object instantiateItem(View container, int position) {
        ((ViewPager)container).addView(views.get(position % views.size()), 0);
        return views.get(position % views.size());
//        ((ViewPager)container).addView(views.get(position), 0);
//        return views.get(position);
    }
  
    @Override
    public boolean isViewFromObject(View arg0, Object arg1) {  
        return (arg0 == arg1);  
    }  
}
       上面的代码中,注释的地方就是不循环的代码,注意:我们在getCount()里面给的是最大的条数,这样保证ViewPager可以一直左滑动右滑动,让数据循环显示重点在views.get(position%views.size())这句代码上,给用户的感觉就是在循环显示,其实呢,不是循环,你打印position就知道,它一直在递增,我们只是让views.get()出来的数据是循环的(views.get出来的数据:1,2,3,......list.size(),1,2,3.....list.size()这样实现循环的)。而要实现一开始就可以左滑动,网友的办法是 vp.setCurrentItem(views.size()*10);这样只是一个障眼法,让用户看到的第一张position就不是0开始的。参考

       为了让ViewPager右下角的圆点跟上ViewPager(也就是需求5),我们需要监听ViewPager,代码如下:
vp.setOnPageChangeListener(new OnPageChangeListener() {

         @Override
         public void onPageSelected(int position) {
            position=position%views.size();//循环时,一定要有这句,不然会越界异常
            radioButton = (RadioButton) group.getChildAt(position);
            radioButton.setChecked(true);
         }

         @Override
         public void onPageScrolled(int positon, float arg1, int arg2) {
         }
         @Override
         public void onPageScrollStateChanged(int state) {

         }
      });

当ViewPager要实现循环,我们要注意,使用position的地方都要:positon=position%views.size();


需求6:初始化RadioGroup,在监听RadioGroup的时候,去判断是哪个RadioButton,从而控制ViewPager显示那一张广告图  viewpager.setCurrentItem(x)
RadioGroup.setOnCheckedChangeListener(new OnCheckedChangeListener() {

      @Override
      public void onCheckedChanged(RadioGroup group, int checkId) {
         switch (checkId) {
            case R.id.radio1:
               vp.setCurrentItem(0);
               break;
            case R.id.radio2:
               vp.setCurrentItem(1);
               break;
            case R.id.radio3:
               vp.setCurrentItem(2);
               break;
            case R.id.radio4:
               vp.setCurrentItem(3);
               break;
            default:
               break;
         }
      }
   });
}

   一般情况下,网页版的会考虑上面的需求(6),手机端很少有app会这样做,可能是手机页面本身就小,圆点就更小了,让用户可点的话,用户很容易就会点击到广告图,所以这种效果不佳。所以我们去掉需求6,那么圆点就是图片实现,每次ViewPager显示的图片改变的时候,都要调用下面的setCurPage(intpage, intcount)方法,去改变圆点的显示效果,page是当前页,count是广告图片数量,这样还有一个好处就是,可以根据接口获得的广告图片数量,来决定圆点的数量,比直接在布局中写死灵活很多。

  这样广告栏的布局变成:

<?xml version="1.0" encoding="utf-8"?>
<RelativeLayout xmlns:android="http://schemas.android.com/apk/res/android"
    android:layout_width="wrap_content"
    android:layout_height="wrap_content"
    android:orientation="vertical">

    <android.support.v4.view.ViewPager
        android:id="@+id/viewpager"
        android:layout_width="match_parent"
        android:layout_height="400dp"
        android:background="#696969" />


    <LinearLayout
        android:id="@+id/three_tv_viewpager_dot1"
        android:layout_width="wrap_content"
        android:layout_height="wrap_content"
        android:layout_alignParentBottom="true"
        android:layout_centerInParent="true"
        android:orientation="horizontal"
        android:layout_marginBottom="12dp"/>
</RelativeLayout>

里面的LinearLayout是用来装圆点
LinearLayout dot = (LinearLayout) view.findViewById(R.id.three_tv_viewpager_dot1);

public void setCurPage(int page, int count) {
    try {
        dot.removeAllViews();
        for (int i = 0; i < count; i++) {
            ImageView imgCur = new ImageView(getActivity());
            imgCur.setBackgroundResource(R.drawable.news_dot1);
            imgCur.setId(i);
            LinearLayout.LayoutParams lp = new LinearLayout.LayoutParams(
                    -2, -2);
            lp.rightMargin = 5;
            if (imgCur.getId() == page) {
                imgCur.setBackgroundResource(R.drawable.news_dot);
            }
            dot.addView(imgCur, lp);
        }
    } catch (Exception e) {
        // TODO: handle exception
    }
}

需求2,自动播放广告栏

(1)定义一个全局变量:private int currentItem; // 当前页面

(这是为了记录当前页面,这样自动播放的时候才会知道该显示哪一页,所以单选按钮切换的时候viewpager.setCurrentItem(x);更改当前页面的currentItem 值:currentItem = x,滑动改变页面的时候也要写:currentItem = position;)

(2)自动滚动肯定要开线程,线程做的就是停一点时间(比如2秒),完了之后告诉Hanlder去改变显示的页面:

private Handler handler = new Handler() {
   public void handleMessage(android.os.Message msg) {
      // 设置当前页面
      vp.setCurrentItem(currentItem);
   };
};

(3)在onStart()里面开启ScheduledExecutorService,再onPause()里面关闭ScheduledExecutorService

private ScheduledExecutorService scheduledExecutorService;
@Override
protected void onStart() {
   super.onStart();
   scheduledExecutorService = Executors.newSingleThreadScheduledExecutor();
   // 每隔2秒钟切换一张图片
   scheduledExecutorService.scheduleWithFixedDelay(new ViewPagerTask(), 2, 2, TimeUnit.SECONDS);
   // scheduleAtFixedRate(command, initialDelay, period, unit);
   // command:执行线程 initialDelay:初始化延时 period:前一次执行结束到下一次执行开始的间隔时间(间隔执行延迟时间)
   // unit:计时单位
}
@Override
protected void onStop() {
   if (scheduledExecutorService!=null){
      scheduledExecutorService.shutdown();
   }
   super.onStop();
}
// 切换图片
private class ViewPagerTask implements Runnable {
   @Override
   public void run() {
      currentItem = (currentItem + 1) % pics.length;
      // 更新界面
      handler.obtainMessage().sendToTarget();
      // message对象sendToTarget(),handler对象sendMessage();
   }
}

这就能实现图片像广告一样自动播放,也可以滑动选择。


实现暂停一段时间再显示,这个功能有很多方法,上面讲到的ScheduledExecutorService可以,Timer计时器也可以,或者直接用handler设置延迟时间有可以做到。


private int currentItem=0; // 当前页面

/**
 * 焦点图自动滚动方法
 *
 * @param delayTimeInMills
 */
private final int SCROLL_WHAT = 1;
private boolean mIsStop = false;// 焦点图触摸暂停监听
private Handler handler = new Handler() {
   @Override
   public void handleMessage(Message msg) {
      super.handleMessage(msg);
      switch (msg.what) {
         case SCROLL_WHAT:
            if (currentItem == views.size()) {
               currentItem = 0;
            }
            //点击图片时,自动切换暂停
            if (!mIsStop) {
               currentItem++;
               vp.setCurrentItem(currentItem % views.size());
            }
            sendScrollMessage(4000);
            break;
      }
   }
};
private void sendScrollMessage(long delayTimeInMills) {
   /** remove messages before, keeps one message is running at most **/
   handler.removeMessages(SCROLL_WHAT);
   handler.sendEmptyMessageDelayed(SCROLL_WHAT, delayTimeInMills);
}

setAdapter之后就开启自动切换,

vp.setAdapter(vpAdapter);
vp.setCurrentItem(0);// 默认显示第一张
sendScrollMessage(300);// 自动切换启动

ViewPager触摸监听,实现触摸的时候,暂停自动切换,即功能3

//ViewPager 触摸事件
vp.setOnTouchListener(new View.OnTouchListener() {

   @Override
   public boolean onTouch(View arg0, MotionEvent event) {
      int action = event.getAction();
      if (action == MotionEvent.ACTION_DOWN) {
         mIsStop = true;
      } else if (action == MotionEvent.ACTION_UP) {
         mIsStop = false;
      }
      return false;
   }
});

目前:手动循环滑动加上自动播放共同的效果,会出现异常,有待解决




左右滑动,不支持循环滑动,自动播放,可以点击右下角切换ViewPager显示图的:

源代码:http://download.csdn.net/detail/qq_30716173/9273873


评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值