Android自定義組件(一)

1.Activity 的組成結構

Activity代表一個窗口,其本質上是一個PhoneWindow對象,其負責窗口的管理,其負責的DecorView負責界面的效果。DecorView類是FrameLayout的子類,是整個View的根。各組件之間的關係如下圖所示:

(1)Activity負責整個容器的生命週期以及活動,窗口通過window來管理

(2)窗口的繪製以及渲染交給DecorView來完成

(3)從圖中可以得知,開發人員定義的layout都是ContentParent的子視圖 

WindowManager將創建一個ViewRootImpl對象和WindowManagerService進行溝通。WindowManagerService能夠獲取觸摸時間、鍵盤事件以及軌跡球事件,通過ViewRootImpl將事件分發給各個Activity,另外ViewRootImpl還負責整個Activity的GUI繪製。

 2.View樹的繪製流程

(1)測量組件的大小:首先測量子組件的大小,最後纔會確定該組件的大小

(2)確定組件的位置:首先確定頂層View的位置,然後從最頂層開始,從上向下確定各個組件的位置。

(3)組件的繪製:組件的繪製也是一個遞歸的過程,繪製過程是從根容器開始繪製,當根容器繪製結束後纔會繪製子組件,直到所都的組件均繪製完成爲止。(繪製背景background.draw(canvas)->繪製自己onDraw(canvas)->繪製子視圖dispatchDraw(canvas)->繪製滾動條onDrawScrollBars(canvas))

繼承View需要重寫的方法:

(1)構造方法

(2)onDraw()方法,用來繪製View的圖像

(3)如果需要改變View的大小,需要重寫onMeasure()方法

(4)如果要改變其在父控件中的位置,需要重寫onLayout()方法

繼承ViewGroup需要重寫的方法:

(1)重寫OnMeasure()方法,測試子控件的大小。

(2)重寫onLayout()方法,計算子控件的佈局。

(3)在onDraw()方法中,繪製子控件,可有可無。

(4)監聽onTouch事件,響應屏幕觸摸事件。

 

3.Graphics2D

 1.Point和PointF類

1)Point類是最簡單的結構,代表了一個點,實現了Parcelable接口,支持序列化和反序列化。

2)PointF類和Point類是完全相同的,唯一的區別是x和y的取值是float類型

2.Rect和RectF類

Rect類中需要正確理解left、top、right和bottom四個變量的作用:

 矩形是一種常見的圖形,能夠衍生出更多的圖形,如:橢圓、扇形、弧線等等。

3.Bitmap類和BitmapDrawable類

bitmap是用於儲存png、jpg、gif等格式的圖片數據,一般情況是先將圖片讀入bitmap對象,在對圖像進行相關處理,圖片的讀取操作是由BitmapFactory類來完成的。(bitmap是相當佔用系統資源的,所以要及時對其進行回收操作)

 在繪圖中,通常採用“雙緩存”技術,即先將圖繪製到bitmap上,然後再統一展示出來。BitmapDrawable是一種通用的位圖格式,但是相較於bitmap佔用資源更少、性能更高。

4.Cavas類和Paint類

Canvas類中定義了繪圖的方法,Paint類用於指定繪圖參數。

Paint類用於定義繪圖時的參數,主要包含顏色、文本、圖形樣式、位圖模式、濾鏡等方面。

繪製文本時,可以指定文本的大小、對齊方式、文本樣式等屬性,文本樣式主要是文本指定粗體、下劃線、刪除線等修飾屬性。

Canvas類封裝了大量的繪圖方法,繪製的圖形受到Paint對象的影響。一般情況下,在繪製圖形之前我們都先創建一個Paint對象,定義繪製的顏色、樣式等。Paint是一個輕量級的對象,在程序中我們可以創建多個、也可以僅僅創建一個即可。

(1)繪製位圖:

        //繪製一個原圖和比原圖片大三倍的圖 均在一個畫布上顯示
        Bitmap bitmap = Bitmap.createBitmap(500, 800, Bitmap.Config.ARGB_8888);
        Canvas canvas = new Canvas(bitmap);
        Bitmap bmp = BitmapFactory.decodeResource(getResources(), R.drawable.ic_launcher);
        canvas.drawBitmap(bmp, 0, 0, null);
        //獲取圖片的高度和寬度
        int bmpWidth = bmp.getWidth();
        int bmpHeight = bmp.getHeight();
        Rect src = new Rect(0, 0, bmpWidth, bmpHeight);
        Rect dst = new Rect(0, bmpHeight, bmpWidth * 3, bmpHeight * 3);
        canvas.drawBitmap(bmp, src, dst, null);
        tmpIv.setImageBitmap(bitmap);

(2)繪製點:

        Bitmap bitmap = Bitmap.createBitmap(500, 800, Bitmap.Config.ARGB_8888);
        Canvas canvas = new Canvas(bitmap);
