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

449cc46fa0f57c335301803440fec756.png

577cd721899458fbd57be9bb27a0a66f.png

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

Logo

华为开发者空间,是为全球开发者打造的专属开发空间,汇聚了华为优质开发资源及工具,致力于让每一位开发者拥有一台云主机,基于华为根生态开发、创新。

更多推荐