日韩性视频-久久久蜜桃-www中文字幕-在线中文字幕av-亚洲欧美一区二区三区四区-撸久久-香蕉视频一区-久久无码精品丰满人妻-国产高潮av-激情福利社-日韩av网址大全-国产精品久久999-日本五十路在线-性欧美在线-久久99精品波多结衣一区-男女午夜免费视频-黑人极品ⅴideos精品欧美棵-人人妻人人澡人人爽精品欧美一区-日韩一区在线看-欧美a级在线免费观看

歡迎訪問 生活随笔!

生活随笔

當前位置: 首頁 > 运维知识 > Android >内容正文

Android

Android使用SVG矢量图打造酷炫动效!

發布時間:2023/12/20 Android 24 豆豆
生活随笔 收集整理的這篇文章主要介紹了 Android使用SVG矢量图打造酷炫动效! 小編覺得挺不錯的,現在分享給大家,幫大家做個參考.

一個真正酷炫的動效往往讓人虎軀一震,話不多說,咱們先瞅瞅效果:

如果你想看 GAStudio Github主頁,請戳這里;
如果你想看 GAStudio更多技術文章,請戳這里;
QQ技術交流群:277582728;
github地址: github.com/Ajian-studi…

這個效果我們需要考慮以下幾個問題:

1.這是圖片還是文字;
2.如果是圖片該如何拿到圖形的邊沿線坐標,如果是文字呢?
3.如果拿到了邊沿線坐標,如何讓光線沿著路徑跑動;
4.怎么處理過程的銜接;

以上四個問題似乎不是太好處理,而這幾個問題也正好是這個效果精華所在,接下來咱們一個一個進行考慮,當然這種考慮已經基于一些國外大神的基礎之上;

首先這是圖片還是文字?

答案是:背景是圖片,表面的文字還是圖片,有些同學可能會說了,靠,這么沒含量,一個幀動畫而已,還虎軀一震,XXXXX,當然,答案肯定不會是這樣的,背景我就不說了,普通的jpg或png圖,但文字則是SVG格式的矢量圖;

有了第一個問題的答案,我們來看第二個問題,如何拿到文字圖形的邊沿坐標;

要回答這個問題,我們先來簡單的了解一個SVG(矢量圖);
SVG 意為可縮放矢量圖形(Scalable Vector Graphics),是使用 XML 來描述二維圖形和繪圖程序的語言;

使用 SVG 的優勢在于:

1.SVG 可被非常多的工具讀取和修改(比如記事本),由于使用xml格式定義,所以可以直接被當作文本文件打開,看里面的數據;
2.SVG 與 JPEG 和 GIF 圖像比起來,尺寸更小,且可壓縮性更強,SVG 圖就相當于保存了關鍵的數據點,比如要顯示一個圓,需要知道圓心和半徑,那么SVG 就只保存圓心坐標和半徑數據,而平常我們用的位圖都是以像素點的形式根據圖片大小保存對應個數的像素點,因而SVG尺寸更小;
3.SVG 是可伸縮的,平常使用的位圖拉伸會發虛,壓縮會變形,而SVG格式圖片保存數據進行運算展示,不管多大多少,可以不失真顯示;
4.SVG 圖像可在任何的分辨率下被高質量地打印;
5.SVG 可在圖像質量不下降的情況下被放大;
6.SVG 圖像中的文本是可選的,同時也是可搜索的(很適合制作地圖);
7.SVG 可以與 Java 技術一起運行;
8.SVG 是開放的標準;
9.SVG 文件是純粹的 XML;

看起來好厲害的樣子,還是回到我們的問題,從SVG圖中我們可否拿到我們想要的數據點呢?根據上面的介紹,答案當然是肯定的,從SVG圖中我們可以拿到我們想要的所有數據;
好的,拿到數據之后,怎么讓一條線沿著路徑跑起來呢?毋庸置疑,我們需要用到path;
最后我們根據效果的需要,設置幾個繪制過程,進行繪制;

接下來我們一起來解決以上問題:
既然SVG是公認的xml文件格式定義的,那么我們則可以通過解析xml文件拿到對應SVG圖的所有數據,我們先看下 path 類型的SVG 數據:

<?xml version="1.0" standalone="no"?> <!DOCTYPE svg PUBLIC "-//W3C//DTD SVG 1.1//EN" "http://www.w3.org/Graphics/SVG/1.1/DTD/svg11.dtd"><svg width="100%" height="100%" version="1.1" xmlns="http://www.w3.org/2000/svg"><path d="M250 150 L150 350 L350 350 Z" /></svg>復制代碼

上面有一個path 標簽,里面用到了 M 和 Z 指令,M 就相當于 android Path 里的moveTo(),Z 則相當于 Path 里的close();
我們先看下SVG 里關于path 有哪些指令:

