轮播广告条在应用中非常广泛的使用,这次在看公司一个项目时,发现多处都使用到轮播广告条的功能,看到了很多重复的代码,所以萌生了整合的想法。先来看看常见的轮播广告条的样式。ps:标题有点吹牛逼了。嘎嘎
通过上面我们也可以发现,常见的轮播广告条的组成:
所以在整合的过程中,我就是将ViewPager和指示器部分封装起来了。根据上面的布局,所以我们继承RelativeLayout进行布局。所以我们定义类ViewPagerBarnner
public class ViewPagerBarnner extends RelativeLayout implements OnPageChangeListener {
/** * ViewPager对象 */
private ViewPager viewPager;
/** * 指示器 */
private LinearLayout indicatorView;
private Context context;
/** * 图片url地址 */
private List<String> imageUrls = new ArrayList<String>();
/** * 获取的ImageView对象集合 */
private List<ImageView> imageViews = new ArrayList<ImageView>();
/** * 点击ViewPager中ImageView的回调事件 */
private ViewPagerClick viewPagerClick;
/** * 指示器的默认大小 */
private float indicatorSize = 15;
/** * 指示器的drawable对应的资源id */
private int idBackgroud;
/** * 指示器之间的距离 */
private float indicatorMargin = 20;
...
}
上面就是我们需要的控件,我们定义了Viewpager和一个LinearLayout,其中LinearLayout用于存储我们的指示器。为了提高定制性,我们自定义了三个属性,如下:
<?xml version="1.0" encoding="utf-8"?>
<resources>
<declare-styleable name="ViewPager">
<attr name="containerHeight" format="dimension"/> <!-- 容器的高度 -->
<attr name="indicatorSize" format="dimension"/> <!-- 指示器大小 -->
<attr name="indicatorBackgroud" format="reference"/> <!-- 指示器背景,可以说drawable对象 -->
<attr name="indicatorMargin" format="dimension"/> <!-- 指示器之间的间隔 -->
</declare-styleable>
</resources>
有了自定义的属性,我们在构造函数中进行获取设定的值。这里,我们定义背景为一个reference类型,在使用的过程中我通过type
public ViewPagerBarnner(Context context, AttributeSet attrs) {
super(context, attrs);
this.context = context;
initViews();
TypedArray typedArray = context.obtainStyledAttributes(attrs, R.styleable.ViewPager);
indicatorSize = typedArray.getDimension(R.styleable.ViewPager_indicatorSize, 10);
indicatorMargin = typedArray.getDimension(R.styleable.ViewPager_indicatorMargin, 15);
idBackgroud = typedArray.getResourceId(R.styleable.ViewPager_indicatorBackgroud, 0);
containerHeight = typedArray.getDimension(R.styleable.ViewPager_containerHeight, 20);
typedArray.recycle();
}
/** * 初始化View的视图 */
private void initViews(){
viewPager = new ViewPager(context);
LayoutParams viewPagerParams = new LayoutParams(RelativeLayout.LayoutParams.MATCH_PARENT,
RelativeLayout.LayoutParams.MATCH_PARENT);
viewPager.setLayoutParams(viewPagerParams);
viewPager.setAdapter(viewPagerAdapter);
viewPager.setOnPageChangeListener(this);
indicatorView = new LinearLayout(context);
indicatorView.setOrientation(LinearLayout.HORIZONTAL);
LayoutParams layoutParams = new LayoutParams(RelativeLayout.LayoutParams.WRAP_CONTENT,(int)containerHeight);
layoutParams.addRule(RelativeLayout.ALIGN_PARENT_BOTTOM);
layoutParams.addRule(RelativeLayout.CENTER_HORIZONTAL);
indicatorView.setLayoutParams(layoutParams);
addView(viewPager);
addView(indicatorView);
}
我们初始化ViewPager和LinearLayout,同时对它们进行布局。将LinearLayout放到最底部。接下来就是设置我们的监听事件以及为ViewPager设置Adapter。
/** * ViewPager的适配器 */
private PagerAdapter viewPagerAdapter = new PagerAdapter() {
@Override
public boolean isViewFromObject(View view, Object object) {
return view == object;
}
@Override
public int getCount() {
return imageUrls == null ? 0 : imageUrls.size();
}
@Override
public void destroyItem(ViewGroup container, int position, Object object) {
container.removeView((View) object);
}
@Override
public void finishUpdate(ViewGroup container) {
}
@Override
public int getItemPosition(Object object) {
return super.getItemPosition(object);
}
@Override
public Object instantiateItem(ViewGroup container, int position) {
ImageView imageView = null;
if(imageViews != null && imageViews.size() > 0){
imageView = imageViews.get(position);
imageView.setOnClickListener(new OnClickListener() {
@Override
public void onClick(View view) {
if(viewPagerClick != null){
viewPagerClick.viewPagerOnClick(view);
}
}
});
}
container.addView(imageView);
return imageView;
}
};
@Override
public void onPageScrollStateChanged(int arg0) {
}
@Override
public void onPageScrolled(int arg0, float arg1, int arg2) {
}
@Override
public void onPageSelected(int location) {
setSelectPage(location);
}
至此,整体的框架已经完成,然后就是我们为Adapter赋予数据。具体处理如下:
/** * 从url地址创建imageview对象,同时初始化指示器 */
private void createImageView(List<String> imageUrlList){
if(imageUrlList != null && imageUrlList.size() > 0){
ImageView imageView;
View pointView;
for(String url : imageUrlList){
imageView = new ImageView(context);
imageView.setScaleType(ScaleType.FIT_XY);
ImageLoader.getInstance().displayImage(url, imageView);
imageView.setTag(url);
imageViews.add(imageView);
pointView = new View(context);
LinearLayout.LayoutParams params = new LinearLayout.LayoutParams((int)(indicatorSize),(int)(indicatorSize));
params.rightMargin = (int)indicatorMargin;
pointView.setLayoutParams(params);
pointView.setBackgroundDrawable(context.getResources().getDrawable(idBackgroud));
pointView.setEnabled(false);
indicatorView.addView(pointView);
}
setSelectPage(0);
}
}
/** * 设置当前选中页面 * @param position */
private void setSelectPage(int position){
for(int index=0; index < indicatorView.getChildCount();index++){
if(position == index){
indicatorView.getChildAt(index).setEnabled(true);
}else{
indicatorView.getChildAt(index).setEnabled(false);
}
}
}
/** * 设置图片的地址,从网络加载图片 * @param imageUrls */
public void addImageUrls(List<String> imageUrls) {
this.imageUrls.addAll(imageUrls);
createImageView(imageUrls);
viewPagerAdapter.notifyDataSetChanged();
}
至此,就完成了基本的广告条展示功能。我们看下MainActivity和布局中的使用。
<com.lcwang.androidviews.ViewPagerBarnner
android:id="@+id/viewPager"
android:layout_height="160dp"
android:layout_width="match_parent"
viewpager:indicatorSize="8dp"
viewpager:indicatorMargin="10dp"
viewpager:indicatorBackgroud="@drawable/indicator_backgroud"
/>
@Override
protected void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
setContentView(R.layout.activity_main);
ViewPagerBarnner viewPagerBarnner = (ViewPagerBarnner) findViewById(R.id.viewPager);
List<String> url = new ArrayList<String>();
url.add("http://pic1.nipic.com/2008-12-25/2008122510134038_2.jpg");
url.add("http://pic3.nipic.com/20090525/2416945_231841034_2.jpg");
url.add("http://img3.3lian.com/2013/s1/20/d/57.jpg");
url.add("http://pic1.nipic.com/2008-11-13/2008111384358912_2.jpg");
url.add("http://img.61gequ.com/allimg/2011-4/201142614314278502.jpg");
viewPagerBarnner.addImageUrls(url);
viewPagerBarnner.setViewPagerClick(new ViewPagerClick() {
@Override
public void viewPagerOnClick(View view) {
Toast.makeText(MainActivity.this, view.getTag().toString(), Toast.LENGTH_SHORT).show();
}
});
}
我们自定义指示器的样式:
<?xml version="1.0" encoding="utf-8"?>
<selector xmlns:android="http://schemas.android.com/apk/res/android" >
<item android:state_enabled="true">
<shape android:shape="oval">
<size android:width="3dp" android:height="3dp"/>
<solid android:color="#00FF00"/>
</shape>
</item>
<item android:state_enabled="false">
<shape android:shape="oval">
<size android:width="3dp" android:height="3dp"/>
<solid android:color="#FFFFFF"/>
</shape>
</item>
</selector>
通过上面的效果图,我们发现基本的效果已经有了,但是还没有实现无限循环以及自动播放的功能。所以接下来我们就是实现无限循环和自动播放的功能。网上流行的两种实现方法,我们先看一种,我画了一个草图:
为了方便我们增加头尾,我将存放url和imageview的集合改为LinkedList。
private LinkedList<String> imageUrls = new LinkedList<String>();
private LinkedList<ImageView> imageViews = new LinkedList<ImageView>();
主要的判断处理就是增加头尾处,这里说一点,在为ImageView的集合增加首尾的时候,为什么重新获取而不是利用集合中已经存在的,这是因为如果我们将该对象进行利用后,持有该对象的引用,然后在切换时,报该ImageView已经有父容器了。(这是我理解的)
@Override
public void onPageSelected(int location) {
if(location == this.imageUrls.size() -1){
location = 1;
viewPager.setCurrentItem(location,false);
}else if(location == 0){
location = this.imageUrls.size() -2;
viewPager.setCurrentItem(location,false);
}
currentPostion = location;
setSelectPage(location - 1);
}
/** * 从url地址创建imageview对象,同时初始化指示器 */
private void createImageView(List<String> imageUrlList){
if(imageUrlList != null && imageUrlList.size() > 0){
ImageView imageView;
View pointView;
//清除头尾
if(imageViews.size() > 1){
imageViews.removeFirst();
imageViews.removeLast();
}
for(String url : imageUrlList){
imageView = new ImageView(context);
imageView.setScaleType(ScaleType.FIT_XY);
ImageLoader.getInstance().displayImage(url, imageView);
imageView.setTag(url);
imageViews.add(imageView);
pointView = new View(context);
LinearLayout.LayoutParams params = new LinearLayout.LayoutParams((int)(indicatorSize),(int)(indicatorSize));
params.rightMargin = (int)indicatorMargin;
pointView.setLayoutParams(params);
pointView.setBackgroundDrawable(context.getResources().getDrawable(idBackgroud));
pointView.setEnabled(false);
indicatorView.addView(pointView);
}
//增加头尾
if(imageViews.size() > 1){
ImageView ivFirst = new ImageView(context);
ImageView ivLast = new ImageView(context);
ImageLoader.getInstance().displayImage(imageUrls.getLast(),ivLast);
ImageLoader.getInstance().displayImage(imageUrls.getFirst(),ivFirst);
imageViews.addFirst(ivFirst);
imageViews.addLast(ivLast);
}
viewPagerAdapter.notifyDataSetChanged();
viewPager.setCurrentItem(1);
}
}
/** * 设置当前选中页面 * @param position */
private void setSelectPage(int position){
for(int index=0; index < indicatorView.getChildCount();index++){
if(position == index){
indicatorView.getChildAt(index).setEnabled(true);
}else{
indicatorView.getChildAt(index).setEnabled(false);
}
}
}
/** * 设置图片的地址,从网络加载图片 * @param imageUrls */
public void addImageUrls(List<String> imageUrls) {
if(this.imageUrls.size() > 1){//清除头尾
this.imageUrls.removeFirst();
this.imageUrls.removeLast();
}
this.imageUrls.addAll(imageUrls);
if(this.imageUrls.size() >1){//增加头尾
String first = this.imageUrls.getFirst();
this.imageUrls.addFirst(this.imageUrls.getLast());
this.imageUrls.addLast(first);
}
createImageView(imageUrls);
}
这样就可以实现了ViewPager的循环,同时我们可以通过addImageUrls方法进行新增页。实现了循环,就开始自动播放,自动播放的实现无外乎几种:
我们通过Handler进行实现。
private Handler mHandler = new Handler(){
@Override
public void handleMessage(Message msg) {
viewPager.setCurrentItem(currentPostion + 1);
mHandler.sendEmptyMessageDelayed(0, 3000);
}
};
/** * 初始化View的视图 */
private void initViews(){
...
mHandler.sendEmptyMessageDelayed(0, 3000);
}
这样就完成了一个组合的ViewPager开发。来瞄一眼效果:
至此,这个控件就完成了,可以很方便使用,在也不用去搞很多逻辑判断了。这里面加载网络图片使用的ImageLoader库,需要添加,或者改源码自己修改。
源码下载地址
github
下篇地址:http://blog.csdn.net/Mr_dsw/article/details/50429396