https://developer.android.com/guide/topics/graphics
Drawables
-
從資源文件中獲取Drawable
val image:Drawable = ResourcesCompat.getDrawable(context.resources, R.drawable.my_image, null)
-
從xml文件中獲取Drawable
val transition = ResourcesCompat.getDrawable(context.resources, R.drawable.transition, null) as TransitionDrawable
-
ShapeDrawable:適用于動態(tài)繪制不同形狀邊長的圖形
class CustomDrawableView(context: Context) : View(context) { private val drawable: ShapeDrawable = run { val x = 10 val y = 10 val width = 300 val height = 50 contentDescription = context.resources.getString(R.string.my_view_desc) ShapeDrawable(OvalShape()).apply { // If the color isn't set, the shape uses black as the default. paint.color = 0xff74AC23.toInt() // If the bounds aren't set, the shape can't be drawn. setBounds(x, y, x + width, y + height) } } override fun onDraw(canvas: Canvas) { drawable.draw(canvas) } }
NinePatchDrawable:左、上是拉伸區(qū)域客冈,右因宇、下是內(nèi)容顯示區(qū)域
-
自定義drawables:重寫draw(Canvas)
class MyDrawable : Drawable() { private val redPaint: Paint = Paint().apply { setARGB(255, 255, 0, 0) } override fun draw(canvas: Canvas) { // Get the drawable's bounds val width: Int = bounds.width() val height: Int = bounds.height() val radius: Float = Math.min(width, height).toFloat() / 2f // Draw a red circle in the center canvas.drawCircle((width / 2).toFloat(), (height / 2).toFloat(), radius, redPaint) } override fun setAlpha(alpha: Int) { // This method is required } override fun setColorFilter(colorFilter: ColorFilter?) { // This method is required } override fun getOpacity(): Int = // Must be PixelFormat.UNKNOWN, TRANSLUCENT, TRANSPARENT, or OPAQUE PixelFormat.OPAQUE }
給drawables添加tint:著色
從image中抽取顏色:Palette類
Vector drawables
- VectorDrawable
- AnimatedVectorDrawable
Handling bitmaps
? 推薦Glide
Selecting Colors with the Palette API
依賴:implementation 'com.android.support:palette-v7:28.0.0'
-
創(chuàng)建Palette對象
// Generate palette synchronously and return it fun createPaletteSync(bitmap: Bitmap): Palette = Palette.from(bitmap).generate() // Generate palette asynchronously and use it on a different // thread using onGenerated() fun createPaletteAsync(bitmap: Bitmap) { Palette.from(bitmap).generate { palette -> // Use generated instance } }
-
定制Palette對象
- addFilter()
- maximumColorCount()
- setRegion()
- addTarget()
-
抽取顏色:getXXXColor()
- Light Vibrant
- Vibrant
- Dart Vibrant
- Light Muted
- Muted
- Dark Muted
-
通過色塊Palette.Swatch創(chuàng)建顏色: getXXXSwatch()
// Set the background and text colors of a toolbar given a // bitmap image to match fun setToolbarColor(bitmap: Bitmap) { // Generate the palette and get the vibrant swatch val vibrantSwatch = createPaletteSync(bitmap).vibrantSwatch // Set the toolbar background and text colors. // Fall back to default colors if the vibrant swatch is not available. with(findViewById<Toolbar>(R.id.toolbar)) { setBackgroundColor(vibrantSwatch?.rgb ?: ContextCompat.getColor(context, R.color.default_title_background)) setTitleTextColor(vibrantSwatch?.titleTextColor ?: ContextCompat.getColor(context, R.color.default_title_color)) } }
Reducing image download sizes
WebP優(yōu)先穗慕;背景透明的用PNG;圖片復(fù)雜用JPG旺矾、簡單用PNG
AS中右鍵PNG文件,即可選擇轉(zhuǎn)換WebP
Hardware acceleration
可在Application、Activity遍坟、Window、View級別分別控制
確定是否開啟:Canvas.isHardwareAccelerated()
-
Android繪制模型(難懂哦)
-
基于軟件的繪制模型
- 對層次結(jié)構(gòu)進(jìn)行無效化處理(invalidate)
- 繪制層次結(jié)構(gòu)
當(dāng)需要更新界面一部分時(shí)晴股,會對所有發(fā)生更改的所有視圖調(diào)用invalidate()愿伴。無效化消息一直傳播到視圖樹上層,以計(jì)算需要重新繪制的“臟區(qū)域”电湘,然后系統(tǒng)會繪制視圖樹中與臟區(qū)域交互的所有視圖隔节。
缺點(diǎn):每次繪制都需要執(zhí)行大量代碼鹅经;每次修改都要調(diào)用invalidate()
-
硬件加速繪制模型
- 對層次結(jié)構(gòu)進(jìn)行無效化處理
- 記錄并更新顯示列表
- 繪制顯示列表
Android 系統(tǒng)不會立即執(zhí)行繪制命令,而是將這些命令記錄在顯示列表中怎诫,這些列表中包含視圖樹繪制代碼的輸出瘾晃。另一項(xiàng)優(yōu)化是,Android 系統(tǒng)只需要記錄和更新被
invalidate()
調(diào)用標(biāo)記為臟視圖的視圖的顯示列表幻妓。只需重新發(fā)出之前記錄的顯示列表蹦误,即可重新繪制未經(jīng)過無效化處理的視圖。
-
-
視圖層
在所有 Android 版本中肉津,視圖能夠通過以下兩種方式渲染到屏幕外緩沖區(qū):使用視圖的繪制緩存或使用
Canvas.saveLayer()
强胰。從 Android 3.0(API 級別 11)開始可以通過View.setLayerType()
方法更好地控制如何及何時(shí)使用層。- LAYER_TYPE_NONE
- LAYER_TYPE_HARDWARE
- LAYER_TYPE_SOFTWARE
view.setLayerType(View.LAYER_TYPE_HARDWARE, null) ObjectAnimator.ofFloat(view, "rotationY", 180f).apply { addListener(object : AnimatorListenerAdapter() { override fun onAnimationEnd(animation: Animator) { view.setLayerType(View.LAYER_TYPE_NONE, null) } }) start() }
-
其他技巧
減少應(yīng)用中的視圖數(shù)量
避免過度繪制
請勿在繪制方法中創(chuàng)建渲染對象
請勿過于頻繁地修改形狀
請勿過于頻繁地修改位圖
-
謹(jǐn)慎使用 Alpha
當(dāng)您使用
setAlpha()
妹沙、AlphaAnimation
或ObjectAnimator
將視圖設(shè)置為半透明時(shí)偶洋,該視圖會在屏幕外緩沖區(qū)渲染,導(dǎo)致所需的填充率翻倍距糖。在超大視圖上應(yīng)用 Alpha 時(shí)玄窝,請考慮將視圖的層類型設(shè)置為LAYER_TYPE_HARDWARE
。
OpenGL ES
-
基礎(chǔ)
-
GLSurfaceView
繪制和操作Api的類悍引,功能類似于SurfaceView恩脂,需要給一個(gè)Renderer對象
-
GLSurfaceView.Renderer
- onSurfaceCreated()
- onDrawFrame()
- onSurfaceChanged()
-
-
聲明
<!-- Tell the system this app requires OpenGL ES 2.0. --> <uses-feature android:glEsVersion="0x00020000" android:required="true" />
-
坐標(biāo)
OpenGL使用了一個(gè)正方形、有別于Android的坐標(biāo)系統(tǒng)吗铐,因此不受硬件屏幕的尺寸和形狀影響东亦。
......