欢迎您访问程序员文章站本站旨在为大家提供分享程序员计算机编程知识!
您现在的位置是: 首页  >  移动技术

Android自定义控件实现优雅的广告轮播图

程序员文章站 2023-12-05 13:14:34
前言 今天给大家带来一个新的控件–轮播图,网上已经有很多这类的博客来讲解如何实现的,那么我的这个有哪些特点呢?或是说有哪些不同呢? 满足了轮播图的基本要求,循环滑动,在...

前言

今天给大家带来一个新的控件–轮播图,网上已经有很多这类的博客来讲解如何实现的,那么我的这个有哪些特点呢?或是说有哪些不同呢?

满足了轮播图的基本要求,循环滑动,在最后一张切到第一张时可以平稳的过渡
简洁简洁简洁
扩展性强

如何使用

下面我们先展示两种效果图

1 默认效果

Android自定义控件实现优雅的广告轮播图

代码实现

//布局代码
<com.landptf.view.bannerm
  android:id="@+id/bm_banner"
  android:layout_width="match_parent"
  android:layout_height="200dp" />

//java代码
bannerm banner = (bannerm) findviewbyid(r.id.bm_banner);
if (banner != null) {
 banner.setbannerbeanlist(bannerlist).show();
}

//初始化数据
private void initdata() {
 bannerlist = new arraylist<>(4);
 bannerbean banner1 = new bannerbean("测试图片1", url1, "");
 bannerbean banner2 = new bannerbean("测试图片2", url2, "");
 bannerbean banner3 = new bannerbean("测试图片3", url3, "");
 bannerbean banner4 = new bannerbean("测试图片4", url4, "");
 bannerlist.add(banner1);
 bannerlist.add(banner2);
 bannerlist.add(banner3);
 bannerlist.add(banner4);
}

其实关键代码就一行,这里面用到了bannerbean的实体类,有三个参数,分别是图片的描述文字,图片地址,点击后对应的链接

以上全部都是默认值,下面来看一下都哪些可以自定义

2 自定义效果

Android自定义控件实现优雅的广告轮播图

图1和图2主要有以下几点不同

1 指示器和文字的位置结构,这里面我只实现了两种,大家也可以下载源码后扩展
2 圆点指示器选中后的颜色
3 自动播放的时间间隔
4 支持图片未加载出来之前显示默认图片

自定义效果的代码实现

下面通过xml和java代码来分别演示一下图2的实现

1 xml

<com.landptf.view.bannerm
  android:id="@+id/bm_banner"
  android:layout_width="match_parent"
  android:layout_height="200dp"
  landptf:defaultimagedrawable="@drawable/default_image"
  landptf:intervaltime="3"
  landptf:indexposition="bottom"
  landptf:indexcolor="@color/colorprimary"
  />

bannerm banner = (bannerm) findviewbyid(r.id.bm_banner);
if (banner != null) {
 banner.setbannerbeanlist(bannerlist)
   .setonitemclicklistener(new bannerm.onitemclicklistener() {
    @override
    public void onitemclick(int position) {
     log.e("landptf", "position = " + position);
    }
   })
   .show();
}

2 java

<com.landptf.view.bannerm
  android:id="@+id/bm_banner"
  android:layout_width="match_parent"
  android:layout_height="200dp" />

bannerm banner = (bannerm) findviewbyid(r.id.bm_banner);
if (banner != null) {
 banner.setbannerbeanlist(bannerlist)
   .setdefaultimageresid(r.drawable.default_image)
   .setindexposition(bannerm.index_position_bottom)
   .setindexcolor(getresources().getcolor(r.color.colorprimary))
   .setintervaltime(3)
   .setonitemclicklistener(new bannerm.onitemclicklistener() {
    @override
    public void onitemclick(int position) {
     log.e("landptf", "position = " + position);
    }
   })
   .show();
}

以上两种代码实现的效果完全等价,在java代码中都是通过链式调用,使代码看起来更加的简洁。
有木有很方便,大大的减少了代码量,而且是可以直接拿来用的。好了下面我们来看一下实现的代码。

实现

图片下载集成了picasso,有对picasso不熟悉的童鞋可以看一下我之前的博客图片加载利器之picasso(二)基本用法

