Android自定義View葉子旋轉(zhuǎn)完整版(六)
上一篇實(shí)現(xiàn)多葉子飄動(dòng)旋轉(zhuǎn),今天完成最后的功能。
1、添加右側(cè)旋轉(zhuǎn)楓葉
2、添加滑動(dòng)條效果,顯示百分比
3、修復(fù)葉子飄出邊框問(wèn)題
1、添加右側(cè)旋轉(zhuǎn)葉子
Bitmap turnBitmap = ((BitmapDrawable) mResources.getDrawable(R.drawable.fengshan, null)).getBitmap(); int turnLeafAngle = 0; private void setTurnLeaf(Canvas canvas) { Matrix matrix = new Matrix(); turnLeafAngle = turnLeafAngle + 3; matrix.postTranslate((width - rightCircleWidth/2 - turnBitmap.getWidth()/2), (height - rightCircleWidth/2 - turnBitmap.getHeight()/2)); matrix.postRotate(turnLeafAngle, width - rightCircleWidth/2 - turnBitmap.getWidth()/2 + turnBitmap.getWidth()/2, height - rightCircleWidth/2 - turnBitmap.getHeight()/2 + turnBitmap.getHeight()/2); canvas.drawBitmap(turnBitmap, matrix, new Paint()); }
代碼很明確,首先通過(guò)Matrix.postTranslate(float dx, float dy)把turnBitMap定位到最右側(cè)圓圈
再通過(guò)Matrix.postRotate(float degress, float dx, float dy);設(shè)置旋轉(zhuǎn)角度,每次角度+3°
其中degress為旋轉(zhuǎn)角度,(dx,dy)為旋轉(zhuǎn)中心點(diǎn)坐標(biāo)
2、添加滑動(dòng)效果
原理就是覆蓋一層不同顏色的圖層。根據(jù)當(dāng)前百分比,分別畫(huà)一個(gè)半圓,畫(huà)一個(gè)正方形
a、定義一個(gè)圓形Rectf(為什么不是半圓?因?yàn)楫?huà)圓弧的其實(shí)角度從水平線右側(cè)開(kāi)始)
progressArcRectf = new RectF(0, 0, height, height);
b、定義一個(gè)長(zhǎng)方形Rectf,長(zhǎng)方形x坐標(biāo)起點(diǎn)即時(shí)圓形半徑
progressRectf = new RectF(height/2, 0, width, height);
c、畫(huà)出圓弧Canvas.drawArc(Rectf rectf, float startAngle, float sweepAngle, boolean useCenter, Paint paint)
startAngle:起始角度,默認(rèn)從右側(cè)水平線開(kāi)始
sweepAngle:為旋轉(zhuǎn)的角度,順時(shí)針旋轉(zhuǎn)
useCenter:true只畫(huà)出弧線,false則畫(huà)出圓心到弧線的區(qū)域
//畫(huà)滑動(dòng)后的背景條 int currentProgressWidht = currentProgress * (width - borderWidth)/100; if(currentProgressWidht < leftCircleWidth/2) { //angle取值范圍0~90 int angle = 90 * currentProgressWidht / (leftCircleWidth/2); // 起始的位置 int startAngle = 180 - angle; // 掃過(guò)的角度 int sweepAngle = 2 * angle; canvas.drawArc(progressArcRectf, startAngle, sweepAngle, false, progressBgPaint); }else { //畫(huà)左邊半圓形滑過(guò)部分 canvas.drawArc(progressArcRectf, 90, 180, false, progressBgPaint); progressRectf.left = borderWidth + leftCircleWidth/2; progressRectf.right = borderWidth + currentProgressWidht; //畫(huà)中間滑過(guò)部分 canvas.drawRect(progressRectf, progressBgPaint); }
給LeafView.java添加一個(gè)
public void setCurrentProgress(int currentProgress) { this.currentProgress = currentProgress; }
3、修復(fù)葉子飄動(dòng)范圍
這個(gè)簡(jiǎn)單,就是設(shè)置葉子的rect坐標(biāo)起點(diǎn)+邊框距離
賦上所有代碼
1、activity_leaf.xml
<?xml version="1.0" encoding="utf-8"?> <RelativeLayout xmlns:android="http://schemas.android.com/apk/res/android" android:id="@+id/content_leaf" android:layout_width="match_parent" android:layout_height="match_parent"> <RelativeLayout android:layout_width="226dp" android:layout_height="45dp"> <com.zjcpo.t170313_countdowntimer.LeafView android:id="@+id/leafView" android:layout_width="226dp" android:layout_height="45dp" android:layout_centerHorizontal="true" /> </RelativeLayout> </RelativeLayout>
2、LeafView.java
import android.content.Context; import android.content.res.Resources; import android.graphics.Bitmap; import android.graphics.Canvas; import android.graphics.Color; import android.graphics.Matrix; import android.graphics.Paint; import android.graphics.Rect; import android.graphics.RectF; import android.graphics.drawable.BitmapDrawable; import android.util.AttributeSet; import android.util.Log; import android.view.View; import java.util.LinkedList; import java.util.List; import java.util.Random; import java.util.jar.Attributes; /** * Created by jiemiao.zhang on 2017-3-15. */ public class LeafView extends View { private String TAG = "--------LeafView"; private Resources mResources; //背景圖、葉子 private Bitmap mLeafBitmap, bgBitmap, turnBitmap; //整個(gè)控件的寬度和高度 private int width, height; //最外層邊框?qū)挾? private int borderWidth; //右側(cè)圓形直徑 private int rightCircleWidth; //左側(cè)圓形直徑 private int leftCircleWidth; private Paint bgPaint; private RectF bgRect; private Rect bgDestRect; //進(jìn)度條實(shí)時(shí)背景 private Paint progressBgPaint; //進(jìn)度條左側(cè)半圓,進(jìn)度條中間長(zhǎng)方形部分Rect private RectF progressArcRectf, progressRectf; //當(dāng)前百分比0~100 private int currentProgress = 0; //存放葉子lsit private List<Leaf> leafList; //葉子的寬和高 private int mLeafWidth, mLeafHeight; //葉子滑動(dòng)一周的時(shí)間5秒 private final static long cycleTime = 5000; //葉子數(shù)量 private final static int leafNumber = 6; public LeafView(Context context, AttributeSet attrs) { super(context, attrs); mResources = getResources(); mLeafBitmap = ((BitmapDrawable) mResources.getDrawable(R.drawable.leaf, null)).getBitmap(); mLeafWidth = mLeafBitmap.getWidth(); mLeafHeight = mLeafBitmap.getHeight(); turnBitmap = ((BitmapDrawable) mResources.getDrawable(R.drawable.fengshan, null)).getBitmap(); bgBitmap = ((BitmapDrawable) mResources.getDrawable(R.drawable.leaf_kuang, null)).getBitmap(); bgPaint = new Paint(); bgPaint.setColor(mResources.getColor(R.color.bg_color)); //進(jìn)度條實(shí)時(shí)背景 progressBgPaint = new Paint(); progressBgPaint.setColor(mResources.getColor(R.color.progress_bg_color)); //獲取所有葉子的信息,放入list leafList = getLeafs(leafNumber); } @Override protected void onSizeChanged(int w, int h, int oldw, int oldh) { super.onSizeChanged(w, h, oldw, oldh); width = w; height = h; borderWidth = height * 10/64; rightCircleWidth = width * 62/303; leftCircleWidth = height - 2 * borderWidth; bgDestRect = new Rect(0, 0 , width, height); bgRect = new RectF(0, 0 , width, height); progressArcRectf = new RectF(borderWidth, borderWidth, height - borderWidth, height - borderWidth); progressRectf = new RectF(borderWidth+(height-2*borderWidth)/2, borderWidth, width-rightCircleWidth/2, height-borderWidth); Log.i("leftMarginWidth", (borderWidth + leftCircleWidth/2) + ""); } @Override protected void onDraw(Canvas canvas) { super.onDraw(canvas); //畫(huà)背景顏色到畫(huà)布 canvas.drawRect(bgRect, bgPaint); if(currentProgress <= 100) { //畫(huà)葉子 int size = leafList.size(); for (int i=0; i<size; i++) { Leaf leaf = leafList.get(i); //獲取葉子坐標(biāo) getLocation(leaf); //獲取葉子旋轉(zhuǎn)角度 getRotate(leaf); canvas.save(); Matrix matrix = new Matrix(); //設(shè)置滑動(dòng) matrix.postTranslate(leaf.x, leaf.y); //設(shè)置旋轉(zhuǎn) matrix.postRotate(leaf.rotateAngle, leaf.x + mLeafWidth / 2, leaf.y + mLeafHeight / 2); //添加葉子到畫(huà)布 canvas.drawBitmap(mLeafBitmap, matrix, new Paint()); canvas.restore(); //畫(huà)滑動(dòng)后的背景條 int currentProgressWidht = currentProgress * (width - borderWidth - rightCircleWidth/2)/100; if(currentProgressWidht < leftCircleWidth/2) { //angle取值范圍0~90 int angle = 90 * currentProgressWidht / (leftCircleWidth/2); Log.i(TAG, "angle :" + angle); // 起始的位置 int startAngle = 180 - angle; // 掃過(guò)的角度 int sweepAngle = 2 * angle; canvas.drawArc(progressArcRectf, startAngle, sweepAngle, false, progressBgPaint); }else { //畫(huà)左邊半圓形滑過(guò)部分 canvas.drawArc(progressArcRectf, 90, 180, false, progressBgPaint); progressRectf.left = borderWidth + leftCircleWidth/2; progressRectf.right = borderWidth + currentProgressWidht; //畫(huà)中間滑過(guò)部分 canvas.drawRect(progressRectf, progressBgPaint); } } //調(diào)用onDraw()重復(fù)滑動(dòng) if(currentProgress < 100) { postInvalidate(); } } //畫(huà)背景圖片到畫(huà)布 canvas.drawBitmap(bgBitmap, null, bgDestRect, null); //畫(huà)右邊選擇風(fēng)葉 setTurnLeaf(canvas); //畫(huà)百分比 setText(canvas); } int turnLeafAngle = 0; private void setTurnLeaf(Canvas canvas) { Matrix matrix = new Matrix(); turnLeafAngle = turnLeafAngle + 3; matrix.postTranslate((width - rightCircleWidth/2 - turnBitmap.getWidth()/2), (height - rightCircleWidth/2 - turnBitmap.getHeight()/2)); matrix.postRotate(turnLeafAngle, width - rightCircleWidth/2 - turnBitmap.getWidth()/2 + turnBitmap.getWidth()/2, height - rightCircleWidth/2 - turnBitmap.getHeight()/2 + turnBitmap.getHeight()/2); canvas.drawBitmap(turnBitmap, matrix, new Paint()); } //顯示百分比數(shù)字,大于3%開(kāi)始顯示,到50%停止滑動(dòng) private void setText(Canvas canvas) { Paint paintText = new Paint(); paintText.setColor(Color.WHITE); paintText.setTextSize(30); int textX = currentProgress * width / 100; textX = currentProgress < 50 ? (currentProgress * width / 100) : (width/2); if(currentProgress > 3) { canvas.drawText(currentProgress + "%", textX, height/2 + 10,paintText); } } //獲取每片葉子在XY軸上的滑動(dòng)值 private void getLocation(Leaf leaf) { float betweenTime = leaf.startTime - System.currentTimeMillis(); //周期結(jié)束再加一個(gè)cycleTime if(betweenTime < 0) { leaf.startTime = System.currentTimeMillis() + cycleTime + new Random().nextInt((int) (cycleTime)); betweenTime = cycleTime; } //通過(guò)時(shí)間差計(jì)算出葉子的坐標(biāo) float fraction = (float) betweenTime / cycleTime; float x = (int)(width * fraction); //防止葉子飄出邊框 leaf.x = x < borderWidth ? borderWidth : x; float w = (float) ((float) 2 * Math.PI / width); int y = (int) (18 * Math.sin(w * x)) + (height-mLeafHeight)/2; //防止葉子飄出邊框 y = y > (height - borderWidth) ? (height - borderWidth) : y; y = y < borderWidth ? borderWidth : y; leaf.y = y; } //獲取每片葉子的旋轉(zhuǎn)角度 private void getRotate(Leaf leaf) { float scale = ((leaf.startTime - System.currentTimeMillis())%cycleTime)/ (float)cycleTime; int rotate = (int)(scale * 360); leaf.rotateAngle = rotate; } private class Leaf { // 葉子的坐標(biāo) float x, y; // 旋轉(zhuǎn)角度 int rotateAngle; // 起始時(shí)間(ms) long startTime; } private List<Leaf> getLeafs(int leafSize) { List<Leaf> list = new LinkedList<Leaf>(); for (int i=0; i<leafSize; i++) { list.add(getLeaf()); } return list; } //使葉子初始時(shí)間有間隔 int addTime; private Leaf getLeaf() { Random random = new Random(); Leaf leaf = new Leaf(); leaf.rotateAngle = random.nextInt(360); addTime += random.nextInt((int) (cycleTime)); leaf.startTime = System.currentTimeMillis() + cycleTime + addTime; return leaf; } public void setCurrentProgress(int currentProgress) { this.currentProgress = currentProgress; } } 3、LeafActivity.java public class LeafActivity extends Activity { private LeafView leafView; private int mProgress = 0; Handler mHandler = new Handler() { public void handleMessage(Message msg) { if (mProgress < 40) { mProgress += 1; // 隨機(jī)800ms以內(nèi)刷新一次 mHandler.sendEmptyMessageDelayed(1, new Random().nextInt(800)); leafView.setCurrentProgress(mProgress); } else { mProgress += 1; // 隨機(jī)1200ms以內(nèi)刷新一次 mHandler.sendEmptyMessageDelayed(1, new Random().nextInt(100)); leafView.setCurrentProgress(mProgress); } }; }; @Override protected void onCreate(Bundle savedInstanceState) { super.onCreate(savedInstanceState); setContentView(R.layout.activity_leaf); leafView = (LeafView) findViewById(R.id.leafView); mHandler.sendEmptyMessageDelayed(1, 3000); } }
最后再看下效果
總結(jié)
看過(guò)前5篇的很好理解,用到的技術(shù)點(diǎn)之前都講到了。這篇主要就是幾個(gè)百分比函數(shù)的計(jì)算。
比如設(shè)置半圓時(shí)弧度如何計(jì)算,圓弧對(duì)應(yīng)的百分比,滑動(dòng)區(qū)域長(zhǎng)方形的起點(diǎn)坐標(biāo)計(jì)算,去掉邊框后的坐標(biāo)計(jì)算
畫(huà)半圓必須要有一個(gè)完整圓形Rect,因?yàn)閐rawArc()從右側(cè)半徑水平起始角度,順時(shí)針。然功能要求我們從左側(cè)圓形開(kāi)始畫(huà),所以要通過(guò)一個(gè)算法,假如當(dāng)前百分比為4%,需要畫(huà)30°的圓弧,那么起始角度為165°=180°-15°,畫(huà)出角度30%
通過(guò)matrix.postRotate()實(shí)現(xiàn)旋轉(zhuǎn)功能時(shí),必須加上當(dāng)前view的坐標(biāo)及二分之一長(zhǎng)寬
需要圖片等信息的可以從下面的Github地址下載,不過(guò)原文比較復(fù)雜
參考 https://github.com/Ajian-studio/GALeafLoading
以上就是本文的全部?jī)?nèi)容,希望對(duì)大家的學(xué)習(xí)有所幫助,也希望大家多多支持腳本之家。
- Android自定義View實(shí)現(xiàn)QQ運(yùn)動(dòng)積分轉(zhuǎn)盤(pán)抽獎(jiǎng)功能
- Android 自定View實(shí)現(xiàn)仿QQ運(yùn)動(dòng)步數(shù)圓弧及動(dòng)畫(huà)效果
- Android自定義View仿微博運(yùn)動(dòng)積分動(dòng)畫(huà)效果
- Android UI之ImageView實(shí)現(xiàn)圖片旋轉(zhuǎn)和縮放
- Android使用RotateImageView 旋轉(zhuǎn)ImageView
- Android UI設(shè)計(jì)系列之ImageView實(shí)現(xiàn)ProgressBar旋轉(zhuǎn)效果(1)
- Android自定義View實(shí)現(xiàn)QQ音樂(lè)中圓形旋轉(zhuǎn)碟子
- Android自定義View實(shí)現(xiàn)葉子飄動(dòng)旋轉(zhuǎn)效果(四)
- Android中imageView圖片放大縮小及旋轉(zhuǎn)功能示例代碼
- Android自定義View圖片按Path運(yùn)動(dòng)和旋轉(zhuǎn)
相關(guān)文章
Android實(shí)現(xiàn)簡(jiǎn)單QQ登錄頁(yè)面
這篇文章主要為大家詳細(xì)介紹了Android實(shí)現(xiàn)簡(jiǎn)單QQ登錄頁(yè)面,文中示例代碼介紹的非常詳細(xì),具有一定的參考價(jià)值,感興趣的小伙伴們可以參考一下2022-04-04android實(shí)現(xiàn)通知欄下載更新app示例
這篇文章主要介紹了android實(shí)現(xiàn)通知欄下載更新app示例,需要的朋友可以參考下2014-03-03Android自定義View實(shí)現(xiàn)圓弧進(jìn)度效果逐步完成過(guò)程
在Android開(kāi)發(fā)中,通過(guò)自定義View實(shí)現(xiàn)自己想要的效果是作為android開(kāi)發(fā)程序員的一項(xiàng)必備技能,自定義View對(duì)于android開(kāi)發(fā)來(lái)說(shuō)也是比較難的一項(xiàng)技術(shù)2023-04-04monkeyrunner之電腦安裝驅(qū)動(dòng)(5)
這篇文章主要為大家詳細(xì)介紹了monkeyrunner之電腦安裝驅(qū)動(dòng)的相關(guān)資料,具有一定的參考價(jià)值,感興趣的小伙伴們可以參考一下2016-12-12Android 重力傳感器在游戲開(kāi)發(fā)中的應(yīng)用
本文主要介紹Android 重力傳感器,這里整理了詳細(xì)的資料,并且詳細(xì)的說(shuō)明重力傳感器的使用方法,有興趣的小伙伴可以參考下2016-08-08Android高級(jí)組件AutoCompleteTextView自動(dòng)完成文本框使用詳解
這篇文章主要介紹了Android高級(jí)組件AutoCompleteTextView自動(dòng)完成文本框的使用,具有一定的參考價(jià)值,感興趣的小伙伴們可以參考一下2017-12-12Android RecycleView實(shí)現(xiàn)Item拖拽效果
RecyclerView是Android一個(gè)更強(qiáng)大的控件,其不僅可以實(shí)現(xiàn)和ListView同樣的效果,還有優(yōu)化了ListView中的各種不足。本文將介紹通過(guò)RecyclerView實(shí)現(xiàn)Item拖拽效果以及拖拽位置保存,感興趣的可以參考一下2022-01-01