1. 程式人生 > >針對imageview的擴充套件(轉)

針對imageview的擴充套件(轉)

這次的總結主要涉及到Dev Guide/User Interface中的Building Custom ComponentsHow Android Draws Views內容和部分Graphics內容。圍繞實現一個自定義圓角的ImageView控制元件(我將它叫做RoundedImageView)展開。

首先說明How自定義控制元件。

在Android中用於人機互動的元件叫做widget,比如Button,TextView之類,都直接或間接繼承自View。

說到這,自定義元件的方法就明朗了,就是使用繼承,具體繼承什麼類根據你的需求定,當然直接繼承自View類的話,這個就屬於完全自定義了。這裡有一個快速一點入門的方法,看Android提供的widget的原始碼

。關於Android提供的類庫的原始碼都在platform/frameworks/base.git這個工程下(至於git的使用方法不在本文範圍內,所以略去不寫了)。至於自定義控制元件的,更為詳細內容可以檢視官方文件Building Custom Components

此外,對於在xml定義圓角屬性,這個我建議檢視一些widget的原始碼,主要思想是在你的View的建構函式中通過解析AttributeSet引數獲得相應的值來獲取引數。還有一些命名控制元件的細節,可以檢視API Demos裡的LabelView這個Demos的程式碼獲得細節,或者Google。

那麼對於這個圓角ImageView具體問題,應該怎麼做呢?

由於需求是做圓角的ImageView,所以我們自然而然的想到擴充套件ImageView類了。所以,首先必須先簡介一下ImageView。

Displays an arbitrary image, such as an icon. The ImageView class can load images from various sources (such as resources or content providers), takes care of computing its measurement from the image so that it can be used in any layout manager, and provides various display options such as scaling and tinting.

顧名思義,就是一顯示圖片的控制元件。圖片源提供了豐富的選項,可以使Bitmap,Drawable,ResouceId,Uri,Matrix。

方法的想法我想到了兩個:

重寫所有設定圖片源的方法,將傳入的圖片改成圓角,在傳給父類相應方法。重寫onDraw()方法,當該RoundedImageView由於某些原因觸發這個回撥函式時,Draw一個圓角的圖。

第一個方法顯然過於麻煩。而且維護代價高,十分不優雅。並且需要很多型別之間相互轉換,效能上也帶來一定額外的開銷。

第二個方法是理想中的不錯的想法。但是對於我這個新手,由於涉及到很多東西,所以技術上帶來了一定難度。

When an Activity receives focus, it will be requested to draw its layout. You can force a View to draw, by calling invalidate(). If the view is visible, onDraw(Canvas) will be called at some point in the future.

得知三點:

當Activity獲得焦點是,Activity會請求畫它的佈局。可以通過呼叫invalidate()方法強制一個View重繪。如果View可見那麼invalidate()會回撥onDraw(Canvas)方法。

此外,我通過檢視ImageView的原始碼,得知4. 每一個set一種型別的圖片資源的時候,最後都會呼叫invalidate()方法來請求重繪。比如說當你呼叫setBitmap()方法後,onDraw()方法就會回撥。

還有,5. ImageView每一種setXX()圖片的方法呼叫後,最終都會將影象資源它轉成Drawable型別。(A Drawable is a general abstraction for "something that can be drawn. 更進一步資訊可以檢視Dev Guide中Graphics )

6. 並且ImageView類提供了getDrawable()獲取這個Drawable物件的方法

根據以上6點,於是,我們可以在繼承自ImageView的RoundedImageView方法中先獲取這個Drawable物件,然後把它圓角化,然後再通過一些方法畫出來

新問題又來了,怎麼畫?

一直未提到的一個事情是onDraw()回撥函式會傳入這個Canvas物件,Draw with a Canvas。

When you're writing an application in which you would like to perform specialized drawing and/or control the animation of graphics, you should do so by drawing through a Canvas. A Canvas works for you as a pretense, or interface, to the actual surface upon which your graphics will be drawn — it holds all of your "draw" calls. Via the Canvas, your drawing is actually performed upon an underlying Bitmap, which is placed into the window.

還是StackOverflow,有人給出了個一個pretty awesome的方法,地址在這裡。(但是我說的這個方法是沒有成為提問人的答案的那個方法)

題外話:似乎最近一些問題的關鍵解答,每次都是StackOverflow上求助解決的,悲劇(還是喜劇)。

最後,對於圖形Graphics這個話題,我所知甚少,也許以後會寫一個詳細一點的總結吧。今天就先到這裡了。

補註:按照StackOverflow上的做法可能會有效能上的多餘開銷,可以考慮將圓角圖片cache到本類的一個私有成員上,這樣不用每次重繪都進行圓角轉換。但是還有一個問題,就是如果客戶呼叫更新Bitmap或者Drawable的方法,那麼如何判斷Cache失效也是一個問題,暫時還沒有想好。

注:本人初學,可能一些細節上會有紕漏,如果你有什麼迷惑可以留言或者可以Google,謝謝!