Android 自定義閃屏頁廣告倒計(jì)時(shí)view效果
如今APP越來越多,我們每天所使用的的軟件也越來越多,可是在我們不付費(fèi)的情況下,App制造商如何實(shí)現(xiàn),實(shí)現(xiàn)收入甚至是盈利呢?答案就是在我們打開軟件所必須經(jīng)過的地方穿插廣告,當(dāng)然為了顧及用戶的感受,一般都會(huì)以倒計(jì)時(shí)的形式展示給用戶,用戶可以選擇跳過.可能是因?yàn)樽约旱膹?qiáng)迫癥,總想著是怎么做的,自己就嘗試了一下,分享給大家的同時(shí),順便加深自己的理解.效果如圖:
1.為了滿足產(chǎn)品和設(shè)計(jì),先搞幾個(gè)自定義屬性
1)內(nèi)層背景
2)數(shù)字的顏色
3)外層圓環(huán)寬度
4)文字大小
5)外層圓環(huán)顏色
6)圓的半徑
這里,我的外環(huán)顏色和文字顏色相同,具體的自定義屬性如下:
<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的構(gòu)造方法中讀取自定義屬性:
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()方法,
根據(jù)寬高得出半徑,為什么不適用自定義半徑呢?因?yàn)楦鶕?jù)寬高得出的半徑才是這個(gè)View的內(nèi)切圓半徑,自定義半徑只是為了在根據(jù)寬高無法得出半徑的情況下才使用的.
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方法進(jìn)行繪制
1)繪制內(nèi)層圓
canvas.drawCircle(mCirCleX, mCircleY, (float) (mRadius - 1.5 * mProgressViewWidth), mPaint);
2)繪制文字,要計(jì)算好文字的位置,保持居中
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);
//獲取繪制內(nèi)容的Rect
private Rect getTextRect(String centerContent) {
Rect rect = new Rect();
mTextPaint.getTextBounds(centerContent, 0, centerContent.length(), rect);
return rect;
}
3)繪制外層不斷刷新的圓環(huán)
原理:從360度開始每隔一段時(shí)間進(jìn)行圓弧繪制,角度分別為:360,359,1,0,因此需要一個(gè)輪詢器,不斷的去繪制刷新.
繪制圓弧的代碼:
//保存Canvans的狀態(tài),因?yàn)槔L制其他地方時(shí),Canvas坐標(biāo)系不需要變化 canvas.save(); //將坐標(biāo)系圍繞View的中心逆時(shí)針旋轉(zhuǎn)90度數(shù),為了從正上方開始繪制 canvas.rotate(-90, mCirCleX, mCircleY); //計(jì)算圓弧的RectF RectF rectF = new RectF(mCirCleX - mRadius + mProgressViewWidth, mCirCleX - mRadius + mProgressViewWidth, mCirCleX + mRadius - mProgressViewWidth, mCirCleX + mRadius - mProgressViewWidth); //第四個(gè)參數(shù)表示逆時(shí)針還是順時(shí)針繪制 canvas.drawArc(rectF, 0, -mCurrentAngle, false, mPaint); //恢復(fù)坐標(biāo)系 canvas.restore();
--------------------------------------------------------------------------------
5.刷新的輪詢器
1)使用RxAndroid和lambda實(shí)現(xiàn)
//interval操作符:從1開始每隔一段時(shí)間發(fā)射遞增的數(shù)
Observable.interval(1, TIME_DIFF, TimeUnit.MILLISECONDS)
//map操作符將發(fā)射的數(shù)據(jù)轉(zhuǎn)換成我們需要的數(shù)據(jù)
.map(value -> {
return countAngel - value.intValue();
})
//限制發(fā)射的數(shù)據(jù)個(gè)數(shù),讓其停止,負(fù)責(zé)會(huì)一直發(fā)射下去
.limit(361)
//接收結(jié)果并處理
.subscribe(action -> {
if (action % 72 == 0) {
mAdTIme = action / 72;
}
mCurrentAngle = action;
AdTimePickView.this.postInvalidate();
});
2)使用線程的方式實(shí)現(xiàn)
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,這樣我們的廣告倒計(jì)時(shí)View就完成了,歡迎大家指正.
附:整個(gè)自定義View的代碼
public class AdTimePickView extends View {
private Paint mPaint;
private Paint mTextPaint;
//大圓半徑
private int mRadius = 200;
//內(nèi)層小圓背景
private int mSmallCircleBg = Color.parseColor("#66f1679b");
//小圓外層線條寬度
private int mProgressViewWidth = 10;
private float mCurrentAngle;
private static final int TIME_DIFF = 25;
//圓心坐標(biāo)
private int mCirCleX;
private int mCircleY;
//測(cè)量之后View的寬高,繪制中心文字時(shí)需要用到
private int mWidth;
private int mHeight;
//中心文字的大小與樣式
private int mTextSize;
private int mTextColor;
//廣告總時(shí)間
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);
//設(shè)置畫筆狀態(tài)
mPaint.setColor(mTextColor);
mPaint.setStyle(Paint.Style.STROKE);
mPaint.setStrokeWidth(mProgressViewWidth);
//保存Canvans的狀態(tài)
canvas.save();
//將坐標(biāo)系圍繞View的中心逆時(shí)針旋轉(zhuǎn)90度數(shù)
canvas.rotate(-90, mCirCleX, mCircleY);
RectF rectF = new RectF(mCirCleX - mRadius + mProgressViewWidth, mCirCleX - mRadius + mProgressViewWidth, mCirCleX + mRadius - mProgressViewWidth, mCirCleX + mRadius - mProgressViewWidth);
//第四個(gè)參數(shù)表示逆時(shí)針還是順時(shí)針繪制
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 自定義閃屏頁廣告倒計(jì)時(shí)view效果,希望對(duì)大家有所幫助,如果大家有任何疑問歡迎給我留言,小編會(huì)及時(shí)回復(fù)大家的,在此也非常感謝大家對(duì)腳本之家網(wǎng)站的支持!
相關(guān)文章
Android實(shí)現(xiàn)動(dòng)態(tài)高斯模糊效果
在Android開發(fā)中常常會(huì)用到高斯模糊,但有的時(shí)候我們可能會(huì)需要一個(gè)圖片以不同的模糊程度展現(xiàn)出來,那如何實(shí)現(xiàn)呢,一起通過本文來學(xué)習(xí)學(xué)習(xí)吧。2016-08-08
Android編程實(shí)現(xiàn)顯示在標(biāo)題上的進(jìn)度條功能【附源碼下載】
這篇文章主要介紹了Android編程實(shí)現(xiàn)顯示在標(biāo)題上的進(jìn)度條功能,涉及Android界面布局及相關(guān)組件屬性設(shè)置技巧,并附帶完整實(shí)例源碼供讀者下載參考,需要的朋友可以參考下2018-01-01
Android6.0指紋識(shí)別開發(fā)實(shí)例詳解
這篇文章主要介紹了Android6.0指紋識(shí)別開發(fā)實(shí)例詳解的相關(guān)資料,需要的朋友可以參考下2017-04-04
Android DrawLayout結(jié)合ListView用法實(shí)例
這篇文章主要介紹了Android DrawLayout結(jié)合ListView用法實(shí)例,文中通過示例代碼介紹的非常詳細(xì),對(duì)大家的學(xué)習(xí)或者工作具有一定的參考學(xué)習(xí)價(jià)值,需要的朋友可以參考下2020-09-09
Android實(shí)現(xiàn)引導(dǎo)頁的圓點(diǎn)指示器
這篇文章主要為大家詳細(xì)介紹了Android實(shí)現(xiàn)引導(dǎo)頁的圓點(diǎn)指示器,文中示例代碼介紹的非常詳細(xì),具有一定的參考價(jià)值,感興趣的小伙伴們可以參考一下2021-06-06
Android 超詳細(xì)深刨Activity Result API的使用
這篇文章主要介紹了Android開發(fā)中Activity Result API的使用,掌握了它以后你就可以放棄startActivityForResult了,感興趣的朋友一起來看看吧2022-03-03
Android實(shí)現(xiàn)原生鎖屏頁面音樂控制
這篇文章主要介紹了Android實(shí)現(xiàn)原生鎖屏頁面音樂控制,文中示例代碼介紹的非常詳細(xì),具有一定的參考價(jià)值,感興趣的小伙伴們可以參考一下2019-12-12
Android判斷應(yīng)用程序退到后臺(tái)的方法(示例代碼)
判斷手機(jī)是否退到后臺(tái),這是我們?cè)贏ndroid開發(fā)中實(shí)現(xiàn)一些功能時(shí),經(jīng)常會(huì)考慮的問題,這篇文章主要介紹了android判斷應(yīng)用程序退到后臺(tái)的方法,需要的朋友可以參考下2023-03-03