M = moveto 相當于 android Path 里的moveTo(),用于移動起始點 L = lineto 相當于 android Path 里的lineTo(),用于畫線 H = horizontal lineto 用于畫水平線 V = vertical lineto 用于畫豎直線 C = curveto 相當于cubicTo(),三次貝塞爾曲線 S = smooth curveto 同樣三次貝塞爾曲線,更平滑 Q = quadratic Belzier curve quadTo(),二次貝塞爾曲線 T = smooth quadratic Belzier curveto 同樣二次貝塞爾曲線,更平滑 A = elliptical Arc 相當于arcTo(),用于畫弧 Z = closepath 相當于closeTo(),關閉path復制代碼

了解了以上path相關的指令,就可以看懂path構成的SVG圖的數據了,除此之外,SVG里還定義了一些基本的圖形和效果:

更多介紹和使用大家可以看 W3School

好,以上內容,我們已經知道 SVG 圖是通過 Xml 格式定義的,并且里面用到了一些基本的指令對數據進行組裝,構成基本圖形或復雜的路徑;
而對于我們來說 ,這個xml 如何拿到呢?
1.我們根據最后要做的效果,利用PS等作圖軟件設計制作出想要的圖形;


2.使用 GIMP 之類的矢量圖軟件導出圖片的SVG數據,方法如下:
先使用魔棒工具快速建立選區:

然后將選區導出為path:

這個時候在軟件的右邊欄就可以看見生成的路徑了,然后將路徑導出:

經過以上幾步,我們就拿到了我們自己設計的文字或圖形SVG圖的Path數據,上面圖片的SVG信息如下: <?xml version="1.0" encoding="UTF-8" standalone="no"?> <!DOCTYPE svg PUBLIC "-//W3C//DTD SVG 20010904//EN""http://www.w3.org/TR/2001/REC-SVG-20010904/DTD/svg10.dtd"><svg xmlns="http://www.w3.org/2000/svg"width="6.95746in" height="1.82269in"viewBox="0 0 668 175"><path id="Selection"fill="none" stroke="black" stroke-width="1"d="M 530.00,34.00C 530.00,34.00 526.08,59.00 526.08,59.00526.08,59.00 518.00,105.00 518.00,105.00518.00,105.00 515.42,119.00 515.42,119.00515.42,119.00 513.26,125.01 513.26,125.01513.26,125.01 506.00,126.00 506.00,126.00506.00,126.00 496.00,126.00 496.00,126.00496.00,126.00 496.00,120.00 496.00,120.00490.87,124.16 486.71,126.42 480.00,126.91475.71,127.22 471.06,126.94 467.00,125.44454.13,120.68 451.86,110.19 452.00,98.00452.22,79.34 465.14,64.55 484.00,63.18492.14,62.59 498.96,65.71 504.00,72.00504.00,72.00 510.00,34.00 510.00,34.00510.00,34.00 530.00,34.00 530.00,34.00 ZM 551.00,56.89C 539.01,55.86 537.45,39.82 551.00,35.55568.60,33.45 567.67,58.33 551.00,56.89 Z復制代碼

中間段省略

M 263.00,134.00C 263.00,134.00 263.00,145.00 263.00,145.00263.00,145.00 202.00,145.00 202.00,145.00202.00,145.00 202.00,134.00 202.00,134.00202.00,134.00 263.00,134.00 263.00,134.00 Z" /> </svg>復制代碼

根據圖形路徑的復雜度,生成的path數據復雜度也不一樣,但格式也算是非常的清楚,即采用一定的指令把數據點進行拼接;
現在有了這些數據點,我們需要做的則是對數據進行解析,封裝成我們要的Path;
解析的過程也無非是 遇到指令則采用android Path 里的對應方法進行置換,解析方式如下:

