尊重作者劳动成果,转载时请标明该文章出自 http://blog.csdn.net/allen315410/article/details/39294343
最近翻看以前的某项目时,发现了一个极其常用的效果——广告条,或者也称不上自定义组件,但是使用频率还是相当普遍的。
打开市面上各大App主界面,或多或少会出现这样的东西,甚至一个应用中出现N多个,这种展示广告的效果,不仅动态效果好,而且众所周知的“不占屏”,想想在手机设备这么小的屏幕尺寸下,能放下几页甚至十几页的广告循环播放,就知道这种广告的使用频率之大了。以下是我收集的部分APP中使用的效果截图:
这些“千万亿”级别的APP都在使用的效果,为什么我们不能效仿追随一下呢,那下面我就开始动手做一个自己的广告条;
要求如下:1,实现多图展示
2,实现手势切换
3,广告图片与广告标语同时切换
4,循环切换,定时循环播放
以下是我的项目结构:
广告条实际上用的是ViewPager来做的,布局中仅仅放了一个ViewPager而已,其它的图片切换都是用ViewPager来展示的,布局如下:
package com.example.banner;
import java.util.ArrayList;
import java.util.List;
import android.os.Bundle;
import android.os.SystemClock;
import android.support.v4.view.PagerAdapter;
import android.support.v4.view.ViewPager;
import android.support.v4.view.ViewPager.OnPageChangeListener;
import android.view.View;
import android.view.ViewGroup;
import android.widget.ImageView;
import android.widget.LinearLayout;
import android.widget.TextView;
import android.widget.LinearLayout.LayoutParams;
import android.app.Activity;
public class MainActivity extends Activity {
private List mImageList;
/** 广告条正下方的标语 */
private String[] imageDescriptionArray = { //
"巩俐不低俗,我就不能低俗", //
"扑树又回来啦!再唱经典老歌引万人大合唱", //
"揭秘北京电影如何升级", //
"乐视网TV版大派送", //
"热血屌丝的反杀" };
/** 记录上一次点的位置,默认为0 */
private int previousPointEnale = 0;
private ViewPager mViewPager;
private LinearLayout llPointGroup;
private TextView tvDescription;
/** 记录是否停止循环播放 */
private boolean isStop = false;
@Override
protected void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
setContentView(R.layout.activity_main);
init();
// 开启子线程,让广告条以2秒的频率循环播放
new Thread(new Runnable() {
@Override
public void run() {
while (!isStop) {
SystemClock.sleep(2000);
runOnUiThread(new Runnable() {
public void run() {
mViewPager.setCurrentItem(mViewPager.getCurrentItem() + 1);
}
});
}
}
}).start();
}
private void init() {
llPointGroup = (LinearLayout) findViewById(R.id.ll_point_group);
tvDescription = (TextView) findViewById(R.id.tv_image_description);
mImageList = new ArrayList();
int[] imageIds = new int[] { R.drawable.a, R.drawable.b, R.drawable.c, R.drawable.d, R.drawable.e };
ImageView mImageView;
LayoutParams params;
// 初始化广告条资源
for (int id : imageIds) {
mImageView = new ImageView(this);
mImageView.setBackgroundResource(id);
mImageList.add(mImageView);
// 初始化广告条正下方的"点"
View dot = new View(this);
dot.setBackgroundResource(R.drawable.point_background);
params = new LayoutParams(5, 5);
params.leftMargin = 10;
dot.setLayoutParams(params);
dot.setEnabled(false);
llPointGroup.addView(dot);
}
mViewPager = (ViewPager) findViewById(R.id.viewpager);
mViewPager.setAdapter(new MyAdapter());
// 设置广告条跳转时,广告语和状态语的变化
mViewPager.setOnPageChangeListener(new MyListener());
// 初始化广告条,当前索引Integer.MAX_VALUE的一半
int index = (Integer.MAX_VALUE / 2) - (Integer.MAX_VALUE / 2 % mImageList.size());
mViewPager.setCurrentItem(index); // 设置当前选中的Page,会触发onPageChangListener.onPageSelected方法
}
private class MyListener implements OnPageChangeListener {
@Override
public void onPageScrollStateChanged(int arg0) {
// TODO Auto-generated method stub
}
@Override
public void onPageScrolled(int arg0, float arg1, int arg2) {
// TODO Auto-generated method stub
}
@Override
public void onPageSelected(int arg0) {
// 获取新的位置
int newPosition = arg0 % imageDescriptionArray.length;
// 设置广告标语
tvDescription.setText(imageDescriptionArray[newPosition]);
// 消除上一次的状态点
llPointGroup.getChildAt(previousPointEnale).setEnabled(false);
// 设置当前的状态点“点”
llPointGroup.getChildAt(newPosition).setEnabled(true);
// 记录位置
previousPointEnale = newPosition;
}
}
/**
* ViewPager数据适配器
*/
private class MyAdapter extends PagerAdapter {
@Override
public int getCount() {
// 将viewpager页数设置成Integer.MAX_VALUE,可以模拟无限循环
return Integer.MAX_VALUE;
}
/**
* 复用对象 true 复用view false 复用的是Object
*/
@Override
public boolean isViewFromObject(View arg0, Object arg1) {
// TODO Auto-generated method stub
return arg0 == arg1;
}
/**
* 销毁对象
*
* @param position
* 被销毁对象的索引位置
*/
@Override
public void destroyItem(ViewGroup container, int position, Object object) {
container.removeView(mImageList.get(position % mImageList.size()));
}
/**
* 初始化一个对象
*
* @param position
* 初始化对象的索引位置
*/
@Override
public Object instantiateItem(ViewGroup container, int position) {
container.addView(mImageList.get(position % mImageList.size()));
return mImageList.get(position % mImageList.size());
}
}
@Override
protected void onDestroy() {
// activity销毁时候,关闭循环播放
isStop = true;
super.onDestroy();
}
}
到此还要注意的地方就是,因为getCount中返回Integer.MAX_VALUE这么大数值,为了达到有图循环的效果,避免Bug,所以其后每次涉及到position索引的地方都得用position和资源尺度取余的结果。
此外,在“点”的初始化的时候,应当设置“点”的索引为int index = (Integer.MAX_VALUE / 2) - (Integer.MAX_VALUE / 2 % mImageList.size());
而不能简单设置成0,若是设置成0,就无法制造出循环播放的“假象”,不信试试设置0,往左滑动。
关于“点”的资源,没有用到图片,下面是资源代码,贴出来:
广告条获得焦点:point_bg_enable.xml
以下是效果图:
最后,还需要实现广告的自动循环播放,这个很简单,只要开启一个新线程,在线程中每隔2000ms循环更新一下ViewPager就行。就是在ViewPager中获取当前展示的Item的索引,加上1之后,设置展示这个值即可。还得注意程序的严谨性啊,当activity销毁的时候,这个新线程里负责循环播放的代码是徐璈停止执行的。故设置一个boolean的变量isStop,在while循环的时候,判断是否开启/关闭,在activity的onDestory方法中,设置其为true,即停止循环播放!
源码请在这里下载