編輯:關於Android編程
Android開發中,我們經常會用到Color或Drawable,有時他們是可以混用的,有時卻有嚴格的區別。
Drawable
是可繪制物件的一般抽象。與View不同,Drawable上沒有事件和交互方法。我們經常會自定義View來實現一些復雜或絢麗的UI效果,其實也可以自定義Drawable來實現。
Drawable本身是一個抽象類,我們一般使用的是它的子類,都在android.graphics.drawable包下。有Bitmap
、Levels
、NinePatch
、Scale
、Shape
、Layers
、States
等等。
draw(Canvas canvas)
Drawable必須附在一個View上,繪制成什麼樣子,setBounds()
來決定大小,由view的draw方法來繪制Drawable的子類。
自定義Drawable
很容易實現圓角和圓形圖片,先看效果圖:
/**
* 圓角圖片
* Created by dengpan on 16/4/21.
*/
public class RoundRectImageDrawable extends Drawable {
private RectF rectF;
private Paint mPaint;
private Bitmap bitmap;
public RoundRectImageDrawable(Bitmap bitmap) {
this.bitmap = bitmap;
//表示圖片太大,則填充。TileMode還有repeat、mirror,表示重復
BitmapShader bitmapShader = new BitmapShader(bitmap, Shader.TileMode.CLAMP, Shader.TileMode.CLAMP);
mPaint = new Paint();
mPaint.setAntiAlias(true);
mPaint.setShader(bitmapShader);
rectF = new RectF(0, 0, bitmap.getWidth(), bitmap.getHeight());
}
@Override
public void setBounds(int left, int top, int right, int bottom) {
super.setBounds(left, top, right, bottom);
rectF = new RectF(left, top, right, bottom);
}
@Override
public void draw(Canvas canvas) {
//60表示圓角的半徑
canvas.drawRoundRect(rectF, 60, 60, mPaint);
}
@Override
public void setAlpha(int alpha) {
}
@Override
public void setColorFilter(ColorFilter colorFilter) {
}
@Override
public int getOpacity() {
return 0;
}
//設置下面兩個方法,保證原圖可以完整的顯示出來。
@Override
public int getIntrinsicWidth() {
return bitmap.getWidth();
}
@Override
public int getIntrinsicHeight() {
return bitmap.getHeight();
}
}
下面是圓形Drawable:
/**
* 圓形圖片(頭像)
* Created by dengpan on 16/4/21.
*/
public class CircleDrawable extends Drawable {
private int mWidth;
private RectF rectF;
private Paint mPaint;
private Bitmap bitmap;
public CircleDrawable(Bitmap bitmap) {
this.bitmap = bitmap;
BitmapShader bitmapShader = new BitmapShader(bitmap, Shader.TileMode.CLAMP, Shader.TileMode.CLAMP);
mPaint = new Paint();
mPaint.setAntiAlias(true);
mPaint.setShader(bitmapShader);
rectF = new RectF(0, 0, bitmap.getWidth(), bitmap.getHeight());
mWidth = Math.min(bitmap.getWidth(), bitmap.getHeight());
}
@Override
public void setBounds(int left, int top, int right, int bottom) {
super.setBounds(left, top, right, bottom);
rectF = new RectF(left, top, right, bottom);
mWidth = (int) Math.min(rectF.width(), rectF.height());
}
@Override
public void draw(Canvas canvas) {
canvas.drawCircle(rectF.left + mWidth / 2, rectF.top + mWidth / 2, mWidth / 2, mPaint);
}
@Override
public void setAlpha(int alpha) {
}
@Override
public void setColorFilter(ColorFilter colorFilter) {
}
@Override
public int getOpacity() {
return 0;
}
//設置了下面兩個方法的返回值,才能正常的顯示完整的圓形頭像,不然頭像太大,就截取了左上角部分。
@Override
public int getIntrinsicWidth() {
return mWidth;
}
@Override
public int getIntrinsicHeight() {
return mWidth;
}
}
調用方法:
Bitmap b = BitmapFactory.decodeResource(getResources(), R.mipmap.cute);
//圓角Drawable
imageView1.setImageDrawable(new RoundRectImageDrawable(b));
//圓形Drawable
imageView2.setImageDrawable(new CircleDrawable(b));
Shape
類型是用來繪制幾何圖形的,易用而且輕量化。一般使用XML來使用,放在res/drawable目錄下。
使用
標簽定義的是GradientDrawable
Shape類是個抽象類,draw(Canvas canvas, Paint paint)
必須實現,onResize(float width, float height)
也是非常重要的方法。它有五種子類。
Shape的通用屬性:
例如:很容易做一個圓角的按鈕背景圖,不需要美工作圖。
效果如下:
我們可以使用代碼實現Path和Arc類型的drawable,繪制不同的幾何形狀。
ShapeDrawable shapeDrawable = null;
Path p = new Path();
p.moveTo(50,0);
p.lineTo(0,50);
p.lineTo(50,100);
p.lineTo(100,50);
p.lineTo(50,0);
p.close();
PathShape ps = new PathShape(p,100,100);
shapeDrawable = new ShapeDrawable(ps);
shapeDrawable.setBounds(0,0,100,150);
shapeDrawable.getPaint().setStyle(Paint.Style.FILL);
shapeDrawable.getPaint().setColor(Color.CYAN);
imageViewShapePath.setBackgroundDrawable(shapeDrawable);
//Arc shape
ArcShape arcShape = new ArcShape(225,270);//初始180度,逆時針旋轉270度。0度在右手水平位置。
shapeDrawable = new ShapeDrawable(arcShape);
shapeDrawable.setBounds(0,0,200,200);
shapeDrawable.getPaint().setStyle(Paint.Style.FILL);
shapeDrawable.getPaint().setColor(Color.BLUE);
imageViewShapeArc.setBackgroundDrawable(shapeDrawable);
arcShape = new ArcShape(45,270);//初始180度,旋轉270度。0度在右手水平位置。
shapeDrawable = new ShapeDrawable(arcShape);
shapeDrawable.setBounds(0,0,200,200);
shapeDrawable.getPaint().setStyle(Paint.Style.STROKE);
shapeDrawable.getPaint().setColor(Color.RED);
imageViewShapeRing.setBackgroundDrawable(shapeDrawable);
Shapedrawable
直接在Java代碼中使用。
Shape
對象放入ShapeDrawable
中,ShapeDrawables
設置畫筆樣式。
Drawable尺寸變化時調用ShapeDrawable.ShaderFactory
產生的Shader
。
BitmapShader
、ComposeShader
、LinearGradient
、RadialGradient
、SweepGradient
。
//BitmapShader
shapeDrawable.setShaderFactory(new ShapeDrawable.ShaderFactory() {
@Override
public Shader resize(int width, int height) {
return new BitmapShader(b, Shader.TileMode.CLAMP, Shader.TileMode.CLAMP);
}
});
//LinearGradient
shapeDrawable.setShaderFactory(new ShapeDrawable.ShaderFactory() {
@Override
public Shader resize(int width, int height) {
return new LinearGradient(0,0,width,height,
new int[]{
//可以設置多個顏色漸變,可以任意多個顏色
Color.RED,Color.BLACK,Color.BLUE
},null, Shader.TileMode.CLAMP);
}
});
//SweepGradient 注意:最後兩個參數的數量要一致
shapeDrawable.setShaderFactory(new ShapeDrawable.ShaderFactory() {
@Override
public Shader resize(int width, int height) {
return new SweepGradient(width/2,height/2,
new int[]{
Color.RED,Color.YELLOW,Color.BLUE, Color.CYAN
},new float[]{0.1f,0.3f,0.7f,1.0f});
}
});
BitmapDrawable
是對bitmap
的一種封裝。它可以設置繪制方式,使圖片平鋪、拉伸或保持圖片原始大小。比如一些需要重復的圖片,可以讓美工提供很小的圖片,我們使用BitmapDrawable來進行重復渲染。
實現方法,有代碼和xml方式:
在res/drawable下定義bitmap drawable。
Bitmap b = BitmapFactory.decodeResource(getResources(),R.mipmap.cute);
BitmapDrawable bd = new BitmapDrawable(getResources(),b);
bd.setAntiAlias(true);
bd.setTileModeXY(Shader.TileMode.MIRROR, Shader.TileMode.MIRROR);
ivBitmapPic.setImageDrawable(bd);
.9圖片最大的特點是在拉伸不會失幀。.9圖片只能用於圖片拉伸的情況。
也是可以res/drawable中使用
標簽來定義一個NinePatchDrawable。不過都需要.9.png的圖片。Android提供了.9圖片的制作工具,在/tools目錄下。
android.graphics.Picture
。使用PictureDrawable,很多手機顯示不出來。需要關閉對應的activity的硬件加速屬性。android:hardwareAccelerated="false"
一般在代碼中實現:
Bitmap b = BitmapFactory.decodeResource(getResources(),R.mipmap.cute);
Paint paint = new Paint();
paint.setTextSize(30);
Picture p = new Picture();
Canvas c= p.beginRecording(b.getWidth(),b.getHeight());
c.drawBitmap(b,0,0,paint);
c.drawText("PictureDrawable",20,50,paint);
p.endRecording();
PictureDrawable drawable = new PictureDrawable(p);
ivPicDrawable.setImageDrawable(drawable);
在values目錄下設置color:
#3F51B5
#303F9F
#FF4081
#000000
private void setArgb(int alpha,int red,int green,int blue){
ColorMatrix colorMatrix = new ColorMatrix(new float[]{
red,0,0,0,0,
0,green,0,0,0,
0,0,blue,0,0,
0,0,0,alpha,0
});
drawable.setColorFilter(new ColorMatrixColorFilter(colorMatrix));
view.postInvalidate();
}
LightingColorFilter LightingColorFilter(int mul,int add)= (mul * 原色值 + add) % 255
//表示過濾了blue的顏色,並增強55
drawable.setColorFilter(new LightingColorFilter(0x0000ff,0x000055));
PorterDuffColorFilter PorterDuffColorFilter(int srcColor,PorterDuff.Mode mode)
//mutate方法可以讓同一個drawable在不同的控件上進行展示不同的效果。
drawable.mutate().setColorFilter(new PorterDuffColorFilter(0x0000ff, PorterDuff.Mode.ADD));//18種效果。
GradientDrawable linearGradient = new GradientDrawable();
linearGradient.setGradientType(GradientDrawable.LINEAR_GRADIENT);// RADIAL_GRADIENT,SWEEP_GRADIENT
//xml中只有startColor、centerColor和endColor,在代碼中可以設置任意多個color。
linearGradient.setColors(new int[]{0xff0000, 0xff0001, 0x000ff1, 0xff2310, 0x12ff00});//API 16 above
linearGradient.setShape(GradientDrawable.RECTANGLE);//OVAL,LINE,RING
view.setBackground(linearGradient); // API 16 above
Android5.0以後,引用了Tint的功能。
android:backgroundTint , android:tint及其對應的tintMode。ImageView有這兩個屬性,其它的只有backgound的tint。
LayerDrawable
、LevelListDrawable
和 TransitionDrawable
它們之間有些相似性,都是管理多個 Drawable 的展示,其中 TransitionDrawable 是 LayerDrawable 的子類只管理2個 Drawable。不過,從類繼承體系上分,LevelListDrawable 和 StateListDrawable
才是比較靠近的,效果也相似。
在res/drawable目錄下可以定義根據View的狀態(pressed,focus,checked等)的不同而顯示不同drawable的drawable。這種drawable在開發中經常會用到,比如按鈕點擊顯示按下去的背景。
注意:將正常狀態的drawable放到最後,不然會看不到狀態變化而導致的drawable變化。因為statelist drawbale是從上到下來搜索,如果有匹配的狀態,則顯示對應drawable。
LayerDrawable
是一個多層的Drawable,可以對每一層的drawable進行控制。從而實現一些效果。它是這樣在drawable目錄下定義的:
可以為每一層drawable設置id,這樣可以控制每一層的drawable,從而達到一些特定的效果。比如下面是將最上層的drawable隱藏掉。
vcSzuPZpZLbU06a1xERyYXdhYmxlo6zIu7rzv8nS1L340NCy2df3o6yxyMjn0v6y2KO6IDxjb2RlPmQxLnNldEFscGhhKDApOzwvY29kZT48YnIgLz4NCrWxyLujrNKyv8nS1M2ouf20+sLrwLTJ6NbD0ru49rbgsuO1xGRyYXdhYmxloaPA/cjno7o8L3A+DQo8cHJlIGNsYXNzPQ=="brush:java;">
DisplayMetrics dm = getResources().getDisplayMetrics();
Drawable [] ds = new Drawable[3];
ds[0] = getResources().getDrawable(R.mipmap.mv);
ds[1] = getResources().getDrawable(R.mipmap.mv);
ds[2] = getResources().getDrawable(R.mipmap.mv);
LayerDrawable layerDrawable = new LayerDrawable(ds);
layerDrawable.setLayerInset(0,0,0,(int)(20 * dm.density),(int)(20 * dm.density));//第一個參數表示索引。
layerDrawable.setLayerInset(1,0,0,(int)(40 * dm.density),(int)(40 * dm.density));
layerDrawable.setLayerInset(2,0,0,(int)(60 * dm.density),(int)(60 * dm.density));
imageViewLayer.setImageDrawable(layerDrawable);
LevelListDrawable
根據level-list中的每一個draawable的level范圍來顯示對應的drawable。比如在drawable目錄中定義一個level-list:
-
-
-
-
-
效果如圖,當拖動seekbar改變drawable的level值時,進入到不同的level區間,則會顯示不同的子drawable。
TransitionDraeable
繼承LayerDrawable
,但它只能有2個子drawable。切換drawable會產生漸變動畫,這時一個非常好的效果。同樣,先定義drawable文件:
然後在代碼中設置開始漸變,裡面的參數表示動畫的時間:兩個方法,一個表示正向漸變,一個表示反向漸變。
transitionDrawable.startTransition(500);
transitionDrawable.reverseTransition(500);
效果如下:
ClipDrawable
、InsetDrawable
、RotateDrawable
和ScaleDrawable
都是 DrawableWrapper
的子類。它們都是容器類 Drawable,自生只能有一個子 Drawable,通過對子 Drawable 進行處理來實現 clip、inset、rotate、scale 的效果
使用
標簽定義ClipDrawable,在res/drawable目錄中。
通過在代碼中設置Drawable的Level來控制裁剪效果。容器類Drawable都是通過setLevel(int level)
來控制的,level值的范圍是[0,10000]。
imageView.getDrawable().setLevel(10000);
效果圖:
InsetDrawable
主要是為設置backgroud背景的控件的drawable設置邊距
,類似padding。設置方式也是在res/drawable目錄下,使用
標簽,裡面放一個drawable,然後設置四個邊距。
RotateDrawable
很容易實現旋轉的效果。比如指針轉盤。同樣是在res/drawable目錄下,使用
標簽來設定一個RotateDrawabl。
android:pivotY="50%"
android:visible="true">
上面定義了一個圖片,從0°-180°,以自己的中心點為中心旋轉180。
ScaleDrawable
很容易實現縮放的效果。設置方式和上面的drawable一樣。如:
android:scaleHeight="50%"
android:scaleGravity="right|top">
在 Android5.0(API Level 21)
中引入了 VectorDrawable
和 AnimatedVectorDrawable
,矢量圖不會因為圖像放大而失真,而且占用內存小。所以學會矢量圖並用好它,將對開發 APP 非常有用。VectorDrawable只支持部分的SVG規范。一般去找成型的SVG圖片。
矢量圖中保存的只是圖像繪制的方法:
大寫代表後面的參數是絕對坐標,小寫代表相對坐標。
屬於屬性動畫。
一、前言今天我們開啟Android系統篇的文章了,其實一直想弄,只是之前一直沒有太多深入的了解,最近又把這塊拿出來好好看了一下,所以想從新梳理一下,來看看Android中
Java源文件通過Java編譯器生成CLASS文件,再通過dx工具轉換為classes.dex文件。DEX文件從整體上來看是一個索引的結構,類名、方法名、字段名等信息都存
Android有很多種drawable類型,除了前幾篇詳細講解的shape、selector、layer-list,還有上一篇提到的color、bitmap、
這是作為上一篇Android 數據存儲 如何搞定SQLite Database的實例練習,之所以單獨列出來是因為除了數據庫方面的知識,還涉及其它方面的知識,