public Path parsePath(String s) throws ParseException {mCurrentPoint.set(Float.NaN, Float.NaN);mPathString = s;mIndex = 0;mLength = mPathString.length();PointF tempPoint1 = new PointF();PointF tempPoint2 = new PointF();PointF tempPoint3 = new PointF();Path p = new Path();p.setFillType(Path.FillType.WINDING);boolean firstMove = true;while (mIndex < mLength) {char command = consumeCommand();boolean relative = (mCurrentToken == TOKEN_RELATIVE_COMMAND);switch (command) {case 'M':case 'm': {// m指令,相當于android 里的 moveTo()boolean firstPoint = true;while (advanceToNextToken() == TOKEN_VALUE) {consumeAndTransformPoint(tempPoint1,relative && mCurrentPoint.x != Float.NaN);if (firstPoint) {p.moveTo(tempPoint1.x, tempPoint1.y);firstPoint = false;if (firstMove) {mCurrentPoint.set(tempPoint1);firstMove = false;}} else {p.lineTo(tempPoint1.x, tempPoint1.y);}}mCurrentPoint.set(tempPoint1);break;}case 'C':case 'c': {// c指令,相當于android 里的 cubicTo()if (mCurrentPoint.x == Float.NaN) {throw new ParseException("Relative commands require current point", mIndex);}while (advanceToNextToken() == TOKEN_VALUE) {consumeAndTransformPoint(tempPoint1, relative);consumeAndTransformPoint(tempPoint2, relative);consumeAndTransformPoint(tempPoint3, relative);p.cubicTo(tempPoint1.x, tempPoint1.y, tempPoint2.x, tempPoint2.y,tempPoint3.x, tempPoint3.y);}mCurrentPoint.set(tempPoint3);break;}case 'L':case 'l': {// 相當于lineTo()進行畫直線if (mCurrentPoint.x == Float.NaN) {throw new ParseException("Relative commands require current point", mIndex);}while (advanceToNextToken() == TOKEN_VALUE) {consumeAndTransformPoint(tempPoint1, relative);p.lineTo(tempPoint1.x, tempPoint1.y);}mCurrentPoint.set(tempPoint1);break;}case 'H':case 'h': {// 畫水平直線if (mCurrentPoint.x == Float.NaN) {throw new ParseException("Relative commands require current point", mIndex);}while (advanceToNextToken() == TOKEN_VALUE) {float x = transformX(consumeValue());if (relative) {x += mCurrentPoint.x;}p.lineTo(x, mCurrentPoint.y);}mCurrentPoint.set(tempPoint1);break;}case 'V':case 'v': {// 畫豎直直線if (mCurrentPoint.x == Float.NaN) {throw new ParseException("Relative commands require current point", mIndex);}while (advanceToNextToken() == TOKEN_VALUE) {float y = transformY(consumeValue());if (relative) {y += mCurrentPoint.y;}p.lineTo(mCurrentPoint.x, y);}mCurrentPoint.set(tempPoint1);break;}case 'Z':case 'z': {// 封閉pathp.close();break;}}}return p;}復制代碼

有了圖形對應的path,我們只需要按照我們想要的效果進行繪制即可,具體過程不再細講,大家看代碼:

@Overrideprotected void onDraw(Canvas canvas) {super.onDraw(canvas);if (mState == STATE_NOT_STARTED || mGlyphData == null) {return;}long t = System.currentTimeMillis() - mStartTime;// 繪制出現前的邊沿線和跑動過程for (int i = 0; i < mGlyphData.length; i++) {float phase = MathUtil.constrain(0, 1,(t - (mTraceTime - mTraceTimePerGlyph) * i * 1f / mGlyphData.length)* 1f / mTraceTimePerGlyph);float distance = INTERPOLATOR.getInterpolation(phase) * mGlyphData[i].length;mGlyphData[i].paint.setColor(mTraceResidueColors[i]);mGlyphData[i].paint.setPathEffect(new DashPathEffect(new float[] {distance, mGlyphData[i].length}, 0));canvas.drawPath(mGlyphData[i].path, mGlyphData[i].paint);mGlyphData[i].paint.setColor(mTraceColors[i]);mGlyphData[i].paint.setPathEffect(new DashPathEffect(new float[] {0, distance, phase > 0 ? mMarkerLength : 0,mGlyphData[i].length}, 0));canvas.drawPath(mGlyphData[i].path, mGlyphData[i].paint);}if (t > mFillStart) {if (mState < STATE_FILL_STARTED) {changeState(STATE_FILL_STARTED);}// 繪制漸變出現的過程,即改變alpha過程float phase = MathUtil.constrain(0, 1, (t - mFillStart) * 1f / mFillTime);for (int i = 0; i < mGlyphData.length; i++) {GlyphData glyphData = mGlyphData[i];mFillPaint.setARGB((int) (phase * ((float) mFillAlphas[i] / (float) 255) * 255),mFillReds[i],mFillGreens[i],mFillBlues[i]);canvas.drawPath(glyphData.path, mFillPaint);}}if (t < mFillStart + mFillTime) {ViewCompat.postInvalidateOnAnimation(this);} else {changeState(STATE_FINISHED);}}復制代碼

好了,主要的問題和思路基本如上,有些人可能會說,你這講的跟UX分享似的,沒毛線用,其實我的目的只有一個,那就是不管你是否能看懂代碼,都能按照我上面所說做出自己想要的效果,并加以改變,靈活運用,畢竟輪子不需要重復造!

我本人也是對SVG矢量圖剛有所了解,主要參考國外大神的一篇博客,鏈接如下:www.willowtreeapps.com/blog/muzei-…

CSDN源碼下載地址:download.csdn.net/detail/tian…


最后,附上GAStudio技術交流群和Github,喜歡的話歡迎follow和star:

如果你想看 GAStudio Github主頁,請戳這里;
如果你想看 GAStudio更多技術文章,請戳這里;
QQ技術交流群:277582728;
github地址: github.com/Ajian-studi…

總結

以上是生活随笔為你收集整理的Android使用SVG矢量图打造酷炫动效!的全部內容,希望文章能夠幫你解決所遇到的問題。

如果覺得生活随笔網站內容還不錯,歡迎將生活随笔推薦給好友。