一、BitmapDrawable
Bitmap 是一種位圖圖像尘惧,Android 系統(tǒng)支持三種格式的位圖圖像康栈,.png (preferred)(支持最好),.jpg (acceptable)喷橙, .gif (discouraged)(支持最差)啥么。
在構(gòu)建應(yīng)用的時候,Bitmap文件可能會被appt工具壓縮自動優(yōu)化為無損圖像贰逾。例如,一個真彩色PNG悬荣,不需要超過256的顏色可以被轉(zhuǎn)換成一個8位PNG和調(diào)色板。這將導(dǎo)致一個圖像質(zhì)量相同疙剑,但這需要更少的內(nèi)存氯迂。所以要意識到,在drawable目錄中圖像的二進(jìn)制文件在構(gòu)建程序時可以改變言缤。如果你打算讀一個圖像作為字節(jié)流并將它轉(zhuǎn)換成一個位圖嚼蚀,把你的圖片放在在res /raw/文件夾里,在那里他們不會被優(yōu)化管挟。
屬性介紹
android:src=""
android:alpha=""
android:antialias=""
android:autoMirrored=""
android:dither=""
android:filter=""
android:gravity=""
android:mipMap=""
android:tileMode=""
android:tileModeX=""
android:tileModeY=""
android:tint=""
android:tintMode=""
- android:antialias 抗鋸齒
開啟抗鋸齒轿曙,圖像會變的=得更平滑,但是會降低清晰度僻孝,一般開啟拳芙;
- android:dither 防抖動
讓高質(zhì)量的圖片的比較低質(zhì)量的屏幕上不失真,得到比較好的顯示效果皮璧。
比如圖片的色彩模式是 ARGB8888舟扎,但是手機設(shè)備的支持RGB555的色彩模式,那么開啟這么就可以有效減少失真現(xiàn)象悴务。
(Android中我們創(chuàng)建的Bitmap一般會選擇ARGB888模式睹限,ARGB每個通道各占8位譬猫,8位1個字節(jié),一個像素4個字節(jié)羡疗,一個像素的位數(shù)總和越高染服,圖片越逼真)
- android:filter 過濾效果
在圖片圖片被拉伸或者壓縮的時候開啟過濾效果可以顯示更加好的效果。
- android:mipmap
紋理映射
- android:gravity 圖片位置
可選項 - top|bottom|left|right|center|center_vertical|center_horizontal|cneter 保持圖片原來大小
- fill_vertical|fill_horizontal|fill 拉伸圖片填充容器叨恨,BitmapDrawable 作為背景時會自動拉伸為 View 寬高柳刮,所以默認(rèn)的 gravity 屬性值為 fill
- clip_vertical | clip_horizontal 附加項,表示裁剪圖片
- android:tileMode 平鋪模式
默認(rèn)為 disabled痒钝,不為 disabled 時秉颗,gravity 屬性會被忽略
- disabled 關(guān)閉平鋪模式
- clamp 拉伸像素
- repeat 水平和垂直方向平鋪
- mirror 鏡像平鋪
BitmapDrawable 內(nèi)部寬高
@Override
public int getIntrinsicWidth() {
return mBitmapWidth;
}
@Override
public int getIntrinsicHeight() {
return mBitmapHeight;
}
可以看到 BitmapDrawable 返回的寬高就是 Bitmap 的寬高,Bitmap 的寬高是在 computeBitmapSize() 方法中賦值的:
private void computeBitmapSize() {
final Bitmap bitmap = mBitmapState.mBitmap;
if (bitmap != null) {
mBitmapWidth = bitmap.getScaledWidth(mTargetDensity);
mBitmapHeight = bitmap.getScaledHeight(mTargetDensity);
} else {
mBitmapWidth = mBitmapHeight = -1;
}
}
如果 mBitmapState 中的成員變量 mBitmap 不為 null 的話送矩,把 mTargetDensity 作為參數(shù)調(diào)用 Bitmap 的 getScaledXXX 方法蚕甥。
這里的 mTargetDensity 是 Drawable 的目標(biāo)密度,在構(gòu)造方法中會進(jìn)行賦值栋荸,也可以通過 setTargetDensity
方法賦值菇怀,默認(rèn)為設(shè)備的屏幕像素密度。
Bitmap 也有一個成員變量 mDensity 是自身的像素密度晌块,在 getScaledXXX 方法中會根據(jù) mTargetDensity / mDensity 對 Bitamp 的寬高尺寸進(jìn)行縮放爱沟。
public int getScaledHeight(int targetDensity) {
return scaleFromDensity(getHeight(), mDensity, targetDensity);
}
/**
* @hide
*/
static public int scaleFromDensity(int size, int sdensity, int tdensity) {
if (sdensity == DENSITY_NONE || tdensity == DENSITY_NONE || sdensity == tdensity) {
return size;
}
// Scale by tdensity / sdensity, rounding up.
return ((size * tdensity) + (sdensity >> 1)) / sdensity;
}
Bitmap 和 Drawable 的轉(zhuǎn)換
- Bitmap --> Drawable:
new BitampDrawable(bitmap)
二、NinePatchDrawable
.9格式的圖片匆背。BitmapDrawable 會根據(jù) View 的大小進(jìn)行拉伸呼伸,而.9圖片可自動地根據(jù)所需的寬/高進(jìn)行相應(yīng)的縮放并保證不失真。
同樣可以通過 xml 文件來描述靠汁,屬性同 bitmap
三蜂大、ShapeDrawable & GradientDrawable
屬性
<?xml version="1.0" encoding="utf-8"?>
<shape xmlns:android="http://schemas.android.com/apk/res/android"
android:shape="rectangle|oval|line|ring"
android:innerRadius=""
android:innerRadiusRatio=""
android:thickness=""
android:thicknessRatio=""
android:useLevel="">
<corners android:radius=""
android:topLeftRadius=""
android:topRightRadius=""
android:bottomLeftRadius=""
android:bottomRightRadius=""/>
<gradient
android:type="linear|radio|sweep"
android:startColor=""
android:centerColor=""
android:endColor=""
android:centerX=""
android:centerY=""
android:angle=""
android:gradientRadius=""
android:useLevel=""/>
<padding android:top=""
android:bottom=""
android:left=""
android:right=""/>
<size
android:width=""
android:height=""/>
<solid
android:color=""/>
<stroke
android:color=""
android:width=""
android:dashWidth=""
android:dashGap=""/>
</shape>
- android:shape 默認(rèn)為 rectangle闽铐,line 和 ring 必須通過標(biāo)簽
<stroke>
來指定寬度和顏色蝶怔;
當(dāng) shape 為 ring 時,有五個特殊屬性: - android:innerRadius 圓環(huán)內(nèi)半徑兄墅,會覆蓋 innerRadiusRatio踢星;
- android:innerRadiusRatio 圓環(huán)內(nèi)半徑所占比率,默認(rèn)為9隙咸;
- android:thickness 圓環(huán)厚度沐悦,會覆蓋 thicknessRaio;
- android:thicknessRatio 圓環(huán)厚度所占比率五督,默認(rèn)為3藏否;
- android:useLevel 常為false,除非它被當(dāng)做是LevelListDrawable充包;
- <corners>:表示shape的四個圓角的角度副签,只適用于矩形遥椿。
- <gradient>:漸變效果,與 <solid> 的純色填充相互排斥淆储。
- android:type:漸變的類別冠场。有l(wèi)inear(線性漸變)、radial(徑向漸變)本砰、sweep(掃描線漸變)碴裙,默認(rèn)為linear。
- android:centerX:漸變的中心點的X坐標(biāo)点额。
- android:centerY:漸變的中心點的Y坐標(biāo)舔株。
- android:gradientRadius :漸變半徑。僅當(dāng)android:type="radial"時有效咖楣。
- android:angle:漸變角度督笆,默認(rèn)為0,必須為45的倍數(shù)诱贿,0表示從左到右娃肿,90表示從上到下,僅在 linear 時有效
- <stroke>:描邊珠十。
- android:width:描邊的寬度料扰。
- android:color:描邊的顏色。
- android:dashWidth:虛線的寬度焙蹭。
- android:dashGap:虛線之間的間隔晒杈。
- <solid> :填充純色
- <padding> :內(nèi)邊距
- <size>:大小。其android:width和android:height分別設(shè)定shape的寬/高孔厉。注意拯钻,這個表示的是shape的固有大小,但并不是其最終大小撰豺。
用代碼創(chuàng)建
通過 inflate 方法解析 xml 文件中的屬性粪般,也可以使用構(gòu)造方法來創(chuàng)建 ShapeDrawable 對象:
public ShapeDrawable()
public ShapeDrawable(Shape s)
private ShapeDrawable(ShapeState state, Resources res)
ShapeDrawable 有三個構(gòu)造方法,第一個沒有參數(shù)污桦,第二個傳入一個 Shape 對象亩歹,最終都是調(diào)用了第三個,但是第三個構(gòu)造方法是 private 修飾的凡橱,第三個方法的第一個參數(shù)是一個 ShapeState 對象小作,ShapeState 類繼承自 Drawable 類的靜態(tài)內(nèi)部類 ConstantState ,ShapeState 封裝了當(dāng)前 Drawable 的重要屬性稼钩, ShapeState是Drawable 自己的保存狀態(tài)量和數(shù)據(jù)的重要對象.顾稀。在該方法中給 ShapeDrawable 的成員變量 mShapeState 賦值,并初始化 PorterDuffColorFilter 類型成員變量 mTintFilter坝撑。
但是其實 <shape> 標(biāo)簽定義的不是 ShapeDrawable 而是 GradientDrawable静秆。
Drawable 類也有三個構(gòu)造方法:
public GradientDrawable()
public GradientDrawable(Orientation orientation, @ColorInt int[] colors)
private GradientDrawable(@NonNull GradientState state, @Nullable Resources res)
最終都是調(diào)用了 private 的兩個參數(shù)的構(gòu)造方法氮块,第一個參數(shù)是 ConstantState 的子類 GradientState,第二個參數(shù)還是 Resources 對象诡宗。
GradientState 的構(gòu)造方法有兩個:
public GradientState(Orientation orientation, int[] gradientColors) {
mOrientation = orientation;
setGradientColors(gradientColors);
}
public GradientState(@NonNull GradientState orig, @Nullable Resources res)
也就是說滔蝉,在創(chuàng)建 GradientState 時,必須要確定漸變的方向和漸變顏色:
Orientation 是一個內(nèi)部枚舉類:
public enum Orientation {
TOP_BOTTOM, //從上到下 angle = 90
TR_BL,//從右上到左下 angle = 135
RIGHT_LEFT,//從右向左 angle = 180
BR_TL,//從右下到左上 angle = 225
BOTTOM_TOP,//從下到上 angle = 270
BL_TR,//從左下到右上 angle = 315
LEFT_RIGHT,//從左到右 angle = 0
TL_BR,//從左上到右下 angle = 45
}
public void setGradientColors(@Nullable int[] colors) {
mGradientColors = colors;
mSolidColors = null;
computeOpacity();
}
<solid> 標(biāo)簽和 <gradient> 標(biāo)簽相互沖突塔沃,以及 <stroke> 標(biāo)簽定義的屬性分別存儲在以下三個成員變量中
public ColorStateList mSolidColors;
public ColorStateList mStrokeColors;
public @ColorInt int[] mGradientColors;
GradientDrawable 類對外提供了一系列方法設(shè)置相關(guān)屬性:
- <shape>
setShape(@Shape int shape)蝠引,參數(shù)為 GradientDrawable 內(nèi)部定義的 int 類型常量 - <corners>
setCornerRadius(float radius)
setCornerRadii(@Nullable float[] radii) - <gradient>
setGradientType(@GradientType int gradient) 參數(shù)也為靜態(tài)常量
setGradientCenter(float x, float y)
setGradientRadius(float gradientRadius) - <solid>
setColor(@ColorInt int argb)
setColor(@Nullable ColorStateList colorStateList) - <stroke>
setStroke(int width, @ColorInt int color)
setStroke(int width, ColorStateList colorStateList)
setStroke(int width, @ColorInt int color, float dashWidth, float dashGap)
setStroke(
int width, ColorStateList colorStateList, float dashWidth, float dashGap) - <size>
setSize(int width, int height)
四、StateListDrawable
下面羅列了 selector 的所有 state蛀柴,android:drawable
屬性引用drawable 資源螃概,也可以在 <item>
標(biāo)簽中定義其它 drawable 。
android:contantSize
屬性為 true 時鸽疾,StateListDrawable 固有大小保持不變吊洼,是內(nèi)部所有 Drawable 的固有大小的最大值。false 則會隨著狀態(tài)的改變而改變制肮;
android:variablePadding
屬性為 true 時表示 padding 隨著狀態(tài)改變而改變冒窍,為 false 表示 padding 為內(nèi)部所有 drawable 的 padding 最大值保持不變;
<selector xmlns:android="http://schemas.android.com/apk/res/android"
android:constantSize=""
android:variablePadding="">
<item android:state_accelerated=""
android:state_active=""
android:state_activated=""
android:state_checkable=""
android:state_checked=""
android:state_drag_can_accept=""
android:state_drag_hovered=""
android:state_enabled=""
android:state_first=""
android:state_focused=""
android:state_hovered=""
android:state_last=""
android:state_middle=""
android:state_pressed=""
android:state_selected=""
android:state_single=""
android:state_window_focused=""
android:drawable="">
<color android:color=""/>
<bitmap android:src=""/>
<nine-patch android:src=""/>
<clip android:drawable="" />
<inset android:drawable="" />
<scale android:drawable=""/>
<ripple android:color=""/>
<rotate android:drawable=""/>
<transition />
<layer-list></layer-list>
<level-list></level-list>
<shape ></shape>
<selector></selector>
<animation-list></animation-list>
<animated-rotate />
<animated-selector android:fromId="" android:toId=""/>
</item>
</selector>
StateListDrawable 類有三個構(gòu)造方法:
public StateListDrawable()
private StateListDrawable(StateListState state, Resources res)
StateListDrawable(@Nullable StateListState state)
構(gòu)造方法傳入了一個 StateListState 參數(shù)豺鼻,這個 StateListState 不是繼承自 Drawable.ConstantState 類综液,而是繼承自 DrawableContainer.DrawableContainerState 類,它的構(gòu)造方法是 StateListState(StateListState orig, StateListDrawable owner, Resources res)
構(gòu)造方法內(nèi)部都是創(chuàng)建一個 StateListState 對象儒飒,然后調(diào)用了 setConstantState(DrawableContainerState state) 方法給 成員變量 mStateListState 賦值谬莹。
StateListState 內(nèi)部有一個二維數(shù)組 mStateSets 保存著所有的狀態(tài)和 Drawable。給 StateListDrawable 添加 item 就是通過調(diào)用 addState 方法桩了,state 是放在一個 int 數(shù)組里面的附帽。
public void addState(int[] stateSet, Drawable drawable) {
if (drawable != null) {
mStateListState.addStateSet(stateSet, drawable);
// in case the new state matches our current state...
onStateChange(getState());
}
}