Android 自定義閃屏頁廣告倒計時view效果
如今APP越來越多,我們每天所使用的的軟件也越來越多,可是在我們不付費的情況下,App制造商如何實現(xiàn),實現(xiàn)收入甚至是盈利呢?答案就是在我們打開軟件所必須經(jīng)過的地方穿插廣告,當然為了顧及用戶的感受,一般都會以倒計時的形式展示給用戶,用戶可以選擇跳過.可能是因為自己的強迫癥,總想著是怎么做的,自己就嘗試了一下,分享給大家的同時,順便加深自己的理解.效果如圖:
1.為了滿足產(chǎn)品和設(shè)計,先搞幾個自定義屬性
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ù)寬高得出半徑,為什么不適用自定義半徑呢?因為根據(jù)寬高得出的半徑才是這個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方法進行繪制
1)繪制內(nèi)層圓
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); //獲取繪制內(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度開始每隔一段時間進行圓弧繪制,角度分別為:360,359,1,0,因此需要一個輪詢器,不斷的去繪制刷新.
繪制圓弧的代碼:
//保存Canvans的狀態(tài),因為繪制其他地方時,Canvas坐標系不需要變化 canvas.save(); //將坐標系圍繞View的中心逆時針旋轉(zhuǎn)90度數(shù),為了從正上方開始繪制 canvas.rotate(-90, mCirCleX, mCircleY); //計算圓弧的RectF RectF rectF = new RectF(mCirCleX - mRadius + mProgressViewWidth, mCirCleX - mRadius + mProgressViewWidth, mCirCleX + mRadius - mProgressViewWidth, mCirCleX + mRadius - mProgressViewWidth); //第四個參數(shù)表示逆時針還是順時針繪制 canvas.drawArc(rectF, 0, -mCurrentAngle, false, mPaint); //恢復(fù)坐標系 canvas.restore();
--------------------------------------------------------------------------------
5.刷新的輪詢器
1)使用RxAndroid和lambda實現(xiàn)
//interval操作符:從1開始每隔一段時間發(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ù)個數(shù),讓其停止,負責會一直發(fā)射下去 .limit(361) //接收結(jié)果并處理 .subscribe(action -> { if (action % 72 == 0) { mAdTIme = action / 72; } mCurrentAngle = action; AdTimePickView.this.postInvalidate(); });
2)使用線程的方式實現(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,這樣我們的廣告倒計時View就完成了,歡迎大家指正.
附:整個自定義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; //圓心坐標 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); //設(shè)置畫筆狀態(tài) mPaint.setColor(mTextColor); mPaint.setStyle(Paint.Style.STROKE); mPaint.setStrokeWidth(mProgressViewWidth); //保存Canvans的狀態(tài) canvas.save(); //將坐標系圍繞View的中心逆時針旋轉(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); //第四個參數(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 自定義閃屏頁廣告倒計時view效果,希望對大家有所幫助,如果大家有任何疑問歡迎給我留言,小編會及時回復(fù)大家的,在此也非常感謝大家對腳本之家網(wǎng)站的支持!
相關(guān)文章
Android編程實現(xiàn)顯示在標題上的進度條功能【附源碼下載】
這篇文章主要介紹了Android編程實現(xiàn)顯示在標題上的進度條功能,涉及Android界面布局及相關(guān)組件屬性設(shè)置技巧,并附帶完整實例源碼供讀者下載參考,需要的朋友可以參考下2018-01-01Android DrawLayout結(jié)合ListView用法實例
這篇文章主要介紹了Android DrawLayout結(jié)合ListView用法實例,文中通過示例代碼介紹的非常詳細,對大家的學習或者工作具有一定的參考學習價值,需要的朋友可以參考下2020-09-09Android 超詳細深刨Activity Result API的使用
這篇文章主要介紹了Android開發(fā)中Activity Result API的使用,掌握了它以后你就可以放棄startActivityForResult了,感興趣的朋友一起來看看吧2022-03-03Android判斷應(yīng)用程序退到后臺的方法(示例代碼)
判斷手機是否退到后臺,這是我們在Android開發(fā)中實現(xiàn)一些功能時,經(jīng)常會考慮的問題,這篇文章主要介紹了android判斷應(yīng)用程序退到后臺的方法,需要的朋友可以參考下2023-03-03