项目要求做一个广告页,实现几秒更换一次广告页,下方还有指示第几张广告页,同样也支持手动左滑或右滑。
摘要:项目要求做一个广告页,实现几秒更换一次广告页,下方还有指示第几张广告页,同样也支持手动左滑或右滑。
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
效果如下:
既然选择了,便不顾风雨兼程。Just follow yourself.