仿易訊客戶端loading效果
下面來實現一個loading效果。具體效果如下:
首先對這個效果進行拆分,它由以下部分組成:
- 1 一個”閃電”樣式的圖案;
- 2 “閃電”圖案背後是一個圓角矩形;
- 3 “閃電”圖案上面有一層顏色不斷”飄過”
拆分完效果後,思考下如何實現。下面是我的思考過程。
- 1 android sdk並沒有提供這樣的控制元件,很顯然是需要自定義控制元件;
- 2 很顯然是一個View而不是ViewGroup,所以可以繼承View;
- 3 重點是onDraw的邏輯;
- 4 怎樣繪製”閃電”的圖案?可以通過Path繪製;
- 5 怎樣繪製”閃電”背後的圓角矩形?canvas.drawRoundRect;
- 6 怎樣實現”閃電”的動效?仔細觀察,發現上方那層顏色的運動規律是從0~閃電高度不斷擴大,到達閃電高度的時候,高度不斷減小直到0。所以可以通過控制高度的方式實現。只要有兩個變數scanTop/scanBottom記錄繪製的上下界限即可,然後控制scanTop/scanBottom進行變化即可,怎樣控制變化很顯然可以通過post/postDelayed實現。另外一個難點是如何繪製部分”閃電”?思索一番,可以通過canvas.clipRect的方式控制繪製區域,這樣間接實現了我們需要的效果;
- 7 核心邏輯實現之後,需要考慮到應該讓這個自定義控制元件支援wrap_content.這必然需要重寫onMeasure,並考慮到父容器的MeasureSpec(view的預設實現下wrap_content和match_parent效果一樣);
- 8 需要讓這個控制元件支援padding。所以得在measure和draw的過程中充分考慮到padding這個因素;
- 9 當view被detach的時候,需要remove掉動畫;
- 10 應該提供幾個預設大小,比如small/midium/large,這可以通過自定義屬性實現。
大致思考完之後,可以寫程式碼了。
首先是measure過程:
@Override
protected void onMeasure(int widthMeasureSpec, int heightMeasureSpec) {
super.onMeasure(widthMeasureSpec, heightMeasureSpec);
//需要計算自己實際需要的寬高
//需要把padding考慮進來
//需要考慮父容器的測量規則
int width,height;
width = (int)mViewMinWidth+getPaddingLeft()+getPaddingRight();
height = (int)mViewMinHeight+getPaddingTop()+getPaddingBottom();
setMeasuredDimension(getMeasuredSize(widthMeasureSpec, width), getMeasuredSize(heightMeasureSpec, height));
}
通過getMeasuredSize計算考慮父容器限制後的實際大小:
private int getMeasuredSize(int measureSpec,int desiredSize){
int result;
int mode = MeasureSpec.getMode(measureSpec);
int size = MeasureSpec.getSize(measureSpec);
switch (mode){
case MeasureSpec.EXACTLY:
result = size;
break;
default:
result = desiredSize;
if(mode == MeasureSpec.AT_MOST)
result = Math.min(result,size);
break;
}
return result;
}
然後是draw的過程:
@Override
protected void onDraw(Canvas canvas) {
super.onDraw(canvas);
mPaint.setColor(mViewBackground);
//如果xml中設定layout_width/layout_height大於預設寬高,那麼居中(不允許小於預設寬高)
if(getWidth()-getPaddingLeft()-getPaddingRight() > (int)mViewMinWidth || getHeight()-getPaddingTop()-getPaddingBottom() > (int)mViewMinHeight){
canvas.translate((getWidth()-mViewMinWidth)/2.0f,(getHeight()-mViewMinHeight)/2.0f);
}
//畫圓角矩形
canvas.drawRoundRect(mBounds, dp2px(5), dp2px(5), mPaint);
//平移到圓角矩形中心點,畫閃電
canvas.translate((mViewMinWidth - mDefaultWidth) / 2.0f, (mViewMinHeight - mDefaultHeight) / 2.0f);
mPaint.setColor(mBackgroundColor);
canvas.drawPath(mThunderPath, mPaint);
mPaint.setColor(mCoverColor);
//通過clicpRect的方式控制可繪製區域(在外界看來好像有閃動的動畫效果)
canvas.clipRect(getPaddingLeft(), mScanTop + getPaddingTop(), mDefaultWidth + getPaddingLeft(), mScanBottom + getPaddingTop());
canvas.drawPath(mThunderPath, mPaint);
}
mScanTop/mScanBottom變數可以通過post()進行改變:
class AnimRunnable implements Runnable{
@Override
public void run() {
if (!flag) {
mScanBottom += mGap;
if (mScanBottom >= mDefaultHeight) {
mScanBottom = (int) mDefaultHeight;
flag = true;
}
postInvalidate();
post(this);
} else {
mScanTop += mGap;
if (mScanTop >= mDefaultHeight) {
mScanTop = mScanBottom = 0;
flag = false;
postInvalidate();
postDelayed(this, 700);
} else {
postInvalidate();
post(this);
}
}
}
}
private void startAnim() {
mRunnable = new AnimRunnable();
post(mRunnable);
}
核心程式碼就這麼多。
完整程式碼在這裡:https://github.com/Rowandjj/ThunderLoadingView
相關文章
- 仿UC客戶端的快速搜尋訊息通知效果客戶端
- 仿WanAndroid客戶端Flutter版NaNAndroid客戶端Flutter
- TCP/UDP簡易通訊框架原始碼,支援輕鬆管理多個TCP服務端(客戶端)、UDP客戶端TCPUDP框架原始碼服務端客戶端
- 仿今日頭條按鈕loading效果
- Go 實現簡易的 Redis 客戶端GoRedis客戶端
- linux簡易 Oracle客戶端安裝LinuxOracle客戶端
- 完整仿寫鴻洋WanAndroid網站客戶端NaNAndroid網站客戶端
- electron+vue 仿微信客戶端聊天|electron 仿微信介面|electron 聊天例項Vue客戶端
- 看視訊必備:YouTube客戶端客戶端
- C/S(socket、執行緒 實現多個客戶端、伺服器端簡易通訊)執行緒客戶端伺服器
- python實現douban.fm簡易客戶端Python客戶端
- React 伺服器端渲染和客戶端渲染效果對比React伺服器客戶端
- js 客戶端與伺服器端的通訊JS客戶端伺服器
- 「iOS」高仿【少數派】客戶端 程式碼+思路講解iOS客戶端
- IM撤回訊息-iOS客戶端實現iOS客戶端
- Aeron訊息傳遞客戶端--Go版客戶端Go
- 環信即時通訊——整合客戶端客戶端
- Vue實現騰訊視訊Mac客戶端VueMac客戶端
- oracle9i簡易客戶端製作說明Oracle客戶端
- 實現客戶端與服務端的HTTP通訊客戶端服務端HTTP
- 客戶端到伺服器端的通訊過程客戶端伺服器
- 客戶端與服務端Socket通訊原理詳解客戶端服務端
- dubbo客戶端客戶端
- Pulsar客戶端客戶端
- mqtt 客戶端MQQT客戶端
- 客戶端,服務端客戶端服務端
- 服務端,客戶端服務端客戶端
- Flutter 仿微部落格戶端Flutter
- Nacos - 客戶端心跳續約及客戶端總結客戶端
- JAVA通訊(一)——輸入資料到客戶端Java客戶端
- 基於WebSocket的modbus通訊(二)- 客戶端Web客戶端
- zeroc ice 客戶端與服務端通訊例子(c++)客戶端服務端C++
- 物理DataGuard客戶端無縫切換--客戶端TAF 配置客戶端
- 為什麼CDN對移動客戶端加速“沒有”效果客戶端
- 客戶端加解密客戶端解密
- Zookeeper 客戶端 API客戶端API
- java websocket 客戶端JavaWeb客戶端
- 客戶端筆記客戶端筆記