Android 自定义闪屏页广告倒计时view效果
如今app越来越多,我们每天所使用的的软件也越来越多,可是在我们不付费的情况下,app制造商如何实现,实现收入甚至是盈利呢?答案就是在我们打开软件所必须经过的地方穿插广告,当然为了顾及用户的感受,一般都会以倒计时的形式展示给用户,用户可以选择跳过.可能是因为自己的强迫症,总想着是怎么做的,自己就尝试了一下,分享给大家的同时,顺便加深自己的理解.效果如图:
1.为了满足产品和设计,先搞几个自定义属性
1)内层背景
2)数字的颜色
3)外层圆环宽度
4)文字大小
5)外层圆环颜色
6)圆的半径
这里,我的外环颜色和文字颜色相同,具体的自定义属性如下:
<declare-styleable name="adtimepickview"> <attr name="msmallcirclebg" format="color"></attr> <attr name="mtextsize1" format="dimension"></attr> <attr name="mtextcolor1" format="color"></attr> <attr name="mprogresswidth" format="dimension"></attr> <attr name="mradius" format="dimension"></attr> </declare-styleable>
--------------------------------------------------------------------------------
2.在自定义view的构造方法中读取自定义属性:
mprogressviewwidth = typedarray.getdimensionpixelsize(r.styleable.adtimepickview_mprogresswidth, default_progress_width); mradius = typedarray.getdimensionpixelsize(r.styleable.adtimepickview_mradius1, default_radius); msmallcirclebg = typedarray.getcolor(r.styleable.adtimepickview_msmallcirclebg, color.parsecolor(default_bg_color)); mtextsize = typedarray.getdimensionpixelsize(r.styleable.adtimepickview_mtextsize1, default_text_size); mtextcolor = typedarray.getcolor(r.styleable.adtimepickview_mtextcolor1, color.parsecolor(default_text_color));
--------------------------------------------------------------------------------
3.重写onmeasure()方法,
根据宽高得出半径,为什么不适用自定义半径呢?因为根据宽高得出的半径才是这个view的内切圆半径,自定义半径只是为了在根据宽高无法得出半径的情况下才使用的.
protected void onmeasure(int widthmeasurespec, int heightmeasurespec) { super.onmeasure(widthmeasurespec, heightmeasurespec); mwidth = getviewsize(widthmeasurespec, 0); mheight = getviewsize(heightmeasurespec, 1); mradius = math.min(mwidth, mheight) / 2; setmeasureddimension(mwidth, mheight); }
getviewsize方法如下:
private int getviewsize(int viewmeasurespec, int type) { int viewvalue = 0; int viewsize = measurespec.getsize(viewmeasurespec); int viewmode = measurespec.getmode(viewmeasurespec); if (measurespec.exactly == viewmode) { viewvalue = viewsize; if (type == 0) { mcirclex = viewsize / 2; } else { mcircley = viewsize / 2; } } else { if (type == 0) { mcirclex = mradius; } else { mcircley = mradius; } viewvalue = 2 * (mradius + mprogressviewwidth); } return viewvalue; }
--------------------------------------------------------------------------------
4.ondraw方法进行绘制
1)绘制内层圆
canvas.drawcircle(mcirclex, mcircley, (float) (mradius - 1.5 * mprogressviewwidth), mpaint);
2)绘制文字,要计算好文字的位置,保持居中
rect textrect = gettextrect(string.valueof(madtime)); paint.fontmetrics fontmetrics = mtextpaint.getfontmetrics(); int baseline = (int) (mheight / 2 + (fontmetrics.descent - fontmetrics.ascent) / 2 - fontmetrics.descent); int x = mwidth / 2 - textrect.width() / 2; canvas.drawtext(string.valueof(madtime), x, baseline, mtextpaint); //获取绘制内容的rect private rect gettextrect(string centercontent) { rect rect = new rect(); mtextpaint.gettextbounds(centercontent, 0, centercontent.length(), rect); return rect; }
3)绘制外层不断刷新的圆环
原理:从360度开始每隔一段时间进行圆弧绘制,角度分别为:360,359,1,0,因此需要一个轮询器,不断的去绘制刷新.
绘制圆弧的代码:
//保存canvans的状态,因为绘制其他地方时,canvas坐标系不需要变化 canvas.save(); //将坐标系围绕view的中心逆时针旋转90度数,为了从正上方开始绘制 canvas.rotate(-90, mcirclex, mcircley); //计算圆弧的rectf rectf rectf = new rectf(mcirclex - mradius + mprogressviewwidth, mcirclex - mradius + mprogressviewwidth, mcirclex + mradius - mprogressviewwidth, mcirclex + mradius - mprogressviewwidth); //第四个参数表示逆时针还是顺时针绘制 canvas.drawarc(rectf, 0, -mcurrentangle, false, mpaint); //恢复坐标系 canvas.restore();
--------------------------------------------------------------------------------
5.刷新的轮询器
1)使用rxandroid和lambda实现
//interval操作符:从1开始每隔一段时间发射递增的数 observable.interval(1, time_diff, timeunit.milliseconds) //map操作符将发射的数据转换成我们需要的数据 .map(value -> { return countangel - value.intvalue(); }) //限制发射的数据个数,让其停止,负责会一直发射下去 .limit(361) //接收结果并处理 .subscribe(action -> { if (action % 72 == 0) { madtime = action / 72; } mcurrentangle = action; adtimepickview.this.postinvalidate(); });
2)使用线程的方式实现
new thread(new runnable() { @override public void run() { for (int i = 360; i>=0;i--){ try { thread.sleep(100); } catch (interruptedexception e) { e.printstacktrace(); } if (i % 72 == 0) { madtime = i / 72; } mcurrentangle = i; adtimepickview.this.postinvalidate(); } } }).start();
ok,这样我们的广告倒计时view就完成了,欢迎大家指正.
附:整个自定义view的代码
public class adtimepickview extends view { private paint mpaint; private paint mtextpaint; //大圆半径 private int mradius = 200; //内层小圆背景 private int msmallcirclebg = color.parsecolor("#66f1679b"); //小圆外层线条宽度 private int mprogressviewwidth = 10; private float mcurrentangle; private static final int time_diff = 25; //圆心坐标 private int mcirclex; private int mcircley; //测量之后view的宽高,绘制中心文字时需要用到 private int mwidth; private int mheight; //中心文字的大小与样式 private int mtextsize; private int mtextcolor; //广告总时间 private int madtime = 5; private context mcontext; public adtimepickview(context context) { this(context, null); } public adtimepickview(context context, attributeset attrs) { this(context, attrs, 0); } public adtimepickview(context context, attributeset attrs, int defstyleattr) { super(context, attrs, defstyleattr); typedarray typedarray = context.obtainstyledattributes(attrs, r.styleable.adtimepickview, defstyleattr, 0); mprogressviewwidth = typedarray.getdimensionpixelsize(r.styleable.adtimepickview_mprogresswidth, 10); mradius = typedarray.getdimensionpixelsize(r.styleable.adtimepickview_mradius1, 100); msmallcirclebg = typedarray.getcolor(r.styleable.adtimepickview_msmallcirclebg, color.parsecolor("#66f1679b")); mtextsize = typedarray.getdimensionpixelsize(r.styleable.adtimepickview_mtextsize1, 20); mtextcolor = typedarray.getcolor(r.styleable.adtimepickview_mtextcolor1, color.parsecolor("#333333")); //注意资源的回收 typedarray.recycle(); this.mcontext = context; init(); } private void init() { mpaint = new paint(paint.anti_alias_flag); mpaint.setantialias(true); mtextpaint = new paint(paint.anti_alias_flag); mtextpaint.setcolor(mtextcolor); mtextpaint.settextsize(mtextsize); mtextpaint.setstyle(paint.style.fill); mtextpaint.setantialias(true); } @override protected void onmeasure(int widthmeasurespec, int heightmeasurespec) { super.onmeasure(widthmeasurespec, heightmeasurespec); mwidth = getviewsize(widthmeasurespec, 0); mheight = getviewsize(heightmeasurespec, 1); //大半径 mradius = math.min(mwidth, mheight) / 2; setmeasureddimension(mwidth, mheight); } private int getviewsize(int viewmeasurespec, int type) { int viewvalue = 0; int viewsize = measurespec.getsize(viewmeasurespec); int viewmode = measurespec.getmode(viewmeasurespec); if (measurespec.exactly == viewmode) { viewvalue = viewsize; if (type == 0) { mcirclex = viewsize / 2; } else { mcircley = viewsize / 2; } } else { if (type == 0) { mcirclex = mradius; } else { mcircley = mradius; } viewvalue = 2 * (mradius + mprogressviewwidth); } return viewvalue; } @override protected void ondraw(canvas canvas) { super.ondraw(canvas); mpaint.setcolor(msmallcirclebg); mpaint.setstyle(paint.style.fill); canvas.drawcircle(mcirclex, mcircley, (float) (mradius - 1.5 * mprogressviewwidth), mpaint); //设置画笔状态 mpaint.setcolor(mtextcolor); mpaint.setstyle(paint.style.stroke); mpaint.setstrokewidth(mprogressviewwidth); //保存canvans的状态 canvas.save(); //将坐标系围绕view的中心逆时针旋转90度数 canvas.rotate(-90, mcirclex, mcircley); rectf rectf = new rectf(mcirclex - mradius + mprogressviewwidth, mcirclex - mradius + mprogressviewwidth, mcirclex + mradius - mprogressviewwidth, mcirclex + mradius - mprogressviewwidth); //第四个参数表示逆时针还是顺时针绘制 canvas.drawarc(rectf, 0, -mcurrentangle, false, mpaint); canvas.restore(); rect textrect = gettextrect(string.valueof(madtime)); paint.fontmetrics fontmetrics = mtextpaint.getfontmetrics(); int baseline = (int) (mheight / 2 + (fontmetrics.descent - fontmetrics.ascent) / 2 - fontmetrics.descent); int x = mwidth / 2 - textrect.width() / 2; canvas.drawtext(string.valueof(madtime), x, baseline, mtextpaint); } private rect gettextrect(string centercontent) { rect rect = new rect(); mtextpaint.gettextbounds(centercontent, 0, centercontent.length(), rect); return rect; } public void refresh() { final int countangel = 360; observable.interval(1, time_diff, timeunit.milliseconds) .map(value -> { return countangel - value.intvalue(); }) .limit(361) .subscribe(action -> { if (action % 72 == 0) { madtime = action / 72; } mcurrentangle = action; adtimepickview.this.postinvalidate(); }); } }
以上所述是小编给大家介绍的android 自定义闪屏页广告倒计时view效果,希望对大家有所帮助