<?xml version="1.0" encoding="utf-8"?>
<relativelayout xmlns:android="http://schemas.android.com/apk/res/android"
 android:layout_width="match_parent"
 android:layout_height="match_parent">

 <android.support.v4.view.viewpager
  android:id="@+id/vp_banner"
  android:layout_width="match_parent"
  android:layout_height="match_parent" />

 <viewstub
  android:id="@+id/vs_index_right"
  android:layout_width="match_parent"
  android:layout_height="wrap_content"
  android:layout_alignparentbottom="true"
  android:layout="@layout/viewstub_banner_m_index_right" />

 <viewstub
  android:id="@+id/vs_index_bottom"
  android:layout_width="match_parent"
  android:layout_height="wrap_content"
  android:layout_alignparentbottom="true"
  android:layout="@layout/viewstub_banner_m_index_bottom" />

</relativelayout>

viewstub的引用代码这里就不给出,大家可以访问我的git查看,文末会给出地址

package com.landptf.view;

import android.annotation.suppresslint;
import android.content.context;
import android.content.res.colorstatelist;
import android.content.res.typedarray;
import android.graphics.drawable.drawable;
import android.graphics.drawable.gradientdrawable;
import android.os.handler;
import android.os.message;
import android.os.parcelable;
import android.support.annotation.nullable;
import android.support.v4.view.pageradapter;
import android.support.v4.view.viewpager;
import android.util.attributeset;
import android.view.layoutinflater;
import android.view.view;
import android.view.viewgroup;
import android.view.viewparent;
import android.view.viewstub;
import android.widget.imageview;
import android.widget.linearlayout;
import android.widget.relativelayout;
import android.widget.textview;

import com.landptf.r;
import com.landptf.bean.bannerbean;
import com.landptf.util.convertm;
import com.squareup.picasso.memorypolicy;
import com.squareup.picasso.picasso;

import java.util.arraylist;
import java.util.list;
import java.util.concurrent.executors;
import java.util.concurrent.scheduledexecutorservice;
import java.util.concurrent.timeunit;

/**
 * created by landptf on 2017/03/06.
 * 轮播图控件
 */
public class bannerm extends relativelayout {
 /**
  * 圆点指示器的位置,文字在左,圆点在右
  */
 public static final int index_position_right = 0x100;
 /**
  * 圆点指示器的位置,文字在上,圆点在下
  */
 public static final int index_position_bottom = 0x101;

 private static final int handle_update_index = 0;

 private context mcontext;
 private viewpager vpbanner;
 private viewpageradapter adapter;
 private onitemclicklistener monitemclicklistener;

 //装载imageview控件的list
 private list<imageview> ivlist;
 //圆点指示器控件
 private list<view> vlist;
 //控制圆点view的形状,未选中的颜色
 private gradientdrawable gradientdrawable;
 //控制圆点view的形状,选中的颜色
 private gradientdrawable gradientdrawableselected;
 //选中圆点的颜色值,默认为#ff3333
 private int indexcolorresid;
 //图片对应的文字描述
 private textview tvtext;
 //自动滑动的定时器
 private scheduledexecutorservice scheduledexecutorservice;
 //当前加载到第几页
 private int currentindex = 0;
 //默认背景图
 private int defaultimageresid;
 private drawable defaultimagedrawable = null;
 //自动轮播的时间间隔(s)
 private int intervaltime = 5;
 //轮播图需要的数据列表
 private list<bannerbean> bannerbeanlist;
 //圆点指示器的位置,提供两种布局
 private int indexposition = index_position_right;

 public bannerm(context context) {
  this(context, null);
 }

 public bannerm(context context, attributeset attrs) {
  this(context, attrs, 0);
 }

 public bannerm(context context, attributeset attrs, int defstyleattr) {
  super(context, attrs, defstyleattr);
  init(context, attrs, defstyleattr);
 }

 private void init(context context, attributeset attrs, int defstyle) {
  mcontext = context;
  layoutinflater.from(context).inflate(r.layout.view_banner_m, this, true);
  vpbanner = (viewpager) findviewbyid(r.id.vp_banner);
  typedarray a = getcontext().obtainstyledattributes(
    attrs, r.styleable.bannerm, defstyle, 0);
  if (a != null) {
   defaultimagedrawable = a.getdrawable(r.styleable.bannerm_defaultimagedrawable);
   intervaltime = a.getinteger(r.styleable.bannerm_intervaltime, 5);
   indexposition = a.getinteger(r.styleable.bannerm_indexposition, index_position_right);
   colorstatelist indexcolorlist = a.getcolorstatelist(r.styleable.bannerm_indexcolor);
   if (indexcolorlist != null) {
    indexcolorresid = indexcolorlist.getcolorforstate(getdrawablestate(), 0);
   }
   a.recycle();
  }
 }

