如今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效果,希望对大家有所帮助,如果大家有任何疑问欢迎给我留言,小编会及时回复大家的,在此也非常感谢大家对网站的支持!
# android
# 闪屏页倒计时
# Android实现闪屏页效果
# Android Handler实现闪屏页倒计时代码
# Android中使用Handler及Countdowntimer实现包含倒计时的闪屏页面
# Android应用闪屏页延迟跳转的三种写法
# Android 实现闪屏页和右上角的倒计时跳转实例代码
# Android App实现闪屏页广告图的全屏显示实例
# 自定义
# 小圆
# 自己的
# 倒计时
# 给大家
# 每隔
# 小编
# 顺时针
# 情况下
# 几个
# 是在
# 是因为
# 才是
# 在此
# 不需要
# 要用
# 欢迎大家
# 重写
# 分别为
# 怎么做
相关文章:
制作网站公司那家好,网络公司是做什么的?
如何通过智能用户系统一键生成高效建站方案?
h5在线制作网站电脑版下载,h5网页制作软件?
已有域名如何免费搭建网站?
如何彻底卸载建站之星软件?
如何在云主机快速搭建网站站点?
魔方云NAT建站如何实现端口转发?
成都响应式网站开发,dw怎么把手机适应页面变成网页?
如何选择长沙网站建站模板?H5响应式与品牌定制哪个更优?
免费制作统计图的网站有哪些,如何看待现如今年轻人买房难的情况?
完全自定义免费建站平台:主题模板在线生成一站式服务
宝塔Windows建站如何避免显示默认IIS页面?
合肥做个网站多少钱,合肥本地有没有比较靠谱的交友平台?
PHP正则匹配日期和时间(时间戳转换)的实例代码
韩国网站服务器搭建指南:VPS选购、域名解析与DNS配置推荐
如何在阿里云购买域名并搭建网站?
深圳网站制作平台,深圳市做网站好的公司有哪些?
如何快速查询网站的真实建站时间?
建站之星如何快速生成多端适配网站?
东莞市网站制作公司有哪些,东莞找工作用什么网站好?
定制建站流程步骤详解:一站式方案设计与开发指南
建站之星如何助力企业快速打造五合一网站?
车管所网站制作流程,交警当场开简易程序处罚决定书,在交警网站查询不到怎么办?
建站上市公司网站建设方案与SEO优化服务定制指南
想学网站制作怎么学,建立一个网站要花费多少?
网站制作软件免费下载安装,有哪些免费下载的软件网站?
上海网站制作网站建设公司,建筑电工证网上查询系统入口?
如何确认建站备案号应放置的具体位置?
网站建设设计制作营销公司南阳,如何策划设计和建设网站?
建站之星手机一键生成:多端自适应+小程序开发快速建站指南
如何打造高效商业网站?建站目的决定转化率
怎么制作网站设计模板图片,有电商商品详情页面的免费模板素材网站推荐吗?
如何制作网站标识牌,动态网站如何制作(教程)?
小型网站制作HTML,*游戏网站怎么搭建?
内网网站制作软件,内网的网站如何发布到外网?
简单实现Android验证码
电脑免费海报制作网站推荐,招聘海报哪个网站多?
C++中的Pimpl idiom是什么,有什么好处?(隐藏实现)
mc皮肤壁纸制作器,苹果平板怎么设置自己想要的壁纸我的世界?
北京的网站制作公司有哪些,哪个视频网站最好?
建站之星2.7模板快速切换与批量管理功能操作指南
全景视频制作网站有哪些,全景图怎么做成网页?
实现虚拟支付需哪些建站技术支撑?
制作网站的模板软件,网站怎么建设?
大连 网站制作,大连天途有线官网?
如何在Golang中引入测试模块_Golang测试包导入与使用实践
宝华建站服务条款解析:五站合一功能与SEO优化设置指南
怎么将XML数据可视化 D3.js加载XML
怎么制作一个起泡网,水泡粪全漏粪育肥舍冬季氨气超过25ppm,可以有哪些措施降低舍内氨气水平?
如何在阿里云部署织梦网站?
*请认真填写需求信息,我们会在24小时内与您取得联系。