Android广告页循环播放

 

  摘要:项目要求做一个广告页,实现几秒更换一次广告页,下方还有指示第几张广告页,同样也支持手动左滑或右滑。

 

  1.准备好粘贴5个有关广告页的类。

    ①BaseViewPager==>自定义高度的ViewPager

 1 public class BaseViewPager extends ViewPager {
 2     private boolean scrollable = true;
 3 
 4     public BaseViewPager(Context context) {
 5         super(context);
 6     }
 7 
 8     public BaseViewPager(Context context, AttributeSet attrs) {
 9         super(context, attrs);
10     }
11 
12     /**
13      * 设置viewpager是否可以滚动
14      * 
15      * @param enable
16      */
17     public void setScrollable(boolean enable) {
18         scrollable = enable;
19     }
20 
21     @Override
22     public boolean onInterceptTouchEvent(MotionEvent event) {
23         if (scrollable) {
24             return super.onInterceptTouchEvent(event);
25         } else {
26             return false;
27         }
28     }
29 }
View Code

 

    ②CycleViewPager==>实现可循环、可轮播的viewPager

  1 @SuppressLint("NewApi")
  2 public class CycleViewPager extends Fragment implements OnPageChangeListener {
  3     
  4     private List<ImageView> imageViews = new ArrayList<ImageView>();
  5     private ImageView[] indicators;
  6     private FrameLayout viewPagerFragmentLayout;
  7     private LinearLayout indicatorLayout; // 指示器
  8     private BaseViewPager viewPager;
  9     private BaseViewPager parentViewPager;
 10     private ViewPagerAdapter adapter;
 11     private CycleViewPagerHandler handler;
 12     private int time = 5000; // 默认轮播时间
 13     private int currentPosition = 0; // 轮播当前位置
 14     private boolean isScrolling = false; // 滚动框是否滚动着
 15     private boolean isCycle = false; // 是否循环
 16     private boolean isWheel = false; // 是否轮播
 17     private long releaseTime = 0; // 手指松开、页面不滚动时间,防止手机松开后短时间进行切换
 18     private int  WHEEL = 100; // 转动
 19     private int WHEEL_WAIT = 101; // 等待
 20     private ImageCycleViewListener mImageCycleViewListener;
 21     private List<MyImage> infos;
 22 
 23     @Override
 24     public View onCreateView(LayoutInflater inflater, ViewGroup container,
 25             Bundle savedInstanceState) {
 26         View view = LayoutInflater.from(getActivity()).inflate(
 27                 R.layout.view_cycle_viewpager_contet, null);
 28 
 29         viewPager = (BaseViewPager) view.findViewById(R.id.viewPager);
 30         indicatorLayout = (LinearLayout) view.findViewById(R.id.layout_viewpager_indicator);//就是那个白点吧
 31         viewPagerFragmentLayout = (FrameLayout) view.findViewById(R.id.layout_viewager_content);
 32 
 33         handler = new CycleViewPagerHandler(getActivity()) {
 34 
 35             @Override
 36             public void handleMessage(Message msg) {
 37                 super.handleMessage(msg);
 38                 if (msg.what == WHEEL && imageViews.size() != 0) {
 39                     if (!isScrolling) {
 40                         int max = imageViews.size() + 1;
 41                         int position = (currentPosition + 1) % imageViews.size();
 42                         viewPager.setCurrentItem(position, true);
 43                         if (position == max) { // 最后一页时回到第一页
 44                             viewPager.setCurrentItem(1, false);
 45                         }
 46                     }
 47 
 48                     releaseTime = System.currentTimeMillis();
 49                     handler.removeCallbacks(runnable);
 50                     handler.postDelayed(runnable, time);
 51                     return;
 52                 }
 53                 if (msg.what == WHEEL_WAIT && imageViews.size() != 0) {
 54                     handler.removeCallbacks(runnable);
 55                     handler.postDelayed(runnable, time);
 56                 }
 57             }
 58         };
 59 
 60         return view;
 61     }
 62 
 63     public void setData(List<ImageView> views, List<MyImage> list, ImageCycleViewListener listener) {
 64         setData(views, list, listener, 0);
 65     }
 66 
 67     /**
 68      * 初始化viewpager
 69      * 
 70      * @param views
 71      *            要显示的views
 72      * @param showPosition
 73      *            默认显示位置
 74      */
 75     public void setData(List<ImageView> views, List<MyImage> list, ImageCycleViewListener listener, int showPosition) {
 76         mImageCycleViewListener = listener;
 77         infos = list;
 78         this.imageViews.clear();
 79 
 80         if (views.size() == 0) {
 81             viewPagerFragmentLayout.setVisibility(View.GONE);
 82             return;
 83         }
 84 
 85         for (ImageView item : views) {
 86             this.imageViews.add(item);
 87         }
 88 
 89         int ivSize = views.size();
 90 
 91         // 设置指示器
 92         indicators = new ImageView[ivSize];
 93         if (isCycle)
 94             indicators = new ImageView[ivSize - 2];
 95         indicatorLayout.removeAllViews();
 96         for (int i = 0; i < indicators.length; i++) {
 97             View view = LayoutInflater.from(getActivity()).inflate(
 98                     R.layout.view_cycle_viewpager_indicator, null);
 99             indicators[i] = (ImageView) view.findViewById(R.id.image_indicator);
100             indicatorLayout.addView(view);
101         }
102 
103         adapter = new ViewPagerAdapter();
104 
105         // 默认指向第一项,下方viewPager.setCurrentItem将触发重新计算指示器指向
106         setIndicator(0);
107 
108         viewPager.setOffscreenPageLimit(3);
109         viewPager.setOnPageChangeListener(this);
110         viewPager.setAdapter(adapter);
111         if (showPosition < 0 || showPosition >= views.size())
112             showPosition = 0;
113         if (isCycle) {
114             showPosition = showPosition + 1;
115         }
116         viewPager.setCurrentItem(showPosition);
117 
118     }
119 
120     /**
121      * 设置指示器居中,默认指示器在右方
122      */
123     public void setIndicatorCenter() {
124         RelativeLayout.LayoutParams params = new RelativeLayout.LayoutParams(
125                 RelativeLayout.LayoutParams.WRAP_CONTENT,
126                 RelativeLayout.LayoutParams.WRAP_CONTENT);
127         params.addRule(RelativeLayout.ALIGN_PARENT_BOTTOM);
128         params.addRule(RelativeLayout.CENTER_HORIZONTAL);
129         indicatorLayout.setLayoutParams(params);
130     }
131     /**
132      * 是否循环,默认不开启,开启前,请将views的最前面与最后面各加入一个视图,用于循环
133      * 
134      * @param isCycle
135      *            是否循环
136      */
137     public void setCycle(boolean isCycle) {
138         this.isCycle = isCycle;
139     }
140 
141     /**
142      * 是否处于循环状态
143      * 
144      * @return
145      */
146     public boolean isCycle() {
147         return isCycle;
148     }
149 
150     /**
151      * 设置是否轮播,默认不轮播,轮播一定是循环的
152      * 
153      * @param isWheel
154      */
155     public void setWheel(boolean isWheel) {
156         this.isWheel = isWheel;
157         isCycle = true;
158         if (isWheel) {
159             handler.postDelayed(runnable, time);
160         }
161     }
162 
163     /**
164      * 是否处于轮播状态
165      * 
166      * @return
167      */
168     public boolean isWheel() {
169         return isWheel;
170     }
171 
172     final Runnable runnable = new Runnable() {
173 
174         @Override
175         public void run() {
176             if (getActivity() != null && !getActivity().isFinishing()
177                     && isWheel) {
178                 long now = System.currentTimeMillis();
179                 // 检测上一次滑动时间与本次之间是否有触击(手滑动)操作,有的话等待下次轮播
180                 if (now - releaseTime > time - 500) {
181                     handler.sendEmptyMessage(WHEEL);
182                 } else {
183                     handler.sendEmptyMessage(WHEEL_WAIT);
184                 }
185             }
186         }
187     };
188 
189     /**
190      * 释放指示器高度,可能由于之前指示器被限制了高度,此处释放
191      */
192     public void releaseHeight() {
193         getView().getLayoutParams().height = RelativeLayout.LayoutParams.MATCH_PARENT;
194         refreshData();
195     }
196 
197     /**
198      * 设置轮播暂停时间,即没多少秒切换到下一张视图.默认5000ms
199      * 
200      * @param time
201      *            毫秒为单位
202      */
203     public void setTime(int time) {
204         this.time = time;
205     }
206 
207     /**
208      * 刷新数据,当外部视图更新后,通知刷新数据
209      */
210     public void refreshData() {
211         if (adapter != null)
212             adapter.notifyDataSetChanged();
213     }
214 
215     /**
216      * 隐藏CycleViewPager
217      */
218     public void hide() {
219         viewPagerFragmentLayout.setVisibility(View.GONE);
220     }
221 
222     /**
223      * 返回内置的viewpager
224      * 
225      * @return viewPager
226      */
227     public BaseViewPager getViewPager() {
228         return viewPager;
229     }
230 
231     /**
232      * 页面适配器 返回对应的view
233      * 
234      * @author Yuedong Li
235      * 
236      */
237     private class ViewPagerAdapter extends PagerAdapter {
238 
239         @Override
240         public int getCount() {
241             return imageViews.size();
242         }
243 
244         @Override
245         public boolean isViewFromObject(View arg0, Object arg1) {
246             return arg0 == arg1;
247         }
248 
249         @Override
250         public void destroyItem(ViewGroup container, int position, Object object) {
251             container.removeView((View) object);
252         }
253 
254         @Override
255         public View instantiateItem(ViewGroup container, final int position) {
256             ImageView v = imageViews.get(position);
257             if (mImageCycleViewListener != null) {
258                 v.setOnClickListener(new OnClickListener() {
259                     
260                     @Override
261                     public void onClick(View v) {
262                         mImageCycleViewListener.onImageClick(infos.get(currentPosition - 1), currentPosition, v);
263                     }
264                 });
265             }
266             container.addView(v);
267             return v;
268         }
269 
270         @Override
271         public int getItemPosition(Object object) {
272             return POSITION_NONE;
273         }
274     }
275 
276     @Override
277     public void onPageScrollStateChanged(int arg0) {
278         if (arg0 == 1) { // viewPager在滚动
279             isScrolling = true;
280             return;
281         } else if (arg0 == 0) { // viewPager滚动结束
282             if (parentViewPager != null)
283                 parentViewPager.setScrollable(true);
284 
285             releaseTime = System.currentTimeMillis();
286 
287             viewPager.setCurrentItem(currentPosition, false);
288             
289         }
290         isScrolling = false;
291     }
292 
293     @Override
294     public void onPageScrolled(int arg0, float arg1, int arg2) {
295     }
296 
297     @Override
298     public void onPageSelected(int arg0) {
299         int max = imageViews.size() - 1;
300         int position = arg0;
301         currentPosition = arg0;
302         if (isCycle) {
303             if (arg0 == 0) {
304                 currentPosition = max - 1;
305             } else if (arg0 == max) {
306                 currentPosition = 1;
307             }
308             position = currentPosition - 1;
309         }
310         setIndicator(position);
311     }
312 
313     /**
314      * 设置viewpager是否可以滚动
315      * 
316      * @param enable
317      */
318     public void setScrollable(boolean enable) {
319         viewPager.setScrollable(enable);
320     }
321 
322     /**
323      * 返回当前位置,循环时需要注意返回的position包含之前在views最前方与最后方加入的视图,即当前页面试图在views集合的位置
324      * 
325      * @return
326      */
327     public int getCurrentPostion() {
328         return currentPosition;
329     }
330 
331     /**
332      * 设置指示器
333      * 
334      * @param selectedPosition
335      *            默认指示器位置
336      */
337     private void setIndicator(int selectedPosition) {
338         for (int i = 0; i < indicators.length; i++) {
339             indicators[i].setBackgroundResource(R.mipmap.icon_point);
340         }
341         if (indicators.length > selectedPosition)
342             indicators[selectedPosition].setBackgroundResource(R.mipmap.icon_point_pre);
343     }
344 
345     /**
346      * 如果当前页面嵌套在另一个viewPager中,为了在进行滚动时阻断父ViewPager滚动,可以 阻止父ViewPager滑动事件
347      * 父ViewPager需要实现ParentViewPager中的setScrollable方法
348      */
349     public void disableParentViewPagerTouchEvent(BaseViewPager parentViewPager) {
350         if (parentViewPager != null)
351             parentViewPager.setScrollable(false);
352     }
353 
354     
355     /**
356      * 轮播控件的监听事件
357      * 
358      * @author minking
359      */
360     public static interface ImageCycleViewListener {
361 
362         /**
363          * 单击图片事件
364          * 
365          * @param position
366          * @param imageView
367          */
368         public void onImageClick(MyImage info, int postion, View imageView);
369     }
370 }
View Code

 

       ③CycleViewPagerHandler==>为了防止内存泄漏,定义外部类,防止内部类对外部类的引用