 /**
  * 设置图片加载之前默认显示的图片
  *
  * @param defaultimageresid
  * @return bannerm
  */
 public bannerm setdefaultimageresid(int defaultimageresid) {
  this.defaultimageresid = defaultimageresid;
  return this;
 }

 /**
  * 设置图片加载之前默认显示的图片
  *
  * @param defaultimagedrawable
  * @return bannerm
  */
 public bannerm setdefaultimagedrawable(drawable defaultimagedrawable) {
  this.defaultimagedrawable = defaultimagedrawable;
  return this;
 }

 /**
  * 设置轮播的时间间隔,单位为s,默认为5s
  *
  * @param intervaltime
  * @return bannerm
  */
 public bannerm setintervaltime(int intervaltime) {
  this.intervaltime = intervaltime;
  return this;
 }

 /**
  * 设置圆点指示器的位置
  * #bannerm.index_position_right or #bannerm.index_position_bottom
  *
  * @param indexposition
  * @return bannerm
  */
 public bannerm setindexposition(int indexposition) {
  this.indexposition = indexposition;
  return this;
 }

 /**
  * 选中圆点的颜色值,默认为#ff3333
  *
  * @param indexcolor
  * @return bannerm
  */
 public bannerm setindexcolor(int indexcolor) {
  this.indexcolorresid = indexcolor;
  return this;
 }

 /**
  * 设置轮播图需要的数据列表
  *
  * @param bannerbeanlist
  * @return bannerm
  */
 public bannerm setbannerbeanlist(list<bannerbean> bannerbeanlist) {
  this.bannerbeanlist = bannerbeanlist;
  return this;
 }

 /**
  * 设置图片的点击事件
  * @param listener
  */
 public bannerm setonitemclicklistener(@nullable onitemclicklistener listener) {
  monitemclicklistener = listener;
  return this;
 }

 public void show() {
  if (bannerbeanlist == null || bannerbeanlist.size() == 0) {
   throw new illegalargumentexception("bannerbeanlist == null");
  }
  initimageviewlist();
  initindexlist();
  vpbanner.addonpagechangelistener(new onpagechangelistener());
  adapter = new viewpageradapter();
  vpbanner.setadapter(adapter);
  //定时器开始工作
  startplay();
 }

 /**
  * 初始化圆点指示器,根据indexposition来加载不同的布局
  */
 private void initindexlist() {
  int count = bannerbeanlist.size();
  vlist = new arraylist<>(count);
  linearlayout llindex;
  if (indexposition == index_position_right) {
   viewstub vsindexright = (viewstub) findviewbyid(r.id.vs_index_right);
   vsindexright.inflate();
   llindex = (linearlayout) findviewbyid(r.id.ll_index_right);
   tvtext = (textview) findviewbyid(r.id.tv_text);
  } else {
   viewstub vsindexbottom = (viewstub) findviewbyid(r.id.vs_index_bottom);
   vsindexbottom.inflate();
   llindex = (linearlayout) findviewbyid(r.id.ll_index_bottom);
   tvtext = (textview) findviewbyid(r.id.tv_text);
  }
  //默认第一张图片的文字描述
  tvtext.settext(bannerbeanlist.get(0).gettext());
  //使用gradientdrawable构造圆形控件
  gradientdrawable = new gradientdrawable();
  gradientdrawable.setshape(gradientdrawable.oval);
  gradientdrawable.setcolor(mcontext.getresources().getcolor(r.color.text));
  gradientdrawableselected = new gradientdrawable();
  gradientdrawableselected.setshape(gradientdrawable.oval);
  if (indexcolorresid != 0) {
   gradientdrawableselected.setcolor(indexcolorresid);
  } else {
   gradientdrawableselected.setcolor(mcontext.getresources().getcolor(r.color.maincolor));
  }

  for (int i = 0; i < count; i++) {
   view view = new view(mcontext);
   linearlayout.layoutparams lpview = new linearlayout.layoutparams(convertm.dp2px(mcontext, 8), convertm.dp2px(mcontext, 8));
   lpview.rightmargin = convertm.dp2px(mcontext, 4);
   view.setlayoutparams(lpview);
   if (0 == i) {
    view.setbackgrounddrawable(gradientdrawableselected);
   } else {
    view.setbackgrounddrawable(gradientdrawable);
   }
   view.bringtofront();
   vlist.add(view);
   llindex.addview(view);
  }
 }