//        畫一個點
        Paint paint = new Paint();
        paint.setColor(Color.RED);
        paint.setStrokeWidth(8);//參數越大 點就越大
        canvas.drawPoint(120, 20, paint);//畫一個點
        paint.setColor(Color.BLACK);
        float[] points = new float[]{10, 10, 50, 50, 50, 100, 250, 150};
        canvas.drawPoints(points, paint);
        paint.setColor(Color.GRAY);
        float[] points1 = new float[]{101, 101, 150, 150, 250, 100, 250, 160};
        canvas.drawPoints(points1, 1, 4, paint);//從offset:1開始取count:4個數字 每兩個數字爲一組
        iv.setImageBitmap(bitmap);

 (3)繪製線:

兩個點確定一條直線,同畫點一樣,畫直線同樣有三個重載方法:

        
        Bitmap bitmap = Bitmap.createBitmap(500, 800, Bitmap.Config.ARGB_8888);
        Canvas canvas = new Canvas(bitmap);
        Paint paint = new Paint();
        paint.setColor(Color.RED);
        paint.setStrokeWidth(8);//參數越大 點就越大
        canvas.drawLine(10, 20, 200, 300, paint);
        canvas.drawLines( float[],offset, counts, paint);
        canvas.drawLines( float[],paint);
        iv.setImageBitmap(bitmap);

 (4)繪製矩形:

繪製矩形有直角矩形和圓角矩形,正方形也是矩形的一種,所以Canvas沒有提供正方形的畫法。

繪製矩形時,參數分爲兩種,一種是直接指定left、top、bottom和right等四個參數,一種是直接指定一個Rect或者RectF對象。

繪製圓角矩形共提供了兩個重載方法:

繪製圓角矩形不能分別爲四個角指定圓角,而是統一設置成統一的值。

public void drawRoundRect(float left, float top, float right, float bottom, float rx, float ry,Paint paint)和

public void drawRoundRect(RectF rect, float rx, float ry, Paint paint)
其中rx和ry不一定相同,其分別代表圓角處的水平半徑和垂直半徑,如果兩個值不同則是橢圓上的一段弧線。

        Bitmap bitmap = Bitmap.createBitmap(500, 800, Bitmap.Config.ARGB_8888);
        Canvas canvas = new Canvas(bitmap);
        Paint paint = new Paint();
        paint.setColor(Color.RED);
        canvas.drawRoundRect(10, 10, 400, 300, 50, 30, paint);
        paint.setStyle(Paint.Style.FILL);//FILL:填充內部 STROKE:僅邊框 FILL_AND_STROKE:所有
        canvas.drawRoundRect(new RectF(10, 320, 400, 620), 30, 50, paint);
        iv.setImageBitmap(bitmap);

(5)繪製圓形:

繪製橢圓的大小是由它的外形相切矩形來決定的,所以繪製橢圓的方法有:

public void drawOval(float left, float top, float right, float bottom, Paint paint)和public void drawOval(RectF oval, Paint paint)
上面的兩個方法均是定義了一個矩形結構,繪製的結果就是內切橢圓。

繪製橢圓時,如果長和寬相等,那麼繪製出來的圖形就是一個圓形,但是Canvas提供了更加簡單的方法繪製圓形:

public void drawCircle(float cx, float cy, float radius, Paint paint)
其中:cx和cy是圓心座標,radius是圓的半徑

繪製弧線和扇形本質上是相同的,他們均是橢圓上的一段,繪製方法如下所示:

public void drawArc(RectF oval, float startAngle, float sweepAngle, boolean useCenter, Paint paint)

public void drawArc(float left, float top, float right, float bottom, float startAngle, floatsweepAngle, boolean useCenter, Paint paint)
其中,startAngle表示起始的角度,正數爲順時針,負數爲逆時針,sweepAngle表示扇形或者弧線所佔的角度,userCenter爲true表示扇形,爲false表示弧線。

(6)繪製路徑

Path是一個類,用於繪製複雜圖形,所有的信息都存儲在Path對象中,Canvas根據Path對象來繪製相應的圖形。

Path的功能可以分爲添加線條;矩形、橢圓、弧線;曲線和貝賽爾曲線;對圖形進行運算。

Path對象中如果要添加矩形,橢圓、圓或者圓弧,則需要傳遞一個Path.Direction的參數,其中CW表示順時針,CCW表示逆時針

        Bitmap bitmap = Bitmap.createBitmap(500, 800, Bitmap.Config.ARGB_8888);
        Canvas canvas = new Canvas(bitmap);

        Paint paint = new Paint();
        paint.setStyle(Paint.Style.STROKE);
        Path path = new Path();
        path.addRect(new RectF(10, 10, 300, 100), Path.Direction.CCW);