1 public class CycleViewPagerHandler extends Handler {
2      Context context;
3 
4     public CycleViewPagerHandler(Context context) {
5         this.context = context;
6     }
7 }
View Code

 

        ④ViewFactory==>创建ImageView工厂,获取ImageView视图的同时加载显示url

 1 public class ViewFactory {
 2 
 3     /**
 4      * 获取ImageView视图的同时加载显示url
 5      * 
 6      * @param
 7      * @return
 8      */
 9     public static ImageView getImageView(Context context, String url) {
10         ImageView imageView = (ImageView)LayoutInflater.from(context).inflate(
11                 R.layout.view_banner, null);
12         ImageLoader.getInstance().displayImage(url, imageView);//最核心的部分
13         return imageView;
14     }
15 }
View Code

 

         ⑤MyImage==>这是广告页的bean类

 1 class MyImage {
 2 
 3     var link: String? = null
 4     var image:String?=null
 5     var title:String?=null
 6 
 7     constructor():super()
 8     constructor(image: String) : super() {
 9         this.image = image
10     }
11     constructor(image:String,link:String,title:String){
12         this.image=image
13         this.link=link
14         this.title=title
15     }
16 
17     override fun toString(): String {
18         return "MyImage[link=$link,image=$image,title=$title]"
19     }
20 }
View Code

 

   

   2.从服务器中拿到图片的链接地址,一般广告页都是从服务器拿到的数据。本地的也可以,而且更加简单了。我就拿前者举例吧。

    下面的代码是我自己的一个请求,里面有很多东西都是自己定义的东西。 

    如:LogUtils.d_debugprint()是自己封装好的一个日志输出的类。

      Constant也是自己封装好的常量。

      HttpUtil.httpPost也是自己封装的网络请求的类。

      JsonUtil.get_key_string也是自己封装Json解析的类。

      MyImage是自己定义的一个Bean类。

      Toasty是引用的第三方库toast的类,用来提示用户。

      initialize()是自己初始化广告页,后面第三步就是写这个函数了。

    

      解释清楚之后,请求的函数如下:

 1  private fun getADfromServer() {
 2         var urlPath = ""
 3         var sign = ""
 4         val encode = Constant.ENCODE
 5         val school = Constant.SCHOOLDEFULT
 6         if (LogUtils.APP_IS_DEBUG) {
 7             urlPath = Constant.BASEURLFORTEST + Constant.School_AD
 8             sign = MD5Util.md5(Constant.SALTFORTEST)
 9         } else {
10             urlPath = Constant.BASEURLFORRELEASE + Constant.School_AD
11             sign = MD5Util.md5(Constant.SALTFORRELEASE)
12         }
13         val params = mapOf<String, Any?>("school" to school,"sign" to sign)
14         LogUtils.d_debugprint(TAG, Constant.TOSERVER + urlPath + "\n提交的map=" + params.toString())
15         Thread(Runnable {
16             getAdfromServer= HttpUtil.httpPost(urlPath,params,encode)
17            // LogUtils.d_debugprint(TAG,Constant.GETDATAFROMSERVER+getAdfromServer)
18             val getCode:String
19             var msg:String?=null
20             var result:String
21             var getData:List<Map<String,Any?>>
22             getCode= JsonUtil.get_key_string(Constant.Server_Code,getAdfromServer!!)
23             if(Constant.RIGHTCODE.equals(getCode)) {
24                 handler_result1.post {
25                     msg = JsonUtil.get_key_string(Constant.Server_Msg, getAdfromServer!!)
26                     result = JsonUtil.get_key_string(Constant.Server_Result, getAdfromServer!!)
27                     getData = JsonUtil.getListMap("data", result)//=====这里可能发生异常
28                     LogUtils.d_debugprint(TAG, "json解析出来的对象是=" + getData.toString())
29                     if (getData != null&&getData.size>0) {
30                         for (i in getData.indices) {
31                             val myImage=MyImage()
32                             if(getData[i].getValue("link").toString()!=null&&getData[i].getValue("image").toString()!=null&&getData[i].getValue("title").toString()!=null) {
33                                 myImage.link = getData[i].getValue("link").toString()
34                                 myImage.image = getData[i].getValue("image").toString()
35                                 myImage.title = getData[i].getValue("title").toString()
36                                 myImageList.add(myImage)//=====这里保存了所有广告信息
37                             }else{
38                                 Toasty.error(context,Constant.SERVERBROKEN).show()
39                             }
40                         }
41                         initialize() //初始化顶部导航栏
42                     }else{
43                         val myImage=MyImage()
44                         myImage.link=""
45                         myImage.image=""
46                         myImage.title=""
47                         myImageList.add(myImage)
48                         //Toasty.error(context,Constant.SERVERBROKEN).show()
49                     }
50                 }
51             }
52         }).start()
53     }
View Code

 

 

   3.然后就是initialize()函数了

    说明一下==>>

    myImageOverAD是覆盖在广告页上的一张默认图片,如果没有网,或者请求失败的时候,将显示这张图片。

    cycleViewPager是广告栏中的一个叫fragment的布局。

    views是广告栏的一个ArrayList<ImageView>(),可以动态添加ImageView

    mAdCycleViewListener是广告页点击的监听器,第四步会详细讲。

 1  @SuppressLint("NewApi")
 2     private fun initialize() {
 3         myImageOverAD!!.visibility=View.GONE
 4         cycleViewPager = activity.fragmentManager.findFragmentById(R.id.oneFm_fragment_cycle_viewpager_content) as CycleViewPager
 5 
 6         views.add(ViewFactory.getImageView(context, myImageList[myImageList.size - 1].image)) // 将最后一个ImageView添加进来
 7         for (i in myImageList.indices) {
 8             views.add(ViewFactory.getImageView(context, myImageList[i].image))
 9         }
10         views.add(ViewFactory.getImageView(context, myImageList[0].image)) // 将第一个ImageView添加进来
11         cycleViewPager!!.isCycle = true // 设置循环,在调用setData方法前调用
12         cycleViewPager!!.setData(views, myImageList, mAdCycleViewListener) // 在加载数据前设置是否循环
13         cycleViewPager!!.isWheel = true //设置轮播
14         cycleViewPager!!.setTime(5000) // 设置轮播时间,默认5000ms
15         cycleViewPager!!.setIndicatorCenter() //设置圆点指示图标组居中显示,默认靠右
16     }
View Code

 

 

   4.然后是mAdCycleViewListener监听器的实现了。

    说明一下==>>

    ADWebView是点击广告页要调整的webView。

    R.anim.slide_left_out是一个从左边出去的动画。

    源码如下:

 1 private val mAdCycleViewListener = CycleViewPager.ImageCycleViewListener { info, position, imageView ->
 2         var position = position
 3         if (cycleViewPager!!.isCycle) {
 4             position = position - 1
 5             //Toasty.info(context,"标题:"+info.title+ "\n链接:" + info.link).show()
 6 
 7             val bundle=Bundle()
 8             bundle.putString("title",info.title)
 9             bundle.putString("link",info.link)
10             val intent:Intent=Intent(context,ADWebView::class.java)
11             intent.putExtras(bundle)
12             startActivity(intent)
13             activity.overridePendingTransition(0,R.anim.slide_left_out)
14         }
15     }
View Code

 

   5.广告页的布局代码差点忘记了。

      说明一下==>>

    这里的fragment才是主角,下方的ImageView是覆盖在广告页上的一张默认图片,在没有网获取没有成功请求到服务器的时候显示的图片。

 1  <RelativeLayout
 2        android:layout_width="match_parent"
 3        android:layout_height="350pt">
 4 
 5     <fragment
 6         android:id="@+id/oneFm_fragment_cycle_viewpager_content"
 7         android:name="com.guangdamiao.www.mew_android_debug.banner.CycleViewPager"
 8         android:layout_width="match_parent"
 9         android:layout_height="350pt"
10         />
11 
12     <ImageView
13         android:id="@+id/oneFm_fragment_cycle_viewpager_content_over"
14         android:layout_width="match_parent"
15         android:layout_height="360pt"
16         android:src="@drawable/one_overad"
17         android:visibility="visible"
18         android:scaleType="centerCrop"
19         />
20 
21    </RelativeLayout>
View Code

 

 

  效果如下:

  

 

  

 

posted @ 2017-10-19 12:04  Jason_Jan  阅读(1443)  评论(0编辑  收藏  举报