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

Android 自定义闪屏页广告倒计时view效果

程序员文章站 2023-11-29 11:12:34
如今app越来越多,我们每天所使用的的软件也越来越多,可是在我们不付费的情况下,app制造商如何实现,实现收入甚至是盈利呢?答案就是在我们打开软件所必须经过的地方穿...

如今app越来越多,我们每天所使用的的软件也越来越多,可是在我们不付费的情况下,app制造商如何实现,实现收入甚至是盈利呢?答案就是在我们打开软件所必须经过的地方穿插广告,当然为了顾及用户的感受,一般都会以倒计时的形式展示给用户,用户可以选择跳过.可能是因为自己的强迫症,总想着是怎么做的,自己就尝试了一下,分享给大家的同时,顺便加深自己的理解.效果如图:

Android 自定义闪屏页广告倒计时view效果
Android 自定义闪屏页广告倒计时view效果 

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效果,希望对大家有所帮助