//        四個角的弧度均不相同,;兩個數確定一個弧度
        path.addRoundRect(new RectF(10, 120, 300, 220),
                new float[]{10, 20, 20, 10, 30, 40, 40, 30}, Path.Direction.CCW);
        path.addOval(new RectF(10, 240, 300, 340), Path.Direction.CCW);
        path.addCircle(60, 390, 50, Path.Direction.CCW);
        path.addArc(new RectF(10, 500, 300, 600), -30, -60);
        canvas.drawPath(path,paint);
        iv.setImageBitmap(bitmap);

貝塞爾曲線又分爲一節貝塞爾曲線、二階貝賽爾曲線、三階貝賽爾曲線以及高階貝塞爾曲線,不過Path類支持二階和三階貝塞爾曲線,在畫一條二階貝塞爾曲線時,我們必須調用moveTo()方法定義一個起點,然後調用

public void quadTo(float x1, float y1, float x2, float y2)方法,其中x1,y1表示控制點,x2,y2表示終點。


        Bitmap bitmap = Bitmap.createBitmap(500, 800, Bitmap.Config.ARGB_8888);
        Canvas canvas = new Canvas(bitmap);

        Paint paint = new Paint();
        paint.setStyle(Paint.Style.STROKE);
        Path path = new Path();
        path.moveTo(100, 100);
        path.quadTo(200, 10, 300, 300);
        canvas.drawPath(path, paint);
        iv.setImageBitmap(bitmap);

三階貝塞爾曲線有一個起點,兩個控制點以及一個終點,Path類通過

public void cubicTo(float x1, float y1, float x2, float y2, float x3, float y3)進行控制,其中x3,y3表示終點。
 

我們還可以將多個Path進行圖形運算,得到更加複雜或者不規則的圖形:

1)Path.Op. DIFFERENCE
差集, 圖形 A 減去與圖形 B 重疊的區域後 A 餘下的區域。
2)Path.Op. INTERSECT
交集, 圖形 A 和圖形 B 的重疊區域。
3)Path.Op. REVERSE_DIFFERENCE
反差集, 圖形 B 減去與圖形 A 重疊的區域後 B 餘下的區域。
4)Path.Op. UNION
並集, 包含了圖形 A 和圖形 B 的所有區域。
5)Path.Op.XOR
補集, 即圖形 A 和圖形 B 的所有區域減去他們的重疊區域後餘下的區域。

        Bitmap bitmap = Bitmap.createBitmap(500, 800, Bitmap.Config.ARGB_8888);
        Canvas canvas = new Canvas(bitmap);

        Paint paint = new Paint();
        paint.setAntiAlias(true);//抗鋸齒
        paint.setStyle(Paint.Style.FILL);
        Path path1 = new Path();
        path1.addRect(new RectF(10, 10, 110, 110), Path.Direction.CCW);
        Path path2 = new Path();
        path2.addCircle(100, 100, 50, Path.Direction.CCW);
        path1.op(path2, Path.Op.XOR);
        canvas.drawPath(path1, paint);
//        paint.setColor(Color.RED);
//        canvas.drawPath(path2, paint);
        iv.setImageBitmap(bitmap);

(7)繪製文字:

Canvas爲我們提供了兩種繪製文字的方式,一種是從指定的位置開始繪製文字,另一種則是沿着Path繪製文字。

1) public void drawText(char[] text, int index, int count, float x, float y, Paint paint)
 public void drawText(String text, float x, float y, Paint paint)
 public void drawText(String text, int start, int end, float x, float y, Paint paint)
 public void drawText(CharSequence text, int start, int end, float x, float y, Paint paint)
上面的方法均是從指定的位置開始繪製文字,其中x,y表示文字繪製的座標位置。

2)public void drawTextOnPath(String text, Path path, float hOffset, float vOffset, Paint paint)
 public void drawTextOnPath(char[] text, int index, int count, Path path, float hOffset, float
vOffset, Paint paint)

其中hOffset和vOffset分別定義了文字和Path之間的水平偏移量和垂直偏移量,正數和負數則影響着文字與路徑的相對位置。

        Bitmap bitmap = Bitmap.createBitmap(500, 800, Bitmap.Config.ARGB_8888);
        Canvas canvas = new Canvas(bitmap);
        Paint paint = new Paint();
        paint.setAntiAlias(true);
        paint.setStyle(Paint.Style.FILL);
        paint.setTextSize(14);
        String text = "哎喲~ 這個可是繪製文字哦~~~";
        canvas.drawText(text, 10, 50, paint);
        canvas.drawText(text, 0, 4, 10, 100, paint);
        canvas.drawText(text.toCharArray(), 4, 10, 10, 150, paint);
        Path path = new Path();
        path.moveTo(10, 200);
        path.quadTo(100, 100, 300, 300);
        canvas.drawTextOnPath(text, path, 15, 15, paint);
        paint.setColor(Color.RED);
        paint.setStyle(Paint.Style.STROKE);
        canvas.drawPath(path, paint);
        iv.setImageBitmap(bitmap);

 

發表評論
所有評論
還沒有人評論,想成為第一個評論的人麼? 請在上方評論欄輸入並且點擊發布.
相關文章