編輯:關於Android編程
最近因為一些個人私事導致好久沒寫博客了,多事之年總算要過去了,突然沒了動力,所以趕緊先拿個最近項目中重構的一個小知識點充下數,老題重談。
在我們App開發中大家可能都會有過如下痛疾(程序員和設計妹妹注意喽):
好多小的圖標好煩人,又占體積還要考慮分辨率,一拉伸就模糊等。
同一個圖標不同狀態還有不同顏色的多張。
總是幻想IOS、Android、Web等對於一個圖標只切一次圖多好。
如果你有過類似的痛疾那麼下面討論的故事就是一個完美的解決方案,當然了,采用下面方案對於重型應用或者固件級的優化才會十分明顯,對於普通小應用那就要看自己了。
PNG為位圖,是由不同的排列和染色的像素點組成的圖像,當放大位圖時就能清晰的看見無數個小方塊(像馬賽克一樣),所以位圖的擴大實質是增加單個像素點的大小,故而導致在不同分辨率表現非常糟糕。
SVG為可縮放矢量圖,它不會像位圖一樣因為縮放而讓圖片質量下降,他在不同分辨率的表現都一樣清晰。
IconFont是WebFont形式的圖標,你可以把他認為就是WebFont,該類東東的制作來自於SVG矢量圖,所以它不會像位圖一樣因為縮放而讓圖片質量下降,他在不同分辨率的表現都一樣清晰。
下面我們簡單給出這幾種格式圖標素材的對比:
有了上面這些對比之後,在正式開始實戰之前我們先來簡單粗暴了解下SVG與IconFont在App中的優點吧,不然下文就沒有存在的意義喽,如下:
圖標集中處理,設計妹妹只用出一次圖喽。
減少重型應用或者固件大小,因為IconFont是字符串而不是圖片,SVG的體積也小於PNG。
因為IconFont的繪制原理和普通文本一樣,所以運行時會占用更小的內存空間。
聽著挺誘人,好吊的樣子,實際下面我們來看一下你就明白啦。
有了上面的理論基礎,下面我們就來看下他們各自的使用方法;關於PNG的使用這裡就不介紹了,沒啥新鮮的,從Android一出來支持到現在的格式,要是還不會那就真該拖出去亂炖了。
哈哈,這個其實阿裡媽媽MUX團隊早就給大家搞好強大的庫和相關使用文檔了,詳細可以點我查看。當然喽,有的公司會搞自己的庫服務器,自己去搭建,有的公司會借助阿裡媽媽提供的平台直接去制作;不管哪種平台其實實質都一樣,沒啥可說的,原理一樣,只是我們可能會自己依據需求自定義一些支持IconFont的拓展TextView、ImageView等,萬變不離其宗,由於確實很簡單,下面我們給一個非常簡單的例子描述就行了。如下以阿裡巴巴IconFont平台為例:
從平台選擇要使用到的圖標下載到本地,復制ttf字體文件到項目assets目錄下。
打開從IconFont平台下載下來的demo.html文件,找到圖標相對應的HTML字符碼。
打開項目res/values/strings.xml,添加string字符串值為上面字符碼。
注意:上面2和3步在有些自己搭建的平台上會自動用代碼生成一個iconfont.xml的string文件,這樣就不用自己手動去從demo.html復制到res下了,而是直接將iconfont.xml復制到res,不清楚那麼牛逼的阿裡為何沒這麼做。
打開布局文件activity_main.xml,添加上面3生成的string值到TextView(這裡只以TextView為例演示,實際中一般我們會直接拓展定義TextView等的)。如下:
<
TextView
android:layout_width
=
"wrap_content"
android:layout_height
=
"wrap_content"
android:text
=
"@string/icon_font_add"
/>
接著給該TextView指定使用IconFont的文字文件。如下:
Typeface iconfont = Typeface.createFromAsset(getAssets(),
"iconfont.ttf"
);
TextView textview = (TextView)findViewById(R.id.test);
textview.setTypeface(iconfont);
至此IconFont的使用就搞定了,是不是很簡單而且超級贊,優劣自行腦補。
這玩意超級簡單,主要腦動力在美工妹妹,和咱程序員關系不是很大,所以直接用即可,不做Demo演示了,我們項目中也用了很多這玩意。
說到這貨,哈哈上面搞IconFont的美工妹妹一定知道,IconFont制作的來源就是SVG,只是SVG制作比IconFont容易且使用更加靈活而已。下面我們下來看一下SVG圖片直接用Txt打開後的d屬性,至於為啥看它,請自行腦補。PS:這貨除過控件支持以外還可以直接扔給WebView去顯示,因為其本質就可以說是HTML相關的東東。
SVG Path Data:
前提先說好,SVG和PathData都是可以通過美工的工具生成的,下面之所以介紹PathData只是一種簡單的背景了解而已。如下是一張SVG格式的圖片(再來一層像不像超人標示,哈哈):
我們現在拿txt工具把他打開(而不是圖片浏覽器),如下:
<code> <svg width="4cm" height="4cm" viewBox="0 0 400 400" xmlns="http://www.w3.org/2000/svg" version="1.1"> <title>Example triangle01- simple example of a 'path'</title> <desc>A path that draws a triangle</desc> <rect x="1" y="1" width="398" height="398" fill="none" stroke="red" stroke-width="3"></rect> <path d="M 100 100 L 300 100 L 200 300 z" fill="yellow" stroke="red" stroke-width="10"></path> </svg></code>
握草!可以很明顯的看見PathData不就是SVG圖片裡path節點下的d屬性值麼?為了能夠看明白上面這個d屬性值和上面貼的圖片關系,我們先來看幾個科普。
SVG Path Data命令解釋(注意:每個命令都有大小寫形式,大寫代表後面的參數是絕對坐標,小寫表示相對坐標,每個參數之間用空格或逗號區分):
M/m命令:moveto移動到繪制點,後面跟上坐標系點對即可。
Z/z命令:closepath一段路徑等的閉合點,無參數。
L/l命令:lineto繪制一個點到另一個點的直線,多個坐標對可以繪制折線,後面跟上坐標系點對即可。
H/h命令:lineto從當前點到指定x點繪制水平直線,多個x無意義,後面跟坐標系x點即可。
V/v命令:lineto從當前點到指定x點繪制垂直直線,多個y無意義,後面跟坐標系y點即可。
C/c命令:cubic bezier三次貝塞爾曲線。
S/s命令:cubic bezier三次貝塞爾曲線。
Q/q命令:quatratic bezier二次貝塞爾曲線。
T/t命令:quatratic bezier二次貝塞爾曲線。
A/a命令:elliptical arc圓弧線。
好了,到這裡你至少知道上面那個類超人圖標的東東XML是啥意思了,有這些就足夠了,下面我們開搞。
Android L時代的局部SVG先驅VectorDrawable和AnimatedVectorDrawable:
下面我們先來看下Android L時代Google給我們放的大招,牛逼的SVG支持,其中支持控件有VectorDrawable和AnimatedVectorDrawable,遺憾的是這兩控件在support包木有,可喜的是有現成的第三方開源兼容包。VectorDrawable的父類是Drawable,Drawable的父類是Object;AnimatedVectorDrawable的父類也是Drawable;從這就能看出來Android L拓展的SVG控件實質也是一個Drawable。
VectorDrawable的創建可以通過一個
節點的XML進行定義,下面我們來看看這些相關節點屬性的含義:
:定義一個Vector Drawable。
android:name
定義這個VectorDrawable的名字;
android:width
定義本質的幾何寬度,尺寸標准隨意,一般為dp;
android:height
定義本質的幾何高度,尺寸標准隨意,一般為dp;
android:viewportWidth
定義viewport寬度,viewport是將path繪制在上面的一個虛擬畫布;
android:viewportHeight
定義viewport高度,同上;
android:tint
定義Drawable的著色,默認沒有色彩;
android:tintMode
定義著色模式,默認是src_in;
android:autoMirrored
定義圖片是否需要鏡像反轉,當布局方向是RTL,即從右到左布局時才有用;
android:alpha
設置圖片的透明度;
:定義一個Path組或者子組。
android:name
定義組的名字;
android:rotation
定義組的旋轉角度;
android:pivotX
定義縮放或者旋轉中軸點x坐標,是虛擬畫布中的坐標;
android:pivotY
同上,定義y坐標;
android:scaleX
定義縮放x維;
android:scaleY
定義縮放y維;
android:translateX
定義x縮放,是虛擬畫布中的坐標;
android:translateY
定義y縮放,是虛擬畫布中的坐標;
:定義一個被繪制的Path。
android:name
定義path的名字;
android:pathData
定義路徑采用了SVG文件裡d標簽中的path值,這些值繪制在虛擬畫布上;
android:fillColor
定義路徑填充顏色;
android:strokeColor
定義path的外輪廓顏色;
android:strokeWidth
路徑的寬度;
android:strokeAlpha
一個路徑的透明度;
android:fillAlpha
全路徑透明度;
android:trimPathStart
開始路徑的百分比,0-1;
android:trimPathEnd
結束路徑的百分比,0-1;
android:trimPathOffset
轉換區域0-1;
android:strokeLineCap
設置線的頂路徑,圓還是方等;
android:strokeLineJoin
設置線連接處路徑方式;
android:strokeMiterLimit
設置線的修飾;
:定義路徑裁剪,只適用於當前組或者子項。
android:name
定義裁剪路徑的名字;
android:pathData
定義路徑采用了SVG文件裡d標簽中的path值;
扯了這麼多,接下來我們舉個例子吧,哈哈,好在強大的AS已經支持在drawable下右鍵新建Vector資源了,支持的還是滿強大的,SVG或者MD的圖片直接到我們需要的xml文件一步生成。牛叉的一逼,再也不像剛出來那會搞個SVG2XML需要第三方工具了,如下是我通過AS選擇的一副圖片生成的XML,如下:
生成XML如下:
1 2 3 4 5 6 7 8 9 10
<
vector
xmlns:android
=
"http://schemas.android.com/apk/res/android"
android:height
=
"64dp"
android:width
=
"64dp"
android:viewportHeight
=
"600"
android:viewportWidth
=
"600"
>
<
group
android:name
=
"rotationGroup"
android:pivotX
=
"300.0"
android:pivotY
=
"300.0"
android:rotation
=
"45.0"
>
<
path
android:name
=
"v"
android:fillColor
=
"#000000"
android:pathData
=
"M300,70 l 0,-70 70,70 0,0 -70,70z"
/>
group
>
vector
>
第二步,創建元素的矢量資源動畫,放置在res/drawable/下,這裡主要就是將動畫與前面的VectorDrawable進行關聯。如下是一個例子:
<
animated-vector
xmlns:android
=
"http://schemas.android.com/apk/res/android"
android:drawable
=
"@drawable/vectordrawable"
>
<
target
android:name
=
"rotationGroup"
android:animation
=
"@anim/rotation"
/>
<
target
android:name
=
"v"
android:animation
=
"@anim/path_morph"
/>
animated-vector
>
第三步,創建元素的一個或多個對象動畫器,放置在res/animator下,這玩意其實就是我們之前認識的真實的Android屬性動畫ObjectAnimator或AnimatorSet喽,沒啥意思,不過還是看下它是怎麼控制pathData的吧,如下:
<
objectAnimator
android:duration
=
"6000"
android:propertyName
=
"rotation"
android:valueFrom
=
"0"
android:valueTo
=
"360"
/>
1
2
3
4
5
6
7
8
9
<
set
xmlns:android
=
"http://schemas.android.com/apk/res/android"
>
<
objectAnimator
android:duration
=
"3000"
android:propertyName
=
"pathData"
android:valueFrom
=
"M300,70 l 0,-70 70,70 0,0 -70,70z"
android:valueTo
=
"M300,70 l 0,-70 70,0 0,140 -70,0 z"
android:valueType
=
"pathType"
/>
set
>
最後我們在Java代碼中將該drawable進行動畫啟動即可,如下:
1 2 3if
(drawable
instanceof
Animatable) {
((Animatable) drawable).start();
}
到此AnimatedVectorDrawable的基本情況就OK了,沒啥懸念的,重點依舊是pathData的定義,所以如果項目有需求還是要好好搞搞的,暫時木有需求,因為我們用的IconFont方案。
非Android L時代的局部SVG兼容VectorDrawable和AnimatedVectorDrawable解決方案:
對於做固件App來說可能上面介紹的Android L提供的控件足以滿足用來使用SVG了,但是對於第三方開發者來說確實還是挺悲催的,兼容性問題一大堆,所以這裡給出一個兼容Android L以下版本的SVG控件使用開源庫。如下:
vector-compat
這個庫可以基本滿足替換原生Android L對SVG的兼容性,具體用法自行查看README文檔和查看人家大神的Demo吧,請叫我雷鋒,不再過多說明。
為了效率的完全直接使用SVG拓展優化方案:
可以看見,上面的那麼多控件雖說叫支持SVG,其實實質是只支持SVG圖片裡面的一部分而已,主要就是PathData;所以為了完全直接支持SVG圖片而不是SVG生成的XML,騰訊微信團隊等又給出了一個實現思路,不得不感慨BAT的一些牛逼之處。
該方案微信團隊已經進行過效率、性能、灰度等測試驗證,而且貌似微信都已經完全使用該方案進行資源優化了,這裡不再細說,有興趣的自行查閱資料吧,坐等我們項目能從IconFont切到這種方案,嗚嗚!!!
PS:關於Android AnimatedVectorDrawable等搞出來的各種腦洞大開的動畫場景請君自行腦補,自己暫時沒那麼多沒時間,所以就不多說了,等項目有需求了再說。
PPPS:其實Android L系統的圓圈型ProcessBar之所以那麼玄,實質就是這東東搞的
Service分為兩種工作狀態,一種是啟動狀態,主要用於執行後台計算;另一種是綁定狀態,主要用於其他組件和Service的交互。這兩種狀態可以共存的,即Service既可
先給大家展示下效果圖:掃描內容是下面這張,二維碼是用zxing庫生成的由於改了好幾個類,還是去年的事都忘得差不多了,所以只能上這個類的代碼了,主要就是改了這個Captur
由於Worker線程不能修改UI,所以當在Worker線程中接收到消息之後,需要通知主線程來更新UI。下面是一個下例子: 一 布局 二 代碼&
我在前面的一片博客中,介紹了jPBC 2.0.0在PC平台上面的配置和測試。既然jPBC是Java平台上面實現的,那麼jPBC能不能在Android這個以Java為主要語