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

时间: 2024-09-15 02:28:14

Android 自定义闪屏页广告倒计时view效果的相关文章

Android应用闪屏页延迟跳转的三种写法

闪屏页也称之为欢迎页.在打开一个App时,我们第一眼看到的往往是一个闪屏页面,之所以叫闪屏页,是因为它出现之后会短暂地停留几秒钟再跳转到其他页面.闪屏页除了使用户体验更好外,还能给app留出初始化数据的时间.下面,是我总结的闪屏页的三种写法. 准备工作 打开Android Studio,新建一个projectMyStudy,新建一个SplashActivity并在清单文件中将其设置为启动Activity.在布局文件中将SplashActivity的背景设置为一张图片(可以是手机壁纸). <?xm

Android 实现闪屏页和右上角的倒计时跳转实例代码_Android

以前编程的时候,遇到倒计时的功能时,经常自己去写,但其实Android已经帮封装好了一个倒计时类CountDownTimer,其实是将后台线程的创建和Handler队列封装成为了一个方便的类调用. 闪屏页用到了handler和CountDownTimer类,还需配置一下Activity的主题,这里是:android:theme="@android:style/Theme.NoTitleBar.Fullscreen" 全屏主题的意思. 给大家展示下效果图: 代码如下所示: package

Android 实现闪屏页和右上角的倒计时跳转实例代码

以前编程的时候,遇到倒计时的功能时,经常自己去写,但其实Android已经帮封装好了一个倒计时类CountDownTimer,其实是将后台线程的创建和Handler队列封装成为了一个方便的类调用. 闪屏页用到了handler和CountDownTimer类,还需配置一下Activity的主题,这里是:android:theme="@android:style/Theme.NoTitleBar.Fullscreen" 全屏主题的意思. 给大家展示下效果图: 代码如下所示: package

Android中闪屏实现方法小结(普通闪屏、倒计时闪屏、倒计时+动画闪屏)

一.项目目录结构 二.activity_main.xml代码 <RelativeLayout xmlns:android="http://schemas.android.com/apk/res/android" xmlns:tools="http://schemas.android.com/tools" android:layout_width="match_parent" android:layout_height="match

android 音乐播放器-音乐播放器的闪屏页重复显示

问题描述 音乐播放器的闪屏页重复显示 我给音乐播放器加了一个闪屏页,但是当软件处于后台运行的时候再次打开软件,它依然会显示闪屏.请各位大神们支支招 解决方案 http://blog.csdn.net/jdsjlzx/article/details/7523333

Android实现闪屏及注册和登录界面之间的切换效果_Android

在没给大家介绍正文之前先给大家说下实现思路: 先分别实现闪屏.注册界面.登录界面的活动,再用Intent将相关的活动连接起来,实现不同活动之间的跳转.此次试验代码较多,我只列出主要代码,详细的代码可用底部的下载链接下载. 一.实验效果图: 二.主要代码: (1)WelcomeActivity.Java(这部分代码实现的是第一页的欢迎页面) package com.example.flashscreendemo; import android.app.Activity; import androi

详谈闪屏页相关处理

根据功能模块划分(Android开发推荐此方法) - Activity   mobilesafe.activty     - 后台服务   mobilesafe.service     - 广播接受者 mobilesafe.receiver     - 数据库 mobilesafe.db.dao     - 对象(java bean) mobilesafe.domain/bean     - 自定义控件 mobilesafe.view     - 工具类 mobilesafe.utils    

Android实现闪屏及注册和登录界面之间的切换效果

在没给大家介绍正文之前先给大家说下实现思路: 先分别实现闪屏.注册界面.登录界面的活动,再用Intent将相关的活动连接起来,实现不同活动之间的跳转.此次试验代码较多,我只列出主要代码,详细的代码可用底部的下载链接下载. 一.实验效果图: 二.主要代码: (1)WelcomeActivity.Java(这部分代码实现的是第一页的欢迎页面) package com.example.flashscreendemo; import android.app.Activity; import androi

Android自定义一个图形单点移动缩小的效果

先给大家展示下效果图,如果大家感觉不错,请参考实现代码 效果图如下所示: 代码如下所示: public class MainActivity extends Activity { View view; public static final int DRAG = 1; public static final int SCALE = 2; int mode = 1; int height = 10, width = 10; @Override protected void onCreate(Bun