 /**
  * 初始化imageview,使用picasso下载图片,只在sdcard中缓存
  */
 private void initimageviewlist() {
  int count = bannerbeanlist.size();
  ivlist = new arraylist<>(count);
  for (int i = 0; i < count; i++) {
   final imageview imageview = new imageview(mcontext);
   imageview.setscaletype(imageview.scaletype.center_crop);
   ivlist.add(imageview);
   imageview.setonclicklistener(new onclicklistener() {
    @override
    public void onclick(view v) {
     monitemclicklistener.onitemclick(getposition(imageview));
    }
   });
   if (defaultimageresid != 0) {
    picasso.with(mcontext)
      .load(bannerbeanlist.get(i).geturl())
      .placeholder(defaultimageresid)
      .memorypolicy(memorypolicy.no_cache, memorypolicy.no_store)
      .into(imageview);
   } else if (defaultimagedrawable != null) {
    picasso.with(mcontext)
      .load(bannerbeanlist.get(i).geturl())
      .placeholder(defaultimagedrawable)
      .memorypolicy(memorypolicy.no_cache, memorypolicy.no_store)
      .into(imageview);
   } else {
    picasso.with(mcontext)
      .load(bannerbeanlist.get(i).geturl())
      .memorypolicy(memorypolicy.no_cache, memorypolicy.no_store)
      .into(imageview);
   }
  }
 }

 private void startplay() {
  scheduledexecutorservice = executors.newsinglethreadscheduledexecutor();
  scheduledexecutorservice.scheduleatfixedrate(new runnable() {
   @override
   public void run() {
    currentindex++;
    handler.obtainmessage(handle_update_index).sendtotarget();
   }
  }, intervaltime, intervaltime, timeunit.seconds);
 }

 /**
  * 获取点击图片的位置
  * @param item
  * @return int
  */
 private int getposition(imageview item) {
  for (int i = 0; i < ivlist.size(); i++) {
   if (item == ivlist.get(i)) {
    return i;
   }
  }
  return -1;
 }

 @suppresslint("handlerleak")
 private handler handler = new handler() {
  @override
  public void handlemessage(message msg) {
   switch (msg.what) {
    case handle_update_index:
     vpbanner.setcurrentitem(currentindex);
     break;
    default:
     break;
   }
  }
 };

 private class onpagechangelistener implements viewpager.onpagechangelistener {
  @override
  public void onpagescrolled(int position, float positionoffset, int positionoffsetpixels) {
  }

  @override
  public void onpageselected(int position) {
   currentindex = position;
   for (int i = 0; i < bannerbeanlist.size(); i++) {
    if (position % ivlist.size() == i) {
     vlist.get(i).setbackgrounddrawable(gradientdrawableselected);
    } else {
     vlist.get(i).setbackgrounddrawable(gradientdrawable);
    }
    tvtext.settext(bannerbeanlist.get(position % ivlist.size()).gettext());
   }
  }

  @override
  public void onpagescrollstatechanged(int state) {
  }
 }


 private class viewpageradapter extends pageradapter {
  @override
  public void destroyitem(view container, int position, object object) {
  }

  @override
  public object instantiateitem(view container, int position) {
   position %= ivlist.size();
   if (position<0){
    position = ivlist.size()+position;
   }
   imageview imageview = ivlist.get(position);
   viewparent vp =imageview.getparent();
   if (vp!=null){
    viewgroup parent = (viewgroup)vp;
    parent.removeview(imageview);
   }
   ((viewpager) container).addview(imageview);
   return imageview;
  }

  @override
  public int getcount() {
   return integer.max_value;
  }

  @override
  public boolean isviewfromobject(view arg0, object arg1) {
   return arg0 == arg1;
  }

  @override
  public void restorestate(parcelable arg0, classloader arg1) {

  }

  @override
  public parcelable savestate() {
   return null;
  }

  @override
  public void startupdate(view arg0) {
  }

  @override
  public void finishupdate(view arg0) {
  }
 }

 public interface onitemclicklistener {
  void onitemclick(int position);
 }
}

这篇文章就介绍到这里了,点击查看源码

下面是测试用的图片:

Android自定义控件实现优雅的广告轮播图

Android自定义控件实现优雅的广告轮播图

Android自定义控件实现优雅的广告轮播图

以上就是本文的全部内容,希望对大家的学习有所帮助,也希望大家多多支持。