Android的渲染分為2D渲染和3D渲染兩種,當中2D渲染的引擎為Skia。3D渲染的引擎是OpenGL ES。眼下。Android支援OpenGL ES1.0和OpenGL ES 2.0兩種標準。
1.2D影象處理
在Android中,影象處理時開發類似圖片瀏覽器、拍照顧用時必備的基本能力。
須要說明的是,Android支援對BMP、JPEG、PNG等常見影象格式的瀏覽,支援將BMP壓縮為JPEG、PNG等有失真壓縮影象格式。在Android 4.0中,引入了對webp的支援。
BMP沒有採用不論什麼壓縮演算法。當然也沒有不論什麼失真。依據影象深度的不用,BMP有1bit、4bit、8bit和24bit等不同的位深。
在儲存資料時,對BMP影象的掃描方式按從左到右,從下到上的順序進行。
(1)基本介面
影象處理的基本介面主要位於android.graphics和android.graphics.drawable兩個包中,當中android.graphics除了具有主要的影象處理能力外,更偏向於圖形層面的處理。
1)獲取影象基本資訊
影象的基本資訊包含寬、高、畫素和格式等。眼下,Android支援的RGB配置包含ALPHA_8、RGB_565、ARGB_4444、ARGB_8888等,另外還支援將BMP格式的影象壓縮成PNG、JPEG兩種格式。
獲取BMP配置資訊的方法例如以下:
public final Config getConfig()
除了支援影象本身的寬高外,Android還支援基於Canvas、DisplayMerics、給定密度的密度伸縮後的寬高。
獲得影象本身寬高的方法例如以下:
public final int getWidth()
public final int getHeight()
獲得基於Canvas的寬高的方法例如以下:
public int getScaledWidth(Canvas canvas)
public int getScaledHeight(Canvas canvas)
獲得基於DIsplayMetrics的寬高的方法例如以下:
public int getScaledWidth(DisplayMetrics metrics)
public int getScaledHeight(DisplayMetrics metrics)
獲得給定密度的密度伸縮後的寬高的方法例如以下:
public int getScaledWidth(int targetDensity)
public int getScaledHeight(int targetDensity)
在建立BMP影象後,能夠為其填充特定的顏色,方法例如以下:
b.eraseColor(Color.BLACK)
將BMP影象壓縮為有失真壓縮格式的實現例如以下:
Bitmap photo=extras.getParcelable("data");
if(photo!=null){
ByteArrayOutputStream stream =new ByteArrayOutputStream();
photo.compress(Bitmap.CompressFormat.JPEG, 75, stream); //75為影象質量。一般在0~100之間
}
2)Drawable對影象的封裝
在Android中,Drawable用來管理各種但是物件,如影象、圖形等。Drawable能夠用來設定但是物件的邊界(Bounds)、填充(Padding)、狀態(State,如focused、selected等)和層(0~100)等。
其與檢視的差別在於,Drawable無法接收事件。
眼下。Android提供的物件Drawable,如ScaleDrawable、RotateDrawable、ShapeDrawable和TransitionDrawable等。
(1)影象Drawable
影象的Drawable主要有下面幾種。
1)AnimationDrawable
AnimationDrawable通經常使用於設定幀動畫的場景。
2)BitmapDrawable
BitmapDrawable能夠通過資源、Bitmap物件、檔案路徑和輸入流等來構建。
從Bitmap物件中構建BitmapDrawable的示比例如以下:
Bitmap b=BitmapFactory.decodeResource(r, R.drawable.albumart_mp_unknown_list);
mDefaultAlbumIcon=new BirmapDrawable(context.getResource(), b);
從資源中構建BitmapDrawable的示比例如以下:
BitmapDrawable sourceDrawable=(BitmapDrawable)context.getResources().getDrawable(com.android.cts.stub.R.drawable.testimage);
除了Drawable提供的基本方法外,BitmapDrawable還提供了下面比較有價值的方法:
public final Bitmap getBitmap()
public int getOpacity() //獲得透明度
public void setAntiAlias(boolean aa) //是否抗鋸齒
public void setDither(boolean dither) //是否抗抖動
3)PictureDrawable
PictureDrawable並不想BitmapDrawable那樣經常使用。它通常和Picture結合使用,相對Bitmap物件而言,Picture物件小巧得多,它並不儲存實際的畫素,僅記錄畫布繪製的過程。
PictureDrawable物件能夠從Picture物件和輸入流等中獲得,也能夠通過實時繪製獲得。
獲得PictureDrawable物件的示比例如以下:
Picture mPicture=new Picture();
Canvas canvas=mPicture.beginRecording(220, 100);
Paint p=new Paint(Paint.ANTI_ALIAS_FLAG);
p.setColor(0x88FF0000);
canvas.drawCircle(50, 50, 40, p);
p.setColor(Color.GREEN);
p.setTextSize(30);
canvas.drawText("Pictures", 60, 60, p);
Drawable mDrawable = new PictureDrawable(mPicture);
(2)特效Drawable
特效Drawable支援圖形、影象的伸縮、旋轉、形態、變換等。
1)伸縮
伸縮主要依靠ScaleDrawable進行的,其支援佈局、寬、高等引數的輸入。一個典型的示比例如以下:
ScaleDrawable scaleDrawable=newScaleDrawable(new BitmapDrawable(), Gravity.CENTER, 100, 200);
2)旋轉
旋轉主要依靠RotateDrawable進行。其支援從資原始檔裡獲取Drawable, 方法例如以下:
Resources resources=mContext.getResources();
mRotateDrawable=(RotateDrawable)resource.getDrawable(R.drawable.rotatedrawable);
mRotateDrawable.setChangingConfigurations(Configuration.KEYBOARD_12KEY);
3)形態
形態主要依靠ShapeDrawable進行。
通過ShapeDrawable,開發人員能夠畫出矩形、圓等形狀。在進行一些特效設計時。ShapeDrawable比較實用。比如,畫一個矩形的方法例如以下:
ShapeDrawable mShapeDrawable=new ShapeDrawable(new RectShape);
mShapeDrawable.getPaint().setColor(Color.RED);
Rect bounds=new Rect(50, 5, 90, 25);
mShapeDrawable.setBounds(bounds);
mShapeDrawable.draw(canvas);
4)變換
變換主要通過TransitionDrawable進行。TransitionDrawable是LayerDrawable的一個子類,主要在層1和層2之間進行變換。其本質只是是為層1設定透明度而已。假設開始進行變換,那麼執行例如以下方法:
public void startTransition(int durationMillis)
假設希望僅顯示層1,那麼執行例如以下方法:
public void resetTransition()
和其它Drawable略有不同。TransitionDrawable的資源以transition為標籤。
3)解碼影象
Android支援從檔案、流和資源甚至位元組陣列等資料來源對圖形進行解碼,在執行解碼時。能夠配置一些特定的選項,這些選項位於BitmapFactory的Opotions靜態子類中,基本的選項包含抖動(inDither)、縮放(inScaled)、取樣(inSampleSize),RGB配置(inPreferredConfig)、色深(inDensity)、寬(outWidth)、高(outHeight)、MIME型別(outMineType)等,當中取樣表示對原始影象的取樣。比如,inSampleSize=4時,輸出影象的畫素僅為原始影象的1/16。子啊預設情況下,將解碼影象的選項設定為去抖、自己主動伸縮等。
(1)基於資源的解碼
基於資源的解碼主要通過BitmapFactory.decodeResource()進行。
(2)基於位元組陣列的解碼
基於位元組資料的解碼主要通過BitmapFactory.decodeByteArray()進行。
(3)基於檔案解碼
基於檔案解碼主要通過BitmapFactory.decodeFile()進行。
(4)基於流的解碼
基於流的解碼主要通過BitmapFactory.decodeStream()進行。
4)建立影象
建立影象主要是通過Bitmap實現的。Bitmap支援非常據原始影象通過某些變換、伸縮等建立新的影象,也能夠憑空構建影象。建立影象的方法例如以下:
Bitmap mBitmap3=Bitmap.createBitmap(200, 200, Bitmap.Config.ALPHA_8);
對原始影象進行伸縮。進而創建出新影象的方法例如以下:
mBackgroundImageNear=Bitmap.creaeScaledBitmap(mBackgroundImageNear, mCanvasWidth*2, mCanvasHeight, true);
5)影象變換
在Android中進行影象變換須要使用Matrix類。該類中包括了一個3*3的矩陣。專門用於進行影象變換匹配。Matrix沒有結構體。必須對其進行初始化。
通過其reset方法。能夠得到一個單位矩陣。
另外,通過Matrix能夠實現影象的旋轉、伸縮、正弦餘弦變換、傾斜、平移等特效。
(2)縮圖
在Android中,縮圖有著廣泛的應用。能夠用於圖片瀏覽器的特效。也能夠用於視訊的首幀瀏覽。
依據場景的不同,Android提供了多種獲得縮圖的方法。
針對詳細的影象,開發人員能夠通過BitmapFactory的Options來設定取樣大小,依照比例取得縮放影象,方法例如以下:
BitmapFactory.Options options=new BitmapFactory.Options();
options.inSampleSize=16;
Bitmap lastPictureThumb=BitmapFactory.decodeByteArray(data, 0, data.length, options);
假設希望取得固定大小的縮放影象。以上方法顯然是不合適的。以下是一個取得固定大小的縮放影象的參考實現:
InputStream input=mContext.getContentResolver().openInputStream(mUri);
BitmapFactory.options opt=new BitmapFactory.options();
opt.outWidth=200;
opt.outHeight=200;
BitmapFactory.decodeStream(input, null, opt);
眼下Android提供了兩種縮圖模式,一種為MINI_KIND(512畫素*384畫素)模式,一種為MICRO_KIND(96畫素*96畫素)模式,以下為提取縮圖的一個演示樣例:
ImageView thumbnails=(ImageView)view.findViewById(R.id.thumbnails);
Bitmap bitmap=MediaStore.video.Thumbnails.getThumbnail(getContentResolver(), cursor.getLong(cursor.getColumnIndex(MediaStore.Video.Media, _ID)),MediaStore.Video.Thumbnails.MICRO_KIND, null);
thumbnails.setImageBitmap(bitmap);
(3)影象瀏覽
隨著使用者體驗的提高和系統能力的增強。
在進行影象瀏覽時,原生態的瀏覽已經失去了競爭力,以下介紹倒影、縮放、圓角等幾種比較有競爭力的特效的實現。
1)倒影效果的實現
public static Bitmap createReflectionImageWithOrigin(Bitmap bitmap){
final int reflectionGap=4;
int width=bitmap.getWidth();
int height=bitmap.getHeight();
Matrix matrix=new Matrix();
matrix.preScale(1, -1);
Bitmap reflectionImage = Bitmap.createBitmap(bitmap, 0, height/2, width, height/2. matrix, false);
Bitmap bitmapWithReflection=Bitmap.createBitmap(width, (height+height/2), Config.ARGB_8888);
Canvas canvas=new Canvas(bitmapWithReflection);
canvas.drawBitmap(bitmap, 0, 0, null);
Paint deafalutPaint=new Paint();
canvas.drawBitmap(0, height, width, height+reflectionGap, deafalutPaint);
canvas.drawBitmap(reflectionImage, 0, height+reflectionGap, null);
Paint paint=new Paint();
LinearGradient shader=new LinearGradient(0, bitmap.getHeight(), 0. bitmapWithReflection.getHeight()+reflectionGap, 0x70ffffff, 0x00ffffff,TileMode.CLAMP);
paint.setShader(shader);
paint,setXfermode(new PorterDuffXfermode(Mode.DST_IN)); //為畫筆設定傳輸模式
canvas.drawRect(0, height, width, bitmapWithReflection.getHeight()+reflectionGap, paint);
return bitmapWithReflection;
}
2)縮放效果的實現
縮放效果的實現有多種方式,除了可通過ScaleDrawable實現外。還能夠通過Matrix的方式實現。
public static Bitmap zoomBitmap(Bitmap bitmap, int w, int h){
int width=bitmap.getWidth();
int height=bitmap.getHeight();
Matrix matrix=new Matrix();
float scaleWidth=((float)w/width);
float scaleHeight=((float)h/height);
matrix.postScale(scaleWidth, scaleHeight);
Bitmap newbmp=Bitmap.createBitmap(bitmap, 0, 0, width, height, matrix, true);
return newbmp;
}
3)圓角影象的實現
圓角影象的實現主要通過圖形的處理來進行。以下是一個演示樣例:
public static Bitmap getRoundedCornerBitmap(Bitmap bitmap, float roundPx){
Bitmap output=Bitmap.createBitmap(bitmap.getWidth(), bitmap.getHeight(), Config.ARGB_8888);
Canvas canvas=new Canvas(output);
final int color=0xff424242;
final Paint paint=new Paint();
final Rect rect=new Rect(0, 0, bimap.getWidth(), bitmap.getHeight());
final RectF rectF=new RectF(rect);
paint,setAntiAlias(true);
canvas.drawARGB(0,0,0,0);
paint.setColor(color);
canvas.drawRoundRect(rectF, roundPx, roundPx, paint);
paint.setXfermode(new PorterDuffXfermode(Mode.SRC_IN));
canvas.drawBitmap(bitmap, rect, rect, paint);
return output;
}
4)人臉檢測
人臉檢測主要在FaceDetector類中進行。
在Android 4.0之前。Android的人臉檢測能力尚不強大。對人臉的檢測主要是通過對眼睛的檢測來實現的。
換句話說,僅僅要具有兩僅僅眼睛,有沒有鼻子、嘴。FaceDetector都會覺得是人臉。在Android 4.0中。人臉檢測用來實現解鎖功能,很有特色。
在執行詳細的人臉檢測時,所採用的演算法對影象也有要求,其利用的源資料必須為RGB565格式的Bitmap,影象不能太小。否則會檢測不到。影象也不能太大,否則易造成載入異常。檢測到的人臉將放置在FaceDetector.Face中。
Android主要通過檢測人雙眼之間的中間點來推斷人臉的區域。從而產生一個聚焦的矩形區域(HighlightView)。因為完好了檢測演算法,Android人臉識別的速度很高效以至於不得不人為減少對應以保證使用者體驗。
在Android 4.0中,為了進行人臉檢測,能夠通過Camera的setFaceDetectionListener()來設定Canvas.FaceDetectionListener監聽器。通過這樣的方法,可使人臉檢測變得很easy。
2.3D影象處理
在Android 3.0中,Google引入了RenderScript,這樣在進行3D處理時,開發人員有OpenGL、RenderScript兩種工具可供選擇。就詳細場景而言,是選擇OpenGL還是RenderScript作為開發工具。Google提供的建議例如以下:假設開發人員值開發簡單的應用,且效能不是關鍵,或者希望有更好的靈活性和除錯支援,則須要考慮OpenGL;假設考慮移植性且不會用到OpenGL的所有功能。則RenderScript是個不錯的選擇。
(1)OpenGL ES的實現
Open GL ES渲染系統分為Java框架和原生代碼兩部分。
原生代碼主要實現OpenGL ES介面的庫,在Java框架層,javax.microedition.khrons.opengles是Java標準的OpenGL ES包。android.opengl包提供了OpenGL ES系統和Android GUI系統之間的介面。
1)GLSurfaceView
GLSurfaceView繼承於SuifaceView。是專門用於OpenGL ES渲染的基本檢視控制元件。GLSurfaceView具有下面能力:
管理一個Surface。一個Surface是Android渲染系統進行渲染的基本單位。
管理一個EGL顯示。
可將OpenGL ES渲染到Surface上。
通過開發人員自己定義的一個渲染器物件執行實際的渲染。
支援按需或連續的渲染模式(詳細為RENDERMODE_WHEN_DIRTY、RENDERMODE_CONTINUOUSLY)。
支援OpenGL ES除錯。
SurfaceView是Android渲染系統中一個主要的概念。
2)Renderer
渲染器是執行渲染的實際控制元件,也是實際開發中的重點。當然詳細的實現還要看開發人員在OpenGL ES方面的能力。Android原始碼中提供了ClearRenderer、CubeRenderer、DemoRenderer、KubeRenderer、MatrixPaletteRenderer、QuakeRenderer、TriangleRenderer、AccelerometerTestRenderer等渲染器作為參考。Renderer介面實現例如以下:
public interface Renderer{
void onSurfaceCreated(GL10 gl, EGLConfig config);
void onSurfaceChanged(GL19 gl, int width, int height);
void onDrawFrame(GL10 gl);
}
(2)RenderScript的實現
RenderScript的原生程式碼層為開發人員提供了一組能進行高效能3D圖形渲染和計算的API,是開發人員能夠利用C語言以更底層、更高效的方式實現3D效果。
RenderScript的長處在於:採用了C語言進行設計。能夠在多種CPU、GPU架構下執行。可移植性強;RenderScript擁有和OpenGL相近的效能,卻提供了OpenGL所沒有的設計計算API功能;RenderScript能夠簡化3D實現。
RenderScript的不足在於:提供了與OpenGL不同的新的API功能,致使學習成本新增。因為RenderScript能夠執行在CPU等處理器上,除錯比較困難;另外和OpenGL相比。其提供的功能較少。
RenderScript提供給開發人員3套工具:一套基於硬體加速的簡單3D渲染API;一套類似於CUDA的對程式猿友好的運算API;以及一種常見的語言C99。
不同於已有的NDK。為了實現跨平臺。RenderScript在編譯過程中會被編譯為中間位元組碼(LLVM),在執行時才通過JIT技術轉化為機器碼,這樣能夠避免開發階段須要面對某種特定機器架構而帶來的各種問題。
1)RenderScript的架構
RenderScript整體上採用的是主從架構。原生代碼被虛擬機器中的程式碼控制。Android虛擬機器依然控制全部記憶體和應用的生命週期並在不須要時呼叫本地的RenderScript程式碼。從結構上講,RenderScript自上而下能夠分為原生ReaderScript層、反射層、框架層等3層。
原生RenderScript層主要用於高強度計算和圖形渲染,位於rs(實現檔案)和rsh(標頭檔案)檔案裡。因為原生RenderScript層的設計目標是能夠在不同的CPU、GPU上執行,這使得其無法接入NDK和標準的C語言。進而是原生RenderScript層相對有限。這樣的問題主要集中在高效能運算和圖形渲染領域。
反射層本質上是一個原生代碼的包裝器類,使Android架構層能夠和本地RenderScript進行互動。該層內容在編譯時由編譯工具自己主動產生。反射層定義了接入RenderScript的函式和方法。類名為ScriptC_renderscript_file。物件會包括一個RenderScriptGL上下文物件。當中記錄了RenderScript渲染狀態。
框架層通過反射層實現對本地RenderScript層的控制。
Java層對RenderScript的封裝位於Android框架層,其主要實現位於android.renderescript類中。
框架層主要用於處理Activity的生命週期、記憶體管理等,如有須要,也會將觸控和輸入事件中轉給原生RenderScript層進行處理。框架層中最重要的類為RSSurfaceView。
2)RenderScript應用開發
開發人員能夠利用RenderScript進行3D計算和3D影象渲染。進行3D計算和3D影象渲染的差別在於實現特效的演算法不同。
為了開發RenderScript應用,須要先實現rs、rsh檔案作為渲染的介面,然後建立接入點類和擴充套件RSSurfaceView檢視。
原生RenderScript檔案:實現一個原生RenderScript檔案很easy。僅僅需實現例如以下幾方面:通過預處理命令生命要反射的Java檔案包名;通過預處理命令生命RenderScript版本號,眼下僅為“1”;引入標頭檔案rs_graphics.sh;一個執行實際渲染工作的root方法;一個用於root方法執行前初始化工作的init。其它用於RenderScript的變數、指標、結構體。
實現RenderScript接入點:應用層和原生RenderScript層的通訊須要藉助反射層來進行,反射層在編譯後會作為資原始檔生成在\res\raw資料夾中,檔名稱為rs_filename.bc。
擴充套件RSSurfaceView:為了執行渲染。必須擴充套件RSSurfaceView檢視,建立RenderScript上下文。
3.圖形處理
在Android中,圖形的處理雖不是普通應用層開發人員關注的重點,但其卻是整個UI渲染系統的基石。而這一切都是業界著名的圖形渲染引擎Skia造成的。
(1)基本介面
Android的圖形處理介面多位於android.graphics包中,對於2D圖形。實際的渲染工作是通過框架層的Skia引擎來進行的。
為了在畫布上畫出各種圖形,須要考慮4個方面的要素:用來駐留畫素的Bitmap物件、承接畫圖操作的Canvas物件、畫圖原語和畫筆。
1)Canvas
Canvas能夠支援繪製各種各樣的圖形,預設支援點、線、矩形、圓、文字、圖片等圖形。當畫圖操作完畢後。能夠呼叫save方法儲存。隨後能夠呼叫Canvas的平移、縮放、旋轉、錯切、裁剪等操作。假設希望恢復Canvas之前儲存的狀態,則須要呼叫restore方法。
2)畫圖原語
畫圖原語主要包含Rect、Path、Text、Bitmap等,本質上,這些原語均是點、線的組合。
繪製矩形:Canvas提供了drawRect方法。
繪製線:Android支援各種線的組合,通過這些組合。開發人員能夠繪製出非常多圖形。
繪製文字:Canvas提供了drawText方法。
繪製圖像:採用方法drawBitmap。
3)畫筆
Paint能夠設定各種屬性,如ARGB、透明度、抗鋸齒、顏色、陰影、光柵化、字型等。
4)渲染特效
在圖形處理上。Android支援基於Shader的多種渲染特效。如LinearGradient支援線性漸變、ComposeShader支援混合漸變、BitmapShader支援Bitmap漸變、RadialGradient支援環形漸變、SweepGradient支援梯度漸變等,實現渲染特效的步驟為:
(a)建立渲染物件Shader。
(b)通過setShader方法為Paint設定渲染物件。
(c)執行渲染
(1)線性漸變
LinearGradient對線性漸變的支援主要通過X軸、Y軸、顏色和平鋪模式進行,以下是LinearGradient的建構函式:
public LinearGradien(floar x0, float y0, float x1, float y1, int color0, int color1, TileMode tile)
LinearGradient還支援更復雜的分段漸變效果。方法例如以下:
public LinearGradient(float x0, float y0, float x1, float y1, int colors[], float positions[], TileMode tile)
眼下,Android支援的平鋪模式包含CLAMP、REPEAT、MIRROR等。當中CLAMP模式表示假設在預先定義的範圍外進行繪製,就反覆邊界的顏色;REPEAT模式表示沿著漸變方向迴圈反覆;MIRROR模式與REPEAT模式一樣都是迴圈反覆。但MIRROR模式會對稱反覆。
(2)混合漸變
ComposeShader支援混合漸變,即兩種漸變的組合。
以下是一個演示樣例:
LinearGradient blueGradient=new LinearGradient(0, 0, SIZE, 0,Color.GREEN, Color.BLUE, Shader.TileMode.CLAMP);
LinearGradient blueGradient=new LinearGradient(0, 0,SIZE, Color.GREEN, Color.RED, Shade.TileMode.CLAMP);
ComposeShader shader=new ComposeShader(blueGradient, redGradient, PorterDuff.Mode.SCREEN);
Bitmap bitmap=Bitmap.createBitmap(SIZE, SIZE, Config.ARGB_8888);
Canvas canvas=new Canvas(bitmap);
Paint paint=new Paint();
paint.setShader(shader);
canvas.drawPaint(paint);
(3)Bitmap漸變
BitmapShader主要用來渲染影象,示比例如以下:
Bitmap tile=Bitmap.createBitmap(TILE_WIDTH, TILE_HEIGHT, Config.ARGB_8888);
tile.eraseColor(BORDER_COLOR);
Canvas c=new Canvas(tile);
Paint p=new Paint();
p.setColor(CENTER_COLOR);
c.drawRect(BORDER_WIDTH, BORDER_WIDTH, TILE_WIDTH-BORDER_WIDTH, TILE_HEIGHT-BORDER_WIDTH, p);
BitmapShader shader=new BitmapShader(tile, Shader.TileMode.REPEAT, Shader.TileMode.REPEAT);
Paint paint=new Paint();
Bitmap b=Bitmap.createBitmap(NUM_TILES*TILE_WIDTH-TILE_WIDTH/2, NUM_TILES*TILE_HTIGHT-TILE_HEIGHT/2, Config.ARGB_8888);
b.eraseColor(Color.BLACK);
Canvas canvas=new Canvas(b);
canvas.drawPaint(paint);
(4)環形漸變
RadialGradient支援環形漸變。示比例如以下:
final int[] colors={Color.BLUE, Color.GREEN, Color.RED};
final float[] positions={0f, 0.3f, 1f};
int tolerance=(int)(0xFF/(0.3f*RADIUS)*2);
RadialGradient fg=new RadialGradient(CENTER, CENTER, RADIUS, colors, positions, Shader.TileMode.CLAMP);
Bitmap b=Bitmap.createBitmap(SIZE, SIZE, Bitmap.Config.ARGB_8888);
Canvas canvas=new Canvas(b);
Pain p=new Paint();
p.setShader(rg);
canvas.drawRect(0, 0, SIZE, SIZE, p);
(5)梯度漸變
SweepGradient支援梯度漸變。示比例如以下:
final int[] colors=new int[] {Color.GREEN, Color.RED};
final float[] positions=new float[]{0f, 1f};
Shader shader=new SweepGradient(CENTER, CENTER, colors[0], colors[1]);
mPaint.setShader(shader);
mCanvas.drawRect(new Rect(0, 0, SIZE, SIZE), mPaint);
(2)Surface渲染系統
在Android中,更底層的渲染是通過Android渲染管理器Surface Flinger進行管理的。Surface Flinger通過管理一系列的Surface並對Surface進行組合。然後借組Skia和OpenGL ES來完畢終於的渲染操作。Surface Flinger的引入使Android的渲染機制顯得十分出色。
Android的圖形相同採用了C/S架構的機制。server(Surface Flinger)端程式碼主要由C++編寫,client程式碼則分為兩部分,一部分為Java編寫的供應用呼叫的API。 還有一部分(SurfaceComposerClient)為由C++完畢的底層原生實現。
Surface渲染系統例如以下圖所看到的:
1)Surface
Android圖形系統中一個最重要的概念是Surface。每一個Surface都會建立一個畫布(Canvas)物件,每一個畫布物件都相應於一個位圖(Bitmap)物件。該點陣圖物件中儲存著檢視(View)及其子類等UI控制元件的Surface上的內容。
依據場景的不同,Surface能夠分為多個型別,如Normal Surface、 Blur Surface、Dim Surface、 PushBuffersSurface等。框架層通過Window傳遞的標誌位(flags)來決定建立的Surface的型別。
在通常情況下。每一個Surface相應兩個緩衝:前端緩衝和後端緩衝。後端緩衝即在畫布物件上渲染資訊時畫布物件相應的那個點陣圖物件。
應用通過SurfaceView、ViewRoot等建立Java Surface(同一時候建立Canvas)。並將圖形繪製到Surface物件上,終於將其渲染到螢幕上。
Java Surface建立ISurface(BnSurface)併發送命令,比如更新Surface內容到螢幕上。Server端接受這個命令並執行對應操作。
2)Layer
每一個Surface相應一個Layer物件,Surface Fligner負責將各個Layer物件的前端緩衝組合並渲染到螢幕上。
多個Layer構成一個層向量LayerVector。 它包括了當前全部Surface相應的Layer。Surface Flinger依據每一個Layer的Z序(Z-order)把多個Layer組合為一個終於的螢幕上顯示的緩衝。
Z序實際上定義了窗體之間的層疊順序。Z序實際上是相對螢幕座標而言的。一般螢幕上的全部窗體均有一個座標系,即原點在左上角。X軸水平向右。Y軸垂直向下的座標系。Z序是相當於一個假象的Z軸而言的。這個Z軸從螢幕外指向螢幕內。窗體在這個Z軸上的值確定了其Z序。Z序值大的窗體覆蓋了Z序值小的窗體。者其實就是Activity棧的實現邏輯。
在LayerVector中,每一個Layer都相應一個Z序值,同一時候通過為Layer設定優先順序的方式,是某些Layer能夠實現前端顯示。最後通過相應的裁剪演算法來計算能夠被顯示的區域。
Layer共同擁有4中模式:Layer、LayerDim、LayerBuffer。這4種模式分別與4種類型的Surface相應。
(1)Layer模式
Layer模式是最常見的一種Layer。從使用者角度看。也是最經常使用的全屏窗體相應的模式。
(2)LayerDim模式
LayerDim模式主要用於當前窗體非全屏的情況下,可使可視背景窗體產生一個變暗的透明效果。這是全部對話方塊都具有的特效。
(3)LayerBlur模式
LayerBlur模式在LayerDim模式的基礎上使背景窗體產生模糊的效果。
(4)PushBuffersSurface模式
PushBuffersSurface模式沒有渲染緩衝。其Surface的內容必須有外部實體推送過來,通經常使用於攝像頭預覽、視訊播放等場景中。
3)GraphicBuffer
在建立Surface時,系統會為每一個Surface分配兩個緩衝;前端緩衝和後端緩衝。不論前端緩衝還是後端緩衝,本質上均為GraphicBuffer物件。依據渲染方式的不同。GraphicBuffer的使用方法能夠分為多種,系統會依據緩衝的使用情況設定渲染方式為軟體渲染、硬體渲染和硬體組合。
前端緩衝和後端緩衝是依據緩衝所處的位置進行差別的。當緩衝在後端時,系統在該緩衝上進行渲染並完畢後,該緩衝轉變為前端緩衝和其它Surface中的Layer過載紋理並顯示在螢幕上。
4.動畫處理
眼下Android支援3種動畫。即補間動畫、幀動畫、屬性動畫(屬性動畫是在Android3.0引入的)。當中補間動畫主要採用用於實現Android控制元件本身的動畫效果。幀動畫用於實現類似GIF格式動畫的效果。
Android暫不支援GIF格式動畫,在播放GIF格式動畫時僅顯示首幀。假設確實須要在Android環境下支援GIF格式動畫,變通的方法是通過WebView來載入,僅僅需將URI設為本地GIF資原始檔就可以。可是這樣要消耗大量的資源。建立一個WebView物件至少須要8MB的RAM。
屬性動畫在開發遊戲應用時比較常見,其能力很強大,差點兒能夠用於全部的物件。
(1)補間動畫
補間動畫(Tween Animation),即通過對場景中的物件不斷進行影象變換(透明度、平移、縮放、旋轉)產生的動畫效果。針對不用的影象變換動畫,Android提供了AlphaAnimation、ScaleAnimation、RotateAnimation、TranslateAnimation等4個類的支援。
補間動畫並不針對影象,它還支援TextView等檢視物件。Android的控制元件動畫效果均是基於補間動畫實現的。
最經常使用的控制元件動畫是基於ViewAnimator類進行的,其子類包含ViewFlipper、ViewSwitcher、ImageSwitcher、TextSwitcher等。
對於控制元件動畫,一些常見的動畫效果並不須要開發人員自行實現,除了淡入淡出效果外。Android還支援下推、上推、縮水淡化、成長淡化等多種動畫效果。
動畫的進度是通過插補器來控制的。
眼下,Android支援7種插補器效果,即加速減速插補器、加速插補器、預期插補器、預期超調插補器、彈跳插補器、圓插補器、減速插補器、線性插補器、超調插補器。最簡單的是線性插補器,動畫的進度依照設定的時間均勻展開。其它的插補器都是非線性插補器。
假設這7中插補器還無法滿足開發人員的需求,那麼開發人員能夠通過實現TimeInterpolator介面自己定義一個插補器。
Animation在執行動畫時,監聽器AnimationListener可供開發人員使用,可用於監視動畫的開始、結束和反覆播放等動作。
各種動畫特效能夠組合到AnimationSet中,從而實現複雜的動畫效果。
(2)幀動畫
幀動畫即按順序播放一組影象形成的動畫。幀動畫有兩個比較重要的屬性。一個是android:oneshot屬性,用於設定播放模式(是單次播放還是迴圈播放);一個是android:duration屬性,用於設定每幀的持續時間。單位為毫秒(ms)。幀動畫的資原始檔位於res\anim目錄下。
為了連續顯示一組影象。產生動畫效果,Android須要利用XML資原始檔和AnimationDrawable協同工作。
AnimationDrawable的start方法不能再Activity的onCreate方法中呼叫。這是由於此時影象資源尚未全然載入。假設希望能在Activity啟動後馬上開始動畫,那麼能夠在Activity的onWindowFocusChanged方法中執行start方法呼叫。
在Android中,進度條的實現利用的就是幀動畫的技術。
(3)屬性動畫
屬性動畫在Android3.0中引入,為開發人員提供了更強大的自己定義動畫的能力。屬性動畫在遊戲開發中比較常見。
在Android中,眼下定義了3種類型的演講器:ArgbEvaluator、FloatEvaluator、IntEvaluator。
演進器用於通知動畫系統怎樣計算給定屬性的值。
假設用於動畫的屬性不是int、float、color型別的,那麼開發人員能夠擴充套件TypeEvaluator介面來計算目標物件的屬性變化。
Animator提供了建立動畫的基本結構。但在通常情況下。因為Animator僅提供最主要的功能,故須要對其進行擴展才幹使用。眼下,Android屬性系統提供了3種動畫機制ValueAnimator、ObjectAnimator、AnimatorSet可供選擇。
為了更好地支援動畫播放過程中的互動,Animator通過設定監聽器Animator.AnimatorListener來監聽動畫的開始、結束、反覆播放、取消等多個狀態。
假設開發人員對監聽動畫的全部狀態不感興趣,則須要考慮通過AnimatorListenerAdapter來處理動畫監聽。
1)ValueAnimator
ValueAnimator支援整形、浮點型、顏色等型別的動畫。
以下是一個浮點型動畫的演示樣例:
ValueAnimator animation=ValueAnimator.ofFloat(0f, 1f);
animation.setDuration(1000);
animation.start();
開發人員能夠設定自己定義型別的動畫,方法例如以下:
ValueAnimator animation =ValueAnimator.ofObject(new MyTypeEvaluator(), startPropertyValue, endPropertyValue);
animation.setDuration(1000);
animation.start();
通過監聽器ValueAnimator.AnimatorUpdateListener,開發人員能夠監聽動畫中每一幀的播放。
2)ObjectAnimator
ObjectAnimator是ValueAnimator的子類。其動畫實現和ValueAnimator類似,但須要指定物件和物件的屬性(作為字串),方法例如以下:
ObjectAnimator anim=ObjectAnimator.ofFloat(foo, "alpha", 0f, 1f);
anim.setDuration(1000);
anim.start();
以下是一個為ObjectAnimator設定監聽器的演示樣例:
ValueAnimatorAnimator fadeAnim=ObjectAnimator.ofFloat(newBall, "alpha", 1f, 0f);
fadeAnim.setDuration(250);
fadeAnim.addListener(new AnimatorListenerAdapter(){
public void onAnimationEnd(Animator animation){
balls.remove(((ObjectAnimator)animation).getTarget());
}
});
3)AnimatorSet
AnimatorSet支援對動畫的組合。從而使開發人員能夠構建十分複雜的動畫。
向AnimatorSet中加入動畫的方式很靈活。能夠一次加入一個動畫,也能夠一次加入多個動畫。
在AnimatorSet中相同能夠設定動畫的持續時間、啟動延遲、插補器等。
和其它Android控制元件一樣,屬性動畫也能夠通過資原始檔的方式進行配置,當中ValueAnimator相應的標籤為animator,ObjectAnimator相應的標籤為objectAnimator。AnimatorSet相應的標籤為set。當中ValueAnimator和ObjectAnimator均能夠設定動畫的持續時間、起始值、屬性型別、延遲、反覆次數、反覆模式等。另外,ObjectAnmator還能夠用於設定屬性名。
4)Keyframe
keyframe本質上是<時間,值>對,其能夠定義在動畫的特定時間狀態。
開發人員還能夠為keyframe定義插補器,使在前一個keyframe和當前keyframe之間有更復雜的演進,方法例如以下:
public void setInterpolator(TimeInterpolator interpolator)
5)佈局動畫
針對單個檢視物件的動畫產生的效果總是有限的,在Android3.0中。還引入了佈局動畫。其作用域為ViewGroup及其子類。
為了使ViewGroup及其子類應用動畫小姑,須要為其設定LayoutTransition屬性。方法例如以下:
public void setLayoutTransition(LayoutTransition transition)
通過LayoutTransition屬性,開發人員能夠針對ViewGroup及其子類的多種狀態,如顯示(APPEARING)、變化(CHANGE_APPEARING)、變化消失(CHANGE_DISAPPEARING)、消失(DISAPPEARING)等設定動畫。
設定動畫的方法例如以下:
public void setAnimator(int transitionType, Animatior animator)