首页 > 学院 > 开发设计 > 正文

自定义Banner轮播广告(真*无限循环无卡顿&设置切换速度)

2019-11-07 23:31:26
字体:
来源:转载
供稿:网友

前言自定义控件进入今天的重头戏优化Banner图第一部分viewPager无限循环第二部分手动设置viewPager切换速度源码

前言

Github上有很多轮播广告的源码,比如带着很酷炫动画的FlashView框架。 不过就学习而已,我建议每个人都应该自己多尝试着写一些控件。 以下,是我为小白们分享的简单经验。

自定义控件

先展示下效果图。!由于不会做gif图,只能粗略的展示效果,看官见谅 ![这里写图片描述](http://img.blog.csdn.net/20170225165425535?watermark/2/text/aHR0cDovL2Jsb2cuY3Nkbi5uZXQvZGFiZW5kYW4wNzE0/font/5a6L5L2T/fontsize/400/fill/I0JBQkFCMA==/dissolve/70/gravity/SouthEast)
**简单说下思路,就是由一个展示图片的viewPager和右下角的三个radioButton组成的自定义组合控件。**

送上第一道菜——布局代码

<?xml version="1.0" encoding="utf-8"?><RelativeLayout xmlns:android="http://schemas.android.com/apk/res/android" android:orientation="vertical" android:layout_width="match_parent" android:layout_height="match_parent"> <android.support.v4.view.ViewPager android:id="@+id/pager" android:layout_width="match_parent" android:layout_height="match_parent"> </android.support.v4.view.ViewPager> <RadioGroup android:id="@+id/radio_group" android:layout_alignParentBottom="true" android:layout_alignParentRight="true" android:layout_width="wrap_content" android:layout_height="wrap_content" android:orientation="horizontal" android:layout_marginRight="15dp" android:layout_marginBottom="15dp" > <RadioButton android:id="@+id/rb1" android:layout_width="7dp" android:layout_height="8dp" android:button="@null" android:background="@drawable/circle_advertisement" android:clickable="false" /> <RadioButton android:layout_marginLeft="5dp" android:layout_marginRight="5dp" android:id="@+id/rb2" android:layout_width="7dp" android:layout_height="8dp" android:button="@null" android:background="@drawable/circle_advertisement" android:clickable="false" /> <RadioButton android:id="@+id/rb3" android:layout_width="7dp" android:layout_height="8dp" android:button="@null" android:background="@drawable/circle_advertisement" android:clickable="false" /> </RadioGroup></RelativeLayout>
简单说一说自定义组合控件的使用,其实很简单。1.让你的控件继承一个布局(LinerLayout or RelativeLayout)public class YAdvertisementLayout extends LinearLayout2.重写构造方法,添加你要进行的操作(构造方法有4个,分别对应不同构造方式),尽量在每个构造方法下都要写你初始化的操作。 public YAdvertisementLayout(Context context) { super(context); initView(context); } public YAdvertisementLayout(Context context, AttributeSet attrs) { super(context, attrs); initView(context); } public YAdvertisementLayout(Context context, AttributeSet attrs, int defStyleAttr) { super(context, attrs, defStyleAttr); initView(context); }3.初始化布局,组合控件就加上如下代码,然后就可以对你的控件为所欲为了View v = inflate(context, R.layout.widget_advertisement, this); 接下来的步骤,就是正常findViewById。初始化数据源,对pager进行设置广告图片。

进入今天的重头戏,优化Banner图

1.如何使你的轮播广告无限循环 2. 手动设置viewPager切换速度

第一部分:viewPager无限循环

这个部分得先从viewPager的适配器PagerAdapter讲起 简单介绍下PagerAdapter的各个方法public int getCount();//获取viewPager数据源总个数 public boolean isViewFromObject(View view, Object object);//这个方法是判断对象是否相同,相同直接复用,所以一般都是return view == object;//还有两个方法是要自己重写的 public void destroyItem(ViewGroup container, int position, Object object);//顾名思义,移除对象的操作container.removeView(list.get(position)); public Object instantiateItem(ViewGroup container, int position);//重点方法,在此方法进行初始化操作,设置图片,设置点击时间等等。举个栗子//list是数据源public class MyAdapter extends PagerAdapter { @Override public int getCount() { return list.size(); } @Override public boolean isViewFromObject(View view, Object object) { return view == object; } @Override public void destroyItem(ViewGroup container, int position, Object object) {// container.removeView(list.get(position%list.size())); container.removeView(list.get(position)); } @Override public Object instantiateItem(ViewGroup container, int position) { container.addView(list.get(position)); list.get(position).setImageResource(imgs.get(position)); list.get(position).setOnClickListener(new OnClickListener() { @Override public void onClick(View v) { Toast.makeText(context, "我被点击了", Toast.LENGTH_SHORT).show(); } }); return list.get(position); } }这个就是一般流程。之前有一种无限循环的方式,其实个人认为又low又搞笑。 在getCount()方法中return Integer.MAX_VALUE; 相当于创建无数对象,在初始化对象时container.addView(list.get(position%list.size()));如此一来,反复创建对象,缺点显而易见。那么问题来了,如何能优雅的装逼...**上代码!**/**添加首末图,末图与首图相同,首图为末图*/ imgs.add(R.drawable.match_banner); imgs.add(R.drawable.advertisement_2); imgs.add(R.drawable.advertisement_3); imgs.add(0,R.drawable.advertisement_3); imgs.add(list.size()-1.drawable.match_banner);相信看到这里,你应该有了一些想法。假设三张动图,我们要支持无限滑动,那就设置3+2数据源,编号0| 123 |4(123为展示图,4图与1图相同,这样做是为了让viewPager支持左右滑动,并且欺骗用户的眼睛)在滑动到4时,我们进行一个无动画切换mPager.setCurrentItem(1,false);同理滑动到0时无动画切换3.mPager.setCurrentItem(3,false)注释:在滑动到数据源末端时,viewPager是不支持继续滑动的原理就是这么简单,但是,仅仅这样会有一个bug,是在首末页切换时,会出现,动画并不够平滑,有一种卡顿的感觉。解决方法:mPager.addOnPageChangeListener(this);//在这个方法上做文章,positionOffset这是偏移比例,positionOffsetPixels这是偏移像素@Override public void onPageScrolled(int position, float positionOffset, int positionOffsetPixels) { //原理就是在视觉上滑动完全结束了,进行无动画跳转,如此一来切换过程就没有卡顿效果 if (position == 0 && positionOffset == 0) mPager .setCurrentItem(list.size() - 2, false); else if (position == list.size() - 1 && positionOffset == 0) mPager .setCurrentItem(1, false); }这也是为什么不在public void onPageSelected(int position) ;方法上进行跳转的原因

第二部分:手动设置viewPager切换速度

这个部分设计到反射,修改源码设置时间。本人就不丢人现眼了,直接上源码//添加工具类 import java.lang.reflect.Field;import android.content.Context;import android.support.v4.view.ViewPager;import android.view.animation.Interpolator;import android.widget.Scroller;/** * ViewPager 滚动速度设置 * * @author lyy * */public class ViewPagerScroller extends Scroller { PRivate int mScrollDuration = 2000; // 滑动速度 /** * 设置速度速度 * * @param duration */ public void setScrollDuration(int duration) { this.mScrollDuration = duration; } public ViewPagerScroller(Context context) { super(context); } public ViewPagerScroller(Context context, Interpolator interpolator) { super(context, interpolator); } public ViewPagerScroller(Context context, Interpolator interpolator, boolean flywheel) { super(context, interpolator, flywheel); } @Override public void startScroll(int startX, int startY, int dx, int dy, int duration) { super.startScroll(startX, startY, dx, dy, mScrollDuration); } @Override public void startScroll(int startX, int startY, int dx, int dy) { super.startScroll(startX, startY, dx, dy, mScrollDuration); } public void initViewPagerScroll(ViewPager viewPager) { try { Field mScroller = ViewPager.class.getDeclaredField("mScroller"); mScroller.setaccessible(true); mScroller.set(viewPager, this); } catch (Exception e) { e.printStackTrace(); } }} //使用方式private void fixSpeed() { ViewPagerScroller pagerScroller = new ViewPagerScroller(mPager.getContext()); pagerScroller.setScrollDuration(1000*1);//设置时间,时间越长,速度越慢 pagerScroller.initViewPagerScroll(mPager); }

源码

布局文件,文章开始已经给出了主要布局,下面附上radioButton图片<?xml version="1.0" encoding="UTF-8"?><selector xmlns:android="http://schemas.android.com/apk/res/android"> <item android:drawable="@drawable/circle_advertisement_normal" android:state_checked="false"/> <item android:drawable="@drawable/circle_advertisement_checked" android:state_checked="true"/></selector><?xml version="1.0" encoding="utf-8"?><shape xmlns:android="http://schemas.android.com/apk/res/android" android:shape="oval" android:useLevel="false"> <solid android:color="#ffffff"/> <size android:width="10dp" android:height="10dp"/></shape><?xml version="1.0" encoding="utf-8"?><shape xmlns:android="http://schemas.android.com/apk/res/android" android:shape="oval" android:useLevel="false"> <solid android:color="#80ffffff"/> <size android:width="10dp" android:height="10dp"/></shape>控件源码package app.ui.widget;import android.content.Context;import android.support.v4.view.PagerAdapter;import android.support.v4.view.ViewPager;import android.util.AttributeSet;import android.util.Log;import android.view.MotionEvent;import android.view.View;import android.view.ViewGroup;import android.widget.ImageView;import android.widget.LinearLayout;import android.widget.RadioButton;import android.widget.RadioGroup;import com.wy.sport.R;import java.util.ArrayList;import java.util.List;import android.os.Handler;/** * Created by Yangmu on 2017/2/21. */public class YAdvertisementLayout extends LinearLayout implements ViewPager.OnPageChangeListener { private List<ImageView> list = new ArrayList<>(); private List<Integer> imgs = new ArrayList<>(); private Context context; private ViewPager mPager; private RadioButton mRb1; private RadioButton mRb2; private RadioButton mRb3; private RadioGroup mRadioGroup; private static final String TAG = "ym"; private Handler handler; private Runnable r; private MyAdapter adpter; public YAdvertisementLayout(Context context) { super(context); initView(context); } public YAdvertisementLayout(Context context, AttributeSet attrs) { super(context, attrs); initView(context); } public YAdvertisementLayout(Context context, AttributeSet attrs, int defStyleAttr) { super(context, attrs, defStyleAttr); initView(context); } private void initView(Context context) { this.context = context; View v = inflate(context, R.layout.widget_advertisement, this); mPager = (ViewPager) v.findViewById(R.id.pager); mRadioGroup = (RadioGroup) v.findViewById(R.id.radio_group); mRb1 = (RadioButton) v.findViewById(R.id.rb1); mRb2 = (RadioButton) v.findViewById(R.id.rb2); mRb3 = (RadioButton) v.findViewById(R.id.rb3); initPager(); mPager.addOnPageChangeListener(this); mPager.setCurrentItem(1);// start(); fixSpeed(); } /**修改动画播放速度*/ private void fixSpeed() { ViewPagerScroller pagerScroller = new ViewPagerScroller(mPager.getContext()); pagerScroller.setScrollDuration(1000*1);//设置时间,时间越长,速度越慢 pagerScroller.initViewPagerScroll(mPager); }//开启自动跳转广告功能 public void start() { handler = new Handler(); r = new Runnable() { @Override public void run() { mPager.setCurrentItem(mPager.getCurrentItem()+1);// handler.postDelayed(r,1000*3); } }; handler.postDelayed(r,1000*4); } private void initPager() { for (int i = 0; i < 5; i++) { ImageView iv1 = new ImageView(context); iv1.setScaleType(ImageView.ScaleType.FIT_XY); list.add(iv1); } Log.e(TAG, "initPager: "+list.size() ); // /**添加首末图,末图与首图相同,首图为末图*/ imgs.add(R.drawable.advertisement_3); imgs.add(R.drawable.match_banner); imgs.add(R.drawable.advertisement_2); imgs.add(R.drawable.advertisement_3); imgs.add(R.drawable.match_banner); adpter = new MyAdapter(); mPager.setAdapter(adpter); mRadioGroup.check(mRb1.getId()); } @Override public void onPageScrolled(int position, float positionOffset, int positionOffsetPixels) { Log.e(TAG, "onPageScrolled: position"+position+" positionOffset"+positionOffset+" positionOffsetPixels"+positionOffsetPixels ); if (position == 0 && positionOffset == 0) mPager .setCurrentItem(list.size() - 2, false); else if (position == list.size() - 1 && positionOffset == 0) mPager .setCurrentItem(1, false); } @Override public void onPageSelected(int position) { if (list.size() > 3) { //多于1,才会循环跳转 switch (position) { case 0: mRadioGroup.check(mRb3.getId()); case 1: mRadioGroup.check(mRb1.getId()); break; case 2: mRadioGroup.check(mRb2.getId()); break; case 3: mRadioGroup.check(mRb3.getId()); break; case 4: mRadioGroup.check(mRb1.getId()); } }else { mPager.setCurrentItem(1, false); } } @Override public void onPageScrollStateChanged(int state) { switch(state){ case 1: //滑动状态 handler.removeCallbacks(r); break; case 2://滑动结束状态 handler.postDelayed(r,1000*4); break; default: break; } } public class MyAdapter extends PagerAdapter { @Override public int getCount() { return list.size(); } @Override public boolean isViewFromObject(View view, Object object) { return view == object; } @Override public void destroyItem(ViewGroup container, int position, Object object) {// container.removeView(list.get(position%list.size())); container.removeView(list.get(position)); } @Override public Object instantiateItem(ViewGroup container, int position) { container.addView(list.get(position)); Log.e(TAG, "instantiateItem: position"+position ); list.get(position).setImageResource(imgs.get(position)); list.get(position).setOnClickListener(new OnClickListener() { @Override public void onClick(View v) {// Toast.makeText(context, "呵呵", Toast.LENGTH_SHORT).show(); } }); return list.get(position); } } /**对外借口,通过此方法修改图片*/ public void changerImages(int imgs[]){ this.imgs.clear(); for (int i = 0; i < imgs.length; i++) { this.imgs.add(imgs[i]); } this.imgs.add(0,imgs[imgs.length-1]); this.imgs.add(this.imgs.size()-1,imgs[0]); Log.e(TAG, "changerImages: 更新完毕" ); adpter.notifyDataSetChanged(); }}
发表评论 共有条评论
用户名: 密码:
验证码: 匿名发表