Android自定义控件实现优雅的广告轮播图
程序员文章站
2023-11-12 22:16:22
前言
今天给大家带来一个新的控件–轮播图,网上已经有很多这类的博客来讲解如何实现的,那么我的这个有哪些特点呢?或是说有哪些不同呢?
满足了轮播图的基本要求,循环滑动,在...
前言
今天给大家带来一个新的控件–轮播图,网上已经有很多这类的博客来讲解如何实现的,那么我的这个有哪些特点呢?或是说有哪些不同呢?
满足了轮播图的基本要求,循环滑动,在最后一张切到第一张时可以平稳的过渡
简洁简洁简洁
扩展性强
如何使用
下面我们先展示两种效果图
1 默认效果
代码实现
//布局代码 <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 自定义效果
图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); } }
这篇文章就介绍到这里了,点击查看源码
下面是测试用的图片:
以上就是本文的全部内容,希望对大家的学习有所帮助,也希望大家多多支持。
上一篇: 营销软文要有说服力
下一篇: Python对象与引用的介绍