热门标签 | HotTags
当前位置:  开发笔记 > Android > 正文

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

这篇文章主要介绍了Android自定义闪屏页广告倒计时view效果,需要的朋友可以参考下

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

这里写图片描述
这里写图片描述 

1.为了满足产品和设计,先搞几个自定义属性

1)内层背景
2)数字的颜色
3)外层圆环宽度
4)文字大小
5)外层圆环颜色
6)圆的半径

 这里,我的外环颜色和文字颜色相同,具体的自定义属性如下:


  
  
  
  
  
 

--------------------------------------------------------------------------------

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效果,希望对大家有所帮助,如果大家有任何疑问欢迎给我留言,小编会及时回复大家的,在此也非常感谢大家对网站的支持!


推荐阅读
  • 2023 ARM嵌入式系统全国技术巡讲旨在分享ARM公司在半导体知识产权(IP)领域的最新进展。作为全球领先的IP提供商,ARM在嵌入式处理器市场占据主导地位,其产品广泛应用于90%以上的嵌入式设备中。此次巡讲将邀请来自ARM、飞思卡尔以及华清远见教育集团的行业专家,共同探讨当前嵌入式系统的前沿技术和应用。 ... [详细]
  • Android 九宫格布局详解及实现:人人网应用示例
    本文深入探讨了人人网Android应用中独特的九宫格布局设计,解析其背后的GridView实现原理,并提供详细的代码示例。这种布局方式不仅美观大方,而且在现代Android应用中较为少见,值得开发者借鉴。 ... [详细]
  • CSS 布局:液态三栏混合宽度布局
    本文介绍了如何使用 CSS 实现液态的三栏布局,其中各栏具有不同的宽度设置。通过调整容器和内容区域的属性,可以实现灵活且响应式的网页设计。 ... [详细]
  • Linux 系统启动故障排除指南:MBR 和 GRUB 问题
    本文详细介绍了 Linux 系统启动过程中常见的 MBR 扇区和 GRUB 引导程序故障及其解决方案,涵盖从备份、模拟故障到恢复的具体步骤。 ... [详细]
  • 本文介绍了如何使用jQuery根据元素的类型(如复选框)和标签名(如段落)来获取DOM对象。这有助于更高效地操作网页中的特定元素。 ... [详细]
  • 本文将详细介绍如何使用剪映应用中的镜像功能,帮助用户轻松实现视频的镜像效果。通过简单的步骤,您可以快速掌握这一实用技巧。 ... [详细]
  • 深入理解Cookie与Session会话管理
    本文详细介绍了如何通过HTTP响应和请求处理浏览器的Cookie信息,以及如何创建、设置和管理Cookie。同时探讨了会话跟踪技术中的Session机制,解释其原理及应用场景。 ... [详细]
  • 本文介绍如何在 Xcode 中使用快捷键和菜单命令对多行代码进行缩进,包括右缩进和左缩进的具体操作方法。 ... [详细]
  • 本文介绍了一款用于自动化部署 Linux 服务的 Bash 脚本。该脚本不仅涵盖了基本的文件复制和目录创建,还处理了系统服务的配置和启动,确保在多种 Linux 发行版上都能顺利运行。 ... [详细]
  • 在Linux系统中配置并启动ActiveMQ
    本文详细介绍了如何在Linux环境中安装和配置ActiveMQ,包括端口开放及防火墙设置。通过本文,您可以掌握完整的ActiveMQ部署流程,确保其在网络环境中正常运行。 ... [详细]
  • Android 渐变圆环加载控件实现
    本文介绍了如何在 Android 中创建一个自定义的渐变圆环加载控件,该控件已在多个知名应用中使用。我们将详细探讨其工作原理和实现方法。 ... [详细]
  • 如何在WPS Office for Mac中调整Word文档的文字排列方向
    本文将详细介绍如何使用最新版WPS Office for Mac调整Word文档中的文字排列方向。通过这些步骤,用户可以轻松更改文本的水平或垂直排列方式,以满足不同的排版需求。 ... [详细]
  • 本文总结了在使用Ionic 5进行Android平台APK打包时遇到的问题,特别是针对QRScanner插件的改造。通过详细分析和提供具体的解决方法,帮助开发者顺利打包并优化应用性能。 ... [详细]
  • 理解存储器的层次结构有助于程序员优化程序性能,通过合理安排数据在不同层级的存储位置,提升CPU的数据访问速度。本文详细探讨了静态随机访问存储器(SRAM)和动态随机访问存储器(DRAM)的工作原理及其应用场景,并介绍了存储器模块中的数据存取过程及局部性原理。 ... [详细]
  • 360SRC安全应急响应:从漏洞提交到修复的全过程
    本文详细介绍了360SRC平台处理一起关键安全事件的过程,涵盖从漏洞提交、验证、排查到最终修复的各个环节。通过这一案例,展示了360在安全应急响应方面的专业能力和严谨态度。 ... [详细]
author-avatar
李伟祥祥
这个家伙很懒,什么也没留下!
PHP1.CN | 中国最专业的PHP中文社区 | DevBox开发工具箱 | json解析格式化 |PHP资讯 | PHP教程 | 数据库技术 | 服务器技术 | 前端开发技术 | PHP框架 | 开发工具 | 在线工具
Copyright © 1998 - 2020 PHP1.CN. All Rights Reserved | 京公网安备 11010802041100号 | 京ICP备19059560号-4 | PHP1.CN 第一PHP社区 版权所有