整合營(yíng)銷服務(wù)商

          電腦端+手機(jī)端+微信端=數(shù)據(jù)同步管理

          免費(fèi)咨詢熱線:

          三個(gè)繪圖工具類詳解

          .相關(guān)方法詳解


          1)Paint(畫筆):

          就是畫筆,用于設(shè)置繪制風(fēng)格,如:線寬(筆觸粗細(xì)),顏色,透明度和填充風(fēng)格等 直接使用無參構(gòu)造方法就可以創(chuàng)建Paint實(shí)例: Paint paint = new Paint( );

          我們可以通過下述方法來設(shè)置Paint(畫筆)的相關(guān)屬性,另外,關(guān)于這個(gè)屬性有兩種, 圖形繪制相關(guān)與文本繪制相關(guān):

          • setARGB(int a,int r,int g,int b): 設(shè)置繪制的顏色,a代表透明度,r,g,b代表顏色值。
          • setAlpha(int a): 設(shè)置繪制圖形的透明度。
          • setColor(int color): 設(shè)置繪制的顏色,使用顏色值來表示,該顏色值包括透明度和RGB顏色。
          • setAntiAlias(boolean aa): 設(shè)置是否使用抗鋸齒功能,會(huì)消耗較大資源,繪制圖形速度會(huì)變慢。
          • setDither(boolean dither): 設(shè)定是否使用圖像抖動(dòng)處理,會(huì)使繪制出來的圖片顏色更加平滑和飽滿,圖像更加清晰
          • setFilterBitmap(boolean filter): 如果該項(xiàng)設(shè)置為true,則圖像在動(dòng)畫進(jìn)行中會(huì)濾掉對(duì)Bitmap圖像的優(yōu)化操作, 加快顯示速度,本設(shè)置項(xiàng)依賴于dither和xfermode的設(shè)置
          • setMaskFilter(MaskFilter maskfilter): 設(shè)置MaskFilter,可以用不同的MaskFilter實(shí)現(xiàn)濾鏡的效果,如濾化,立體等
          • setColorFilter(ColorFilter colorfilter): 設(shè)置顏色過濾器,可以在繪制顏色時(shí)實(shí)現(xiàn)不用顏色的變換效果
          • setPathEffect(PathEffect effect) 設(shè)置繪制路徑的效果,如點(diǎn)畫線等
          • setShader(Shader shader): 設(shè)置圖像效果,使用Shader可以繪制出各種漸變效果
          • setShadowLayer(float radius ,float dx,float dy,int color):在圖形下面設(shè)置陰影層,產(chǎn)生陰影效果, radius為陰影的角度,dx和dy為陰影在x軸和y軸上的距離,color為陰影的顏色
          • setStyle(Paint.Style style): 設(shè)置畫筆的樣式,為FILL,F(xiàn)ILL_OR_STROKE,或STROKE
          • setStrokeCap(Paint.Cap cap): 當(dāng)畫筆樣式為STROKE或FILL_OR_STROKE時(shí),設(shè)置筆刷的圖形樣式, 如圓形樣Cap.ROUND,或方形樣式Cap.SQUARE
          • setSrokeJoin(Paint.Join join): 設(shè)置繪制時(shí)各圖形的結(jié)合方式,如平滑效果等
          • setStrokeWidth(float width): 當(dāng)畫筆樣式為STROKE或FILL_OR_STROKE時(shí),設(shè)置筆刷的粗細(xì)度
          • setXfermode(Xfermode xfermode): 設(shè)置圖形重疊時(shí)的處理方式,如合并,取交集或并集,經(jīng)常用來制作橡皮的擦除效果
          • setFakeBoldText(boolean fakeBoldText): 模擬實(shí)現(xiàn)粗體文字,設(shè)置在小字體上效果會(huì)非常差
          • setSubpixelText(boolean subpixelText): 設(shè)置該項(xiàng)為true,將有助于文本在LCD屏幕上的顯示效果
          • setTextAlign(Paint.Align align): 設(shè)置繪制文字的對(duì)齊方向
          • setTextScaleX(float scaleX): 設(shè)置繪制文字x軸的縮放比例,可以實(shí)現(xiàn)文字的拉伸的效果
          • setTextSize(float textSize): 設(shè)置繪制文字的字號(hào)大小
          • setTextSkewX(float skewX): 設(shè)置斜體文字,skewX為傾斜弧度
          • setTypeface(Typeface typeface): 設(shè)置Typeface對(duì)象,即字體風(fēng)格,包括粗體,斜體以及襯線體,非襯線體等
          • setUnderlineText(boolean underlineText): 設(shè)置帶有下劃線的文字效果
          • setStrikeThruText(boolean strikeThruText): 設(shè)置帶有刪除線的效果
          • setStrokeJoin(Paint.Join join): 設(shè)置結(jié)合處的樣子,Miter:結(jié)合處為銳角, Round:結(jié)合處為圓?。築EVEL:結(jié)合處為直線
          • setStrokeMiter(float miter):設(shè)置畫筆傾斜度
          • setStrokeCap (Paint.Cap cap):設(shè)置轉(zhuǎn)彎處的風(fēng)格 其他常用方法:
          • float ascent( ):測(cè)量baseline之上至字符最高處的距離


          • float descent():baseline之下至字符最低處的距離
          • int breakText(char[] text, int index, int count, float maxWidth, float[] measuredWidth): 檢測(cè)一行顯示多少文字
          • clearShadowLayer( ):清除陰影層 其他的自行查閱文檔~

          2)Canvas(畫布):

          畫筆有了,接著就到畫布(Canvas),總不能憑空作畫是吧~常用方法如下:

          首先是構(gòu)造方法,Canvas的構(gòu)造方法有兩種:

          Canvas(): 創(chuàng)建一個(gè)空的畫布,可以使用setBitmap()方法來設(shè)置繪制具體的畫布。

          Canvas(Bitmap bitmap): 以bitmap對(duì)象創(chuàng)建一個(gè)畫布,將內(nèi)容都繪制在bitmap上,因此bitmap不得為null。

          接著是 1.drawXXX()方法族:以一定的坐標(biāo)值在當(dāng)前畫圖區(qū)域畫圖,另外圖層會(huì)疊加, 即后面繪畫的圖層會(huì)覆蓋前面繪畫的圖層。 比如:

          • drawRect(RectF rect, Paint paint) :繪制區(qū)域,參數(shù)一為RectF一個(gè)區(qū)域
          • drawPath(Path path, Paint paint) :繪制一個(gè)路徑,參數(shù)一為Path路徑對(duì)象
          • drawBitmap(Bitmap bitmap, Rect src, Rect dst, Paint paint) : 貼圖,參數(shù)一就是我們常規(guī)的Bitmap對(duì)象,參數(shù)二是源區(qū)域(這里是bitmap), 參數(shù)三是目標(biāo)區(qū)域(應(yīng)該在canvas的位置和大小),參數(shù)四是Paint畫刷對(duì)象, 因?yàn)橛玫搅丝s放和拉伸的可能,當(dāng)原始Rect不等于目標(biāo)Rect時(shí)性能將會(huì)有大幅損失。
          • drawLine(float startX, float startY, float stopX, float stopY, Paintpaint) : 畫線,參數(shù)一起始點(diǎn)的x軸位置,參數(shù)二起始點(diǎn)的y軸位置,參數(shù)三終點(diǎn)的x軸水平位置, 參數(shù)四y軸垂直位置,最后一個(gè)參數(shù)為Paint 畫刷對(duì)象。
          • drawPoint(float x, float y, Paint paint): 畫點(diǎn),參數(shù)一水平x軸,參數(shù)二垂直y軸,第三個(gè)參數(shù)為Paint對(duì)象。
          • drawText(String text, float x, floaty, Paint paint) : 渲染文本,Canvas類除了上面的還可以描繪文字,參數(shù)一是String類型的文本, 參數(shù)二x軸,參數(shù)三y軸,參數(shù)四是Paint對(duì)象。
          • drawOval(RectF oval, Paint paint):畫橢圓,參數(shù)一是掃描區(qū)域,參數(shù)二為paint對(duì)象;
          • drawCircle(float cx, float cy, float radius,Paint paint): 繪制圓,參數(shù)一是中心點(diǎn)的x軸,參數(shù)二是中心點(diǎn)的y軸,參數(shù)三是半徑,參數(shù)四是paint對(duì)象;
          • drawArc(RectF oval, float startAngle, float sweepAngle, boolean useCenter, Paint paint): 畫弧,參數(shù)一是RectF對(duì)象,一個(gè)矩形區(qū)域橢圓形的界限用于定義在形狀、大小、電弧,參數(shù)二是起始角 (度)在電弧的開始,參數(shù)三掃描角(度)開始順時(shí)針測(cè)量的,參數(shù)四是如果這是真的話,包括橢圓中心的電 弧,并關(guān)閉它,如果它是假這將是一個(gè)弧線,參數(shù)五是Paint對(duì)象;

          2.clipXXX()方法族:在當(dāng)前的畫圖區(qū)域裁剪(clip)出一個(gè)新的畫圖區(qū)域,這個(gè)畫圖區(qū)域就是canvas 對(duì)象的當(dāng)前畫圖區(qū)域了。比如:clipRect(new Rect()),那么該矩形區(qū)域就是canvas的當(dāng)前畫圖區(qū)域

          3.save()restore()方法: save( ):用來保存Canvas的狀態(tài)。save之后,可以調(diào)用Canvas的平移、放縮、旋轉(zhuǎn)、錯(cuò)切、裁剪等操作! restore():用來恢復(fù)Canvas之前保存的狀態(tài)。防止save后對(duì)Canvas執(zhí)行的操作對(duì)后續(xù)的繪制有影響。 save()和restore()要配對(duì)使用(restore可以比save少,但不能多),若restore調(diào)用次數(shù)比save多,會(huì)報(bào)錯(cuò)!

          4.translate(float dx, float dy): 平移,將畫布的坐標(biāo)原點(diǎn)向左右方向移動(dòng)x,向上下方向移動(dòng)y.canvas的默認(rèn)位置是在(0,0)

          5.scale(float sx, float sy):擴(kuò)大,x為水平方向的放大倍數(shù),y為豎直方向的放大倍數(shù)

          6.rotate(float degrees):旋轉(zhuǎn),angle指旋轉(zhuǎn)的角度,順時(shí)針旋轉(zhuǎn)


          3)Path(路徑)

          簡(jiǎn)單點(diǎn)說就是描點(diǎn),連線~在創(chuàng)建好我們的Path路徑后,可以調(diào)用Canvas的drawPath(path,paint) 將圖形繪制出來~常用方法如下:

          • addArc(RectF oval, float startAngle, float sweepAngle:為路徑添加一個(gè)多邊形
          • addCircle(float x, float y, float radius, Path.Direction dir):給path添加圓圈
          • addOval(RectF oval, Path.Direction dir):添加橢圓形
          • addRect(RectF rect, Path.Direction dir):添加一個(gè)區(qū)域
          • addRoundRect(RectF rect, float[] radii, Path.Direction dir):添加一個(gè)圓角區(qū)域
          • isEmpty():判斷路徑是否為空
          • transform(Matrix matrix):應(yīng)用矩陣變換
          • transform(Matrix matrix, Path dst):應(yīng)用矩陣變換并將結(jié)果放到新的路徑中,即第二個(gè)參數(shù)。

          更高級(jí)的效果可以使用PathEffect類!

          幾個(gè)To:

          • moveTo(float x, float y):不會(huì)進(jìn)行繪制,只用于移動(dòng)移動(dòng)畫筆
          • lineTo(float x, float y):用于直線繪制,默認(rèn)從(0,0)開始繪制,用moveTo移動(dòng)! 比如 mPath.lineTo(300, 300); canvas.drawPath(mPath, mPaint);
          • quadTo(float x1, float y1, float x2, float y2): 用于繪制圓滑曲線,即貝塞爾曲線,同樣可以結(jié)合moveTo使用!


          • rCubicTo(float x1, float y1, float x2, float y2, float x3, float y3) 同樣是用來實(shí)現(xiàn)貝塞爾曲線的。 (x1,y1) 為控制點(diǎn),(x2,y2)為控制點(diǎn),(x3,y3) 為結(jié)束點(diǎn)。 Same as cubicTo, but the coordinates are considered relative to the current point on this contour.就是多一個(gè)控制點(diǎn)而已~ 繪制上述的曲線: mPath.moveTo(100, 500); mPath.cubicTo(100, 500, 300, 100, 600, 500); 如果不加上面的那個(gè)moveTo的話:則以(0,0)為起點(diǎn),(100,500)和(300,100)為控制點(diǎn)繪制貝塞爾曲線


          • arcTo(RectF oval, float startAngle, float sweepAngle): 繪制弧線(實(shí)際是截取圓或橢圓的一部分)ovalRectF為橢圓的矩形,startAngle 為開始角度, sweepAngle 為結(jié)束角度。

          2.動(dòng)手試試:

          屬性那么多,肯定要手把手的擼一下,才能加深我們的映像是吧~ 嘿嘿,畫圖要么在View上畫,要么在SurfaceView上畫,這里我們?cè)赩iew上畫吧, 我們定義一個(gè)View類,然后再onDraw()里完成繪制工作!

          /**

          * Created by Jay on 2015/10/15 0015.

          */

          public class MyView extends View{

          private Paint mPaint;

          public MyView(Context context) {

          super(context);

          init();

          }

          public MyView(Context context, AttributeSet attrs) {

          super(context, attrs);

          init();

          }

          public MyView(Context context, AttributeSet attrs, int defStyleAttr) {

          super(context, attrs, defStyleAttr);

          init();

          }

          private void init(){

          mPaint = new Paint();

          mPaint.setAntiAlias(true); //抗鋸齒

          mPaint.setColor(getResources().getColor(R.color.puple));//畫筆顏色

          mPaint.setStyle(Paint.Style.FILL); //畫筆風(fēng)格

          mPaint.setTextSize(36); //繪制文字大小,單位px

          mPaint.setStrokeWidth(5); //畫筆粗細(xì)

          }

          //重寫該方法,在這里繪圖

          @Override

          protected void onDraw(Canvas canvas) {

          super.onDraw(canvas);

          }

          }

          然后布局那里設(shè)置下這個(gè)View就好,下述代碼都寫在onDrawable中~


          1)設(shè)置畫布顏色:

          canvas.drawColor(getResources().getColor(R.color.yellow)); //設(shè)置畫布背景顏色


          2)繪制圓形:

          canvas.drawCircle(200, 200, 100, mPaint); //畫實(shí)心圓


          3)繪制矩形:

          canvas.drawRect(0, 0, 200, 100, mPaint); //畫矩形


          4)繪制Bitmap:

          canvas.drawBitmap(BitmapFactory.decodeResource(getResources(), R.mipmap.ic_launcher), 0, 0, mPaint);


          5)繪制弧形區(qū)域:

          canvas.drawArc(new RectF(0, 0, 100, 100),0,90,true,mPaint); //繪制弧形區(qū)域

          假如true改為false:


          6)繪制圓角矩形

          canvas.drawRoundRect(new RectF(10,10,210,110),15,15,mPaint); //畫圓角矩形


          7)繪制橢圓

          canvas.drawOval(new RectF(0,0,200,300),mPaint); //畫橢圓


          8)繪制多邊形:

          Path path = new Path();

          path.moveTo(10, 10); //移動(dòng)到 坐標(biāo)10,10

          path.lineTo(100, 50);

          path.lineTo(200,40);

          path.lineTo(300, 20);

          path.lineTo(200, 10);

          path.lineTo(100, 70);

          path.lineTo(50, 40);

          path.close();

          canvas.drawPath(path,mPaint);


          9)繪制文字:

          canvas.drawText("最喜歡看曹神日狗了~",50,50,mPaint); //繪制文字

          你也可以沿著某條Path來繪制這些文字:

          Path path = new Path();

          path.moveTo(50,50);

          path.lineTo(100, 100);

          path.lineTo(200, 200);

          path.lineTo(300, 300);

          path.close();

          canvas.drawTextOnPath("最喜歡看曹神日狗了~", path, 50, 50, mPaint); //繪制文字


          10)繪制自定義的圖形:

          代碼來源于網(wǎng)上:

          protected void onDraw(Canvas canvas) {

          super.onDraw(canvas);

          canvas.translate(canvas.getWidth()/2, 200); //將位置移動(dòng)畫紙的坐標(biāo)點(diǎn):150,150

          canvas.drawCircle(0, 0, 100, mPaint); //畫圓圈

          //使用path繪制路徑文字

          canvas.save();

          canvas.translate(-75, -75);

          Path path = new Path();

          path.addArc(new RectF(0,0,150,150), -180, 180);

          Paint citePaint = new Paint(mPaint);

          citePaint.setTextSize(14);

          citePaint.setStrokeWidth(1);

          canvas.drawTextOnPath("繪制表盤~", path, 28, 0, citePaint);

          canvas.restore();

          Paint tmpPaint = new Paint(mPaint); //小刻度畫筆對(duì)象

          tmpPaint.setStrokeWidth(1);

          float y=100;

          int count = 60; //總刻度數(shù)

          for(int i=0 ; i <count ; i++){

          if(i%5 == 0){

          canvas.drawLine(0f, y, 0, y+12f, mPaint);

          canvas.drawText(String.valueOf(i/5+1), -4f, y+25f, tmpPaint);

          }else{

          canvas.drawLine(0f, y, 0f, y +5f, tmpPaint);

          }

          canvas.rotate(360/count,0f,0f); //旋轉(zhuǎn)畫紙

          }

          //繪制指針

          tmpPaint.setColor(Color.GRAY);

          tmpPaint.setStrokeWidth(4);

          canvas.drawCircle(0, 0, 7, tmpPaint);

          tmpPaint.setStyle(Paint.Style.FILL);

          tmpPaint.setColor(Color.YELLOW);

          canvas.drawCircle(0, 0, 5, tmpPaint);

          canvas.drawLine(0, 10, 0, -65, mPaint);

          }


          本節(jié)小結(jié):

          本節(jié)我們對(duì)android.graphics接口類下的三個(gè)繪圖API:Canvas(畫布),Paint(畫筆),Path(路徑)進(jìn)行 了學(xué)習(xí),方法有很多,別去死記,用到的時(shí)候查就好,這里我們先有個(gè)大概映像即可,自定義控件那里 我們?cè)賮砺m結(jié)~好的,就說這么多

          UI組件化對(duì)項(xiàng)目有正向收益,不僅能提效,還能保證高度的視覺還原度,減少和UI設(shè)計(jì)師溝通成本,所以也得到了大家的認(rèn)可。

          所以每個(gè)項(xiàng)目都會(huì)啟動(dòng)UI組件化建設(shè),但是UI視圖是和項(xiàng)目強(qiáng)相關(guān)的,項(xiàng)目間無法復(fù)用,導(dǎo)致大家疲于實(shí)現(xiàn),重復(fù)造輪子,拖延下班時(shí)間,那么基于上面的背景,有沒有更好的解決方案呢,答案是有的,下面介紹一下UI組件化在項(xiàng)目中的實(shí)施經(jīng)驗(yàn),下面分為目標(biāo)、工程架構(gòu)、組件架構(gòu)、組件實(shí)現(xiàn)來展開。

          目標(biāo)

          對(duì)現(xiàn)有UI組件化進(jìn)行容器化抽象,底層UI組件提供最大功能集合,完全解耦業(yè)務(wù)邏輯,業(yè)務(wù)方根據(jù)自己需求,基于基礎(chǔ)組件開發(fā),通過屬性配置或者組合的方式達(dá)到復(fù)雜的效果,所以只要底層組件抽象的足夠好、能力足夠全,就能大大的提高開發(fā)效率,后期適配也不會(huì)涉及核心邏輯修改,一定程度的保證了功能的穩(wěn)定性

          工程架構(gòu)

          module劃分

          所有的ui組件統(tǒng)一收斂到uikit下,其下面moudle劃分以是否非常通用為依據(jù),如果非業(yè)務(wù)屬性,并且特別通用的模塊組件,抽取單獨(dú)module,方便解耦和復(fù)用,如果不是則統(tǒng)一放在同一個(gè)module下,這樣uikit模塊劃分如下:

          • app

          空殼工程,可以單獨(dú)運(yùn)行

          • demo

          對(duì)所有的組件提供demo,里面的功能也可以在調(diào)試面板中打開

          • uikit

          依賴widget和module,業(yè)務(wù)使用ui組件直接依賴uikit即可

          • widgetDivideLine
          • XRadioGroup
          • LoadingView
          • ShimmerLayout
          • ...
          • uikit-moduleflatButton
          • roundView
          • load
          • dialog
          • imageSelect
          • toast
          • ...

          工程分層

          工程架構(gòu)可以分為5層,分別是:基礎(chǔ)控件、組合控件、業(yè)務(wù)UI組件、橋接、demo。

          • 基礎(chǔ)控件:提供原子能力,單點(diǎn)控件,比如層疊布局FlowLayout、骨架控件ShimmerLayout、按鈕Flatbutton
          • 組合控件:會(huì)依賴基礎(chǔ)控件,比如Dialog、ImageSelector,這些控件UI會(huì)比較復(fù)雜,所以會(huì)用到FlatButton、ShimmerLayout等基礎(chǔ)組件來提高開發(fā)效率
          • 業(yè)務(wù)UI組件:這個(gè)就是我們真正要實(shí)現(xiàn)的UI組件,基于設(shè)計(jì)要求定制開發(fā),在基礎(chǔ)控件和組合控件上配置業(yè)務(wù)偏好,組合成業(yè)務(wù)組件,開發(fā)工作量比較小
          • 橋接:業(yè)務(wù)層不感知UI組件的個(gè)數(shù)和依賴關(guān)系,業(yè)務(wù)層只依賴uikit,而UI組件的依賴管理收斂到uikit中,這樣的好處就是,后續(xù)迭代只在uikit維護(hù)依賴關(guān)系即可
          • Demo: 一個(gè)好的組件除了使用文檔,還需要有直觀的示例代碼,demo可以直接集成到調(diào)試面板中

          架構(gòu)分層如下圖:

          一個(gè)好的架構(gòu)應(yīng)該層次分明、低耦合、高擴(kuò)展,對(duì)組件的增刪支持的足夠友好,任何組件都能準(zhǔn)確的找到對(duì)應(yīng)的分層,并且不會(huì)改動(dòng)到已有代碼,所以review一下剛剛設(shè)計(jì)的架構(gòu),基本上滿足需求,架構(gòu)設(shè)計(jì)符合預(yù)期。

          架構(gòu)設(shè)計(jì)好之后的步驟就是實(shí)施了,如何和現(xiàn)有的工程做結(jié)合呢,UI組件按階段可以分為:開發(fā)階段、穩(wěn)定階段,理想的開發(fā)模式為開發(fā)階段在宿主工程中開發(fā)調(diào)試,但是放宿主工程中會(huì)帶了編譯慢的問題,組件開發(fā)和業(yè)務(wù)是接耦的,所以希望代碼在宿主工程,demo和組件開發(fā)可以單獨(dú)運(yùn)行,當(dāng)組件開發(fā)完成,到了穩(wěn)定階段,組件代碼修改頻率降低,同時(shí)加快編譯速度,UIKit組件發(fā)布到遠(yuǎn)程maven倉(cāng)庫(kù),最終uikit工程獨(dú)立出來,單獨(dú)迭代,下面是工程架構(gòu)實(shí)現(xiàn)

          UI組件和宿主打包編譯

          settings.gradle

          includeIfAbsent ':uikit:uikit'
          includeIfAbsent ':uikit:demo'
          includeIfAbsent ':uikit:imgselector'
          includeIfAbsent ':uikit:roundview'
          includeIfAbsent ':uikit:widget'
          includeIfAbsent ':uikit:photodraweeview'
          includeIfAbsent ':uikit:flatbutton'
          includeIfAbsent ':uikit:dialog'
          includeIfAbsent ':uikit:widgetlayout'
          includeIfAbsent ':uikit:statusbar'
          includeIfAbsent ':uikit:toolbar'
          復(fù)制代碼
          

          common_business.gradle中一鍵依賴

          apply from: rootProject.file("library_base.gradle")
          
          dependencies {
              ...
              implementation project(":uikit:uikit")
          }
          復(fù)制代碼
          

          UI組件獨(dú)立編譯

          uikit/shell/settings.gradle

          include ':app'
          includeModule('widget','../')
          includeModule('demo','../')
          includeModule('flatbutton','../')
          includeModule('imgselector','../')
          includeModule('photodraweeview','../')
          includeModule('roundview','../')
          includeModule('uikit','../')
          includeModule('widgetlayout','../')
          includeModule('dialog','../')
          includeModule('statusbar','../')
          includeModule('toolbar','../')
          
          def includeModule(name, filePath = name) {
              def projectDir = new File(filePath+name)
              if (projectDir.exists()) {
                  include ':uikit:' + name
                  project(':uikit:' + name).projectDir = projectDir
              } else {
                  print("settings:could not find module $name in path $filePath")
              }
          }
          復(fù)制代碼
          

          UI組件lib的build.gradle中

          if (rootProject.ext.is_in_uikit_project) {
              apply from: rootProject.file('../uikit.gradle')
          } else {
              apply from: rootProject.file('uikit/uikit.gradle')
          }
          復(fù)制代碼
          

          這樣就實(shí)現(xiàn)了宿主工程UIKit代碼單獨(dú)運(yùn)行的效果了

          組件架構(gòu)

          組件可以分為2類:工具型、業(yè)務(wù)類型,2個(gè)類型的組件迭代思路差異非常的大,工具型組件,只要單點(diǎn)做到極致就ok了,整體比較簡(jiǎn)單,復(fù)用性也比較強(qiáng),而業(yè)務(wù)型組件就會(huì)稍顯復(fù)雜,既要考慮復(fù)用性,也要考慮可擴(kuò)展性,下面分別介紹這2個(gè)類型組件的實(shí)現(xiàn)思路

          工具型

          工具型組件迭代的思路就是不斷的完善基礎(chǔ)能力,盡可能的功能全面,在已有的能力上不斷的支持新的功能,比較重要的就是兼容已有api,比較代表性的組件有FlatButton、RoundView、StatusBar,可以參考下FlatButton&RoundView迭代歷程:

          業(yè)務(wù)型

          如何做好一個(gè)業(yè)務(wù)組件呢,實(shí)現(xiàn)可以是具象的,也可以是抽象的,好的組件設(shè)計(jì)應(yīng)該是2者兼?zhèn)?,最底層的?shí)現(xiàn)應(yīng)該是足夠抽象,而上層實(shí)現(xiàn)又應(yīng)該是具象的,所以需要帶著容器化的思路來實(shí)現(xiàn),那么怎么個(gè)思路呢,如下圖:

          組件實(shí)現(xiàn)

          下面以FlatButton為例介紹組件實(shí)現(xiàn)方式,其它組件實(shí)現(xiàn)思路類似。在實(shí)現(xiàn)前,我們先看下視覺稿

          按鈕樣式特別多,實(shí)現(xiàn)方式也可以有很多種,現(xiàn)有工程也給出了實(shí)現(xiàn)方案,具體如下:

          第一步:分別定義noraml下的shape和pressed的shape,如果enable = false,還得再定義一個(gè)dissable的shape

          normal (ui_standard_bg_btn_corner_28_ripple)

          <?xml version="1.0" encoding="utf-8"?>
          <ripple xmlns:android="http://schemas.android.com/apk/res/android"
              android:color="@color/button_pressed_cover">
              <item
                  android:drawable="@drawable/ui_standard_bg_btn_corner_28_enable">
              </item>
          
          </ripple>
          復(fù)制代碼
          

          pressed(ui_standard_bg_btn_corner_28_disable)

          <?xml version="1.0" encoding="utf-8"?>
          <shape xmlns:android="http://schemas.android.com/apk/res/android"
              android:shape="rectangle">
              <gradient
                  android:angle="0"
                  android:endColor="@color/button_disable_end"
                  android:startColor="@color/button_disable_start"
                  android:useLevel="false"
                  android:type="linear" />
              <corners android:radius="28dp" />
          </shape>
          復(fù)制代碼
          

          第二步:定義selector

          selector(ui_standard_bg_btn_corner_28)

          <?xml version="1.0" encoding="utf-8"?>
          <selector xmlns:android="http://schemas.android.com/apk/res/android">
              <item android:state_enabled="true" android:drawable="@drawable/ui_standard_bg_btn_corner_28_ripple" />
              <item android:state_enabled="false" android:drawable="@drawable/ui_standard_bg_btn_corner_28_disable" />
          </selector>
          復(fù)制代碼
          

          第三步:使用

          <TextView
              ...
              android:background="@drawable/ui_standard_bg_btn_corner_28"
              android:textColor="@color/white"/>
          復(fù)制代碼
          

          這樣按鈕的背景按壓就實(shí)現(xiàn)了,如果在此基礎(chǔ)上,文字也需要按壓態(tài),那么就重復(fù)上面的步驟,對(duì)顏色再創(chuàng)建一個(gè)選擇器,當(dāng)實(shí)現(xiàn)完上面UI定義的樣式后,工程中的畫風(fēng)如下:

          我是誰,我在哪里,這該怎么玩,長(zhǎng)得都差不多,基本沒有開發(fā)體驗(yàn),復(fù)用性、擴(kuò)展性都非常的差,如果來個(gè)UI大改版,又得從頭再來一次。那怎么解決上面的問題呢,答案是定義按鈕通用能力,業(yè)務(wù)上層再實(shí)現(xiàn),按這個(gè)思路做,需要?jiǎng)h除上面所有shape、selector,然后自定義控件,我們都知道,上面定義的shape、selector xml文件,android系統(tǒng)最終都是會(huì)解析生成對(duì)應(yīng)的對(duì)象,所以我們借鑒一下系統(tǒng)代碼,實(shí)現(xiàn)起來就so easy

          看下這個(gè)shape xml

          <shape xmlns:android="http://schemas.android.com/apk/res/android"
              android:shape="rectangle">
              <gradient
                  android:angle="0"
                  android:endColor="@color/button_disable_end"
                  android:startColor="@color/button_disable_start"
                  android:useLevel="false"
                  android:type="linear" />
              <corners android:radius="28dp" />
          </shape>
          復(fù)制代碼
          

          解析后的對(duì)象為GradientDrawable

          public void setOrientation(Orientation orientation)
          public void setColors(@Nullable @ColorInt int[] colors)
          public void setCornerRadii(@Nullable float[] radii)
          public void setStroke(int width, @ColorInt int color)
          ...
          復(fù)制代碼
          

          也就是說,xml中定義的屬性,代碼中都可以實(shí)現(xiàn),除了GradientDrawable,還會(huì)用到RippleDrawable實(shí)現(xiàn)水波紋,同理文字顏色選擇器代碼中對(duì)應(yīng)的為ColorStateList,有了上面鋪墊,具體實(shí)現(xiàn)如下:

          第一步:定義自定義屬性

          <declare-styleable name="FlatButton">
              <!--默認(rèn)背景顏色 -->
              <attr name="fb_colorNormal" format="color" />
              <!--按下背景顏色 -->
              <attr name="fb_colorPressed" format="color" />
              <!--Disable背景顏色 -->
              <attr name="fb_colorDisable" format="color" />
              <!--默認(rèn)開始漸變顏色 -->
              <attr name="fb_colorNormalStart" format="color" />
              <!--默認(rèn)結(jié)束漸變顏色 -->
              <attr name="fb_colorNormalEnd" format="color" />
              <!--按下開始漸變顏色 -->
              <attr name="fb_colorPressedStart" format="color" />
              <!--按下結(jié)束漸變顏色 -->
              <attr name="fb_colorPressedEnd" format="color" />
              <!--Disable開始漸變顏色 -->
              <attr name="fb_colorDisableStart" format="color" />
              <!--Disable結(jié)束漸變顏色 -->
              <attr name="fb_colorDisableEnd" format="color" />
              <!--漸變方向 -->
              <attr name="fb_gradientOrientation">
                  <enum name="left_right" value="0" />
                  <enum name="right_left" value="1" />
                  <enum name="top_bottom" value="2" />
                  <enum name="bottom_top" value="3" />
                  <enum name="tr_bl" value="4" />
                  <enum name="bl_tr" value="5" />
                  <enum name="br_tl" value="6" />
                  <enum name="tl_br" value="7" />
              </attr>
          
              <!--默認(rèn)文字顏色 -->
              <attr name="fb_colorNormalText" format="color" />
              <!--按下文字顏色 -->
              <attr name="fb_colorPressedText" format="color" />
              <!--Disable文字顏色 -->
              <attr name="fb_colorDisableText" format="color" />
          
              <!--邊框顏色 -->
              <attr name="fb_strokeColor" format="color" />
              <!--按下邊框顏色 -->
              <attr name="fb_strokePressColor" format="color" />
              <!--Disable邊框顏色 -->
              <attr name="fb_strokeDisableColor" format="color" />
              <!--邊框?qū)挾?-->
              <attr name="fb_strokeWidth" format="dimension" />
          
              <!--水波紋是否可用 -->
              <attr name="fb_isRippleEnable" format="boolean" />
              <!--默認(rèn)水波紋顏色 -->
              <attr name="fb_colorRippleNormal" format="color" />
              <!--按下水波紋顏色 -->
              <attr name="fb_colorRipplePressed" format="color" />
          
              <!--圓角角度 -->
              <attr name="fb_cornerRadius" format="dimension" />
              <!--左上圓角角度 -->
              <attr name="fb_radius_TL" format="dimension" />
              <!--右上圓角角度 -->
              <attr name="fb_radius_TR" format="dimension" />
              <!--左下圓角角度 -->
              <attr name="fb_radius_BL" format="dimension" />
              <!--右下圓角角度 -->
              <attr name="fb_radius_BR" format="dimension" />
          
              <!--是否開啟防抖 -->
              <attr name="fb_antiShakeEnable" format="boolean" />
          </declare-styleable>
          復(fù)制代碼
          

          第二步:核心實(shí)現(xiàn)邏輯

          private fun setBackgroundCompat() {
              val stateListDrawable = createStateListDrawable()
              val pL = paddingLeft
              val pT = paddingTop
              val pR = paddingRight
              val pB = paddingBottom
              background = if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.LOLLIPOP && isRippleEnable) {
                  val rippleDrawable = RippleDrawable(createRippleColorStateList(), stateListDrawable, null)
                  rippleDrawable
              } else {
                  stateListDrawable
              }
              setPadding(pL, pT, pR, pB)
          }
          
          private fun createStateListDrawable(): StateListDrawable {
              var normalDrawable = StateListDrawable()
              normalDrawable.addState(
                      intArrayOf(android.R.attr.state_pressed),
                      createPressedDrawable()
              )
              normalDrawable.addState(
                      intArrayOf(android.R.attr.state_focused),
                      createPressedDrawable()
              )
              normalDrawable.addState(
                      intArrayOf(-android.R.attr.state_enabled),
                      createDisableDrawable()
              )
              normalDrawable.addState(
                      intArrayOf(android.R.attr.state_selected),
                      createPressedDrawable()
              )
              normalDrawable.addState(intArrayOf(), createNormalDrawable())
              return normalDrawable
          }
          
          private fun createRippleColorStateList(): ColorStateList {
              val stateList = arrayOf(intArrayOf(android.R.attr.state_pressed), intArrayOf(android.R.attr.state_focused), intArrayOf(android.R.attr.state_activated), intArrayOf())
              val normalColor = backgroundStyle.getColorRippleNormalFallback()
              val pressedColor = backgroundStyle.getColorRipplePressedFallback()
              val stateColorList = intArrayOf(
                      pressedColor,
                      pressedColor,
                      pressedColor,
                      normalColor
              )
              return ColorStateList(stateList, stateColorList)
          }
          復(fù)制代碼
          

          第三步:UI組件實(shí)現(xiàn)

          xml中使用

          <com.snapsolve.uikit.flatbutton.FlatButton
              app:fb_colorNormalText="@color/uikit_color_white"
              app:fb_colorPressedText="@color/uikit_color_white"
              app:fb_colorNormalEnd="#FF9800"
              app:fb_colorNormalStart="#FF0000"
              app:fb_colorPressedEnd="#4CAF50"
              app:fb_colorPressedStart="#009688"
              app:fb_colorRippleNormal="#303F9F"
              app:fb_colorRipplePressed="#FF4081"
              app:fb_cornerRadius="24dp"
              app:fb_gradientOrientation="left_right"
              app:fb_isRippleEnable="true" 
              ...
              />
          復(fù)制代碼
          

          代碼中使用

          fb_radius_in_code.setBackgroundStyle {
              this.colorNormal = resources.getColor(R.color.uikit_color_FF4081)
              this.colorPressed = resources.getColor(R.color.uikit_color_9C27B0)
              this.colorRippleNormal = resources.getColor(R.color.uikit_color_FF4081)
              this.colorRipplePressed = resources.getColor(R.color.uikit_color_9C27B0)
          }.setRadiusStyle {
              this.radiusTL = dp2px(24F)
              this.radius_BR = dp2px(24F)
          }
          復(fù)制代碼
          

          到這里,底層Button能力定義完成,接下來就是組件化實(shí)現(xiàn)了,具體實(shí)現(xiàn)方式如下:

          無法復(fù)制加載中的內(nèi)容

          項(xiàng)目中的按鈕UI按照UI組件要求,可以基于FlatButton來實(shí)現(xiàn),配置好給種類型的屬性,按鈕名字可以和設(shè)計(jì)對(duì)齊,到這里就基本完成了

          第四步:業(yè)務(wù)使用

          一級(jí)按鈕、二級(jí)按鈕、三級(jí)按鈕的實(shí)現(xiàn)可以通過繼承FlatButton,設(shè)置默認(rèn)樣式,使用的時(shí)候就不需要再在xml中定義任何屬性,只需記住組件名字,依賴即可,做到真正的開箱即用

          舉一個(gè)例子,定義一個(gè)線框button

          class StrokeButton : FlatButton {
              constructor(context: Context) : this(context, null)
              constructor(context: Context, attrs: AttributeSet?) : this(context, attrs, 0)
              constructor(context: Context, attrs: AttributeSet?, defStyleAttr: Int) : super(context, attrs, defStyleAttr) {
                  config(context, attrs)
              }
          
              private fun config(context: Context, attrs: AttributeSet?){
                  .setBackgroundStyle {
                      this.colorNormal = resources.getColor(R.color.uikit_color_FF4081)
                      this.colorPressed = resources.getColor(R.color.uikit_color_9C27B0)
                      this.colorRippleNormal = resources.getColor(R.color.uikit_color_FF4081)
                      this.colorRipplePressed = resources.getColor(R.color.uikit_color_9C27B0)
                  }.setRadiusStyle {
                      this.radiusTL = dp2px(28F)
                      this.radius_BR = dp2px(28F)
                  }
              }
              private fun dp2px(dp: Float): Float {
                  return TypedValue.applyDimension(TypedValue.COMPLEX_UNIT_DIP, dp, resources.displayMetrics)
              }
          }
          復(fù)制代碼
          

          業(yè)務(wù)使用

          .相關(guān)方法詳解


          1)Paint(畫筆):

          就是畫筆,用于設(shè)置繪制風(fēng)格,如:線寬(筆觸粗細(xì)),顏色,透明度和填充風(fēng)格等 直接使用無參構(gòu)造方法就可以創(chuàng)建Paint實(shí)例: Paint paint = new Paint( );

          我們可以通過下述方法來設(shè)置Paint(畫筆)的相關(guān)屬性,另外,關(guān)于這個(gè)屬性有兩種, 圖形繪制相關(guān)與文本繪制相關(guān):

          • setARGB(int a,int r,int g,int b): 設(shè)置繪制的顏色,a代表透明度,r,g,b代表顏色值。
          • setAlpha(int a): 設(shè)置繪制圖形的透明度。
          • setColor(int color): 設(shè)置繪制的顏色,使用顏色值來表示,該顏色值包括透明度和RGB顏色。
          • setAntiAlias(boolean aa): 設(shè)置是否使用抗鋸齒功能,會(huì)消耗較大資源,繪制圖形速度會(huì)變慢。
          • setDither(boolean dither): 設(shè)定是否使用圖像抖動(dòng)處理,會(huì)使繪制出來的圖片顏色更加平滑和飽滿,圖像更加清晰
          • setFilterBitmap(boolean filter): 如果該項(xiàng)設(shè)置為true,則圖像在動(dòng)畫進(jìn)行中會(huì)濾掉對(duì)Bitmap圖像的優(yōu)化操作, 加快顯示速度,本設(shè)置項(xiàng)依賴于dither和xfermode的設(shè)置
          • setMaskFilter(MaskFilter maskfilter): 設(shè)置MaskFilter,可以用不同的MaskFilter實(shí)現(xiàn)濾鏡的效果,如濾化,立體等
          • setColorFilter(ColorFilter colorfilter): 設(shè)置顏色過濾器,可以在繪制顏色時(shí)實(shí)現(xiàn)不用顏色的變換效果
          • setPathEffect(PathEffect effect) 設(shè)置繪制路徑的效果,如點(diǎn)畫線等
          • setShader(Shader shader): 設(shè)置圖像效果,使用Shader可以繪制出各種漸變效果
          • setShadowLayer(float radius ,float dx,float dy,int color):在圖形下面設(shè)置陰影層,產(chǎn)生陰影效果, radius為陰影的角度,dx和dy為陰影在x軸和y軸上的距離,color為陰影的顏色
          • setStyle(Paint.Style style): 設(shè)置畫筆的樣式,為FILL,F(xiàn)ILL_OR_STROKE,或STROKE
          • setStrokeCap(Paint.Cap cap): 當(dāng)畫筆樣式為STROKE或FILL_OR_STROKE時(shí),設(shè)置筆刷的圖形樣式, 如圓形樣Cap.ROUND,或方形樣式Cap.SQUARE
          • setSrokeJoin(Paint.Join join): 設(shè)置繪制時(shí)各圖形的結(jié)合方式,如平滑效果等
          • setStrokeWidth(float width): 當(dāng)畫筆樣式為STROKE或FILL_OR_STROKE時(shí),設(shè)置筆刷的粗細(xì)度
          • setXfermode(Xfermode xfermode): 設(shè)置圖形重疊時(shí)的處理方式,如合并,取交集或并集,經(jīng)常用來制作橡皮的擦除效果
          • setFakeBoldText(boolean fakeBoldText): 模擬實(shí)現(xiàn)粗體文字,設(shè)置在小字體上效果會(huì)非常差
          • setSubpixelText(boolean subpixelText): 設(shè)置該項(xiàng)為true,將有助于文本在LCD屏幕上的顯示效果
          • setTextAlign(Paint.Align align): 設(shè)置繪制文字的對(duì)齊方向
          • setTextScaleX(float scaleX): 設(shè)置繪制文字x軸的縮放比例,可以實(shí)現(xiàn)文字的拉伸的效果
          • setTextSize(float textSize): 設(shè)置繪制文字的字號(hào)大小
          • setTextSkewX(float skewX): 設(shè)置斜體文字,skewX為傾斜弧度
          • setTypeface(Typeface typeface): 設(shè)置Typeface對(duì)象,即字體風(fēng)格,包括粗體,斜體以及襯線體,非襯線體等
          • setUnderlineText(boolean underlineText): 設(shè)置帶有下劃線的文字效果
          • setStrikeThruText(boolean strikeThruText): 設(shè)置帶有刪除線的效果
          • setStrokeJoin(Paint.Join join): 設(shè)置結(jié)合處的樣子,Miter:結(jié)合處為銳角, Round:結(jié)合處為圓?。築EVEL:結(jié)合處為直線
          • setStrokeMiter(float miter):設(shè)置畫筆傾斜度
          • setStrokeCap (Paint.Cap cap):設(shè)置轉(zhuǎn)彎處的風(fēng)格 其他常用方法:
          • float ascent( ):測(cè)量baseline之上至字符最高處的距離


          • float descent():baseline之下至字符最低處的距離
          • int breakText(char[] text, int index, int count, float maxWidth, float[] measuredWidth): 檢測(cè)一行顯示多少文字
          • clearShadowLayer( ):清除陰影層 其他的自行查閱文檔~

          2)Canvas(畫布):

          畫筆有了,接著就到畫布(Canvas),總不能憑空作畫是吧~常用方法如下:

          首先是構(gòu)造方法,Canvas的構(gòu)造方法有兩種:

          Canvas(): 創(chuàng)建一個(gè)空的畫布,可以使用setBitmap()方法來設(shè)置繪制具體的畫布。

          Canvas(Bitmap bitmap): 以bitmap對(duì)象創(chuàng)建一個(gè)畫布,將內(nèi)容都繪制在bitmap上,因此bitmap不得為null。

          接著是 1.drawXXX()方法族:以一定的坐標(biāo)值在當(dāng)前畫圖區(qū)域畫圖,另外圖層會(huì)疊加, 即后面繪畫的圖層會(huì)覆蓋前面繪畫的圖層。 比如:

          • drawRect(RectF rect, Paint paint) :繪制區(qū)域,參數(shù)一為RectF一個(gè)區(qū)域
          • drawPath(Path path, Paint paint) :繪制一個(gè)路徑,參數(shù)一為Path路徑對(duì)象
          • drawBitmap(Bitmap bitmap, Rect src, Rect dst, Paint paint) : 貼圖,參數(shù)一就是我們常規(guī)的Bitmap對(duì)象,參數(shù)二是源區(qū)域(這里是bitmap), 參數(shù)三是目標(biāo)區(qū)域(應(yīng)該在canvas的位置和大小),參數(shù)四是Paint畫刷對(duì)象, 因?yàn)橛玫搅丝s放和拉伸的可能,當(dāng)原始Rect不等于目標(biāo)Rect時(shí)性能將會(huì)有大幅損失。
          • drawLine(float startX, float startY, float stopX, float stopY, Paintpaint) : 畫線,參數(shù)一起始點(diǎn)的x軸位置,參數(shù)二起始點(diǎn)的y軸位置,參數(shù)三終點(diǎn)的x軸水平位置, 參數(shù)四y軸垂直位置,最后一個(gè)參數(shù)為Paint 畫刷對(duì)象。
          • drawPoint(float x, float y, Paint paint): 畫點(diǎn),參數(shù)一水平x軸,參數(shù)二垂直y軸,第三個(gè)參數(shù)為Paint對(duì)象。
          • drawText(String text, float x, floaty, Paint paint) : 渲染文本,Canvas類除了上面的還可以描繪文字,參數(shù)一是String類型的文本, 參數(shù)二x軸,參數(shù)三y軸,參數(shù)四是Paint對(duì)象。
          • drawOval(RectF oval, Paint paint):畫橢圓,參數(shù)一是掃描區(qū)域,參數(shù)二為paint對(duì)象;
          • drawCircle(float cx, float cy, float radius,Paint paint): 繪制圓,參數(shù)一是中心點(diǎn)的x軸,參數(shù)二是中心點(diǎn)的y軸,參數(shù)三是半徑,參數(shù)四是paint對(duì)象;
          • drawArc(RectF oval, float startAngle, float sweepAngle, boolean useCenter, Paint paint): 畫弧,參數(shù)一是RectF對(duì)象,一個(gè)矩形區(qū)域橢圓形的界限用于定義在形狀、大小、電弧,參數(shù)二是起始角 (度)在電弧的開始,參數(shù)三掃描角(度)開始順時(shí)針測(cè)量的,參數(shù)四是如果這是真的話,包括橢圓中心的電 弧,并關(guān)閉它,如果它是假這將是一個(gè)弧線,參數(shù)五是Paint對(duì)象;

          2.clipXXX()方法族:在當(dāng)前的畫圖區(qū)域裁剪(clip)出一個(gè)新的畫圖區(qū)域,這個(gè)畫圖區(qū)域就是canvas 對(duì)象的當(dāng)前畫圖區(qū)域了。比如:clipRect(new Rect()),那么該矩形區(qū)域就是canvas的當(dāng)前畫圖區(qū)域

          3.save()restore()方法: save( ):用來保存Canvas的狀態(tài)。save之后,可以調(diào)用Canvas的平移、放縮、旋轉(zhuǎn)、錯(cuò)切、裁剪等操作! restore():用來恢復(fù)Canvas之前保存的狀態(tài)。防止save后對(duì)Canvas執(zhí)行的操作對(duì)后續(xù)的繪制有影響。 save()和restore()要配對(duì)使用(restore可以比save少,但不能多),若restore調(diào)用次數(shù)比save多,會(huì)報(bào)錯(cuò)!

          4.translate(float dx, float dy): 平移,將畫布的坐標(biāo)原點(diǎn)向左右方向移動(dòng)x,向上下方向移動(dòng)y.canvas的默認(rèn)位置是在(0,0)

          5.scale(float sx, float sy):擴(kuò)大,x為水平方向的放大倍數(shù),y為豎直方向的放大倍數(shù)

          6.rotate(float degrees):旋轉(zhuǎn),angle指旋轉(zhuǎn)的角度,順時(shí)針旋轉(zhuǎn)


          3)Path(路徑)

          簡(jiǎn)單點(diǎn)說就是描點(diǎn),連線~在創(chuàng)建好我們的Path路徑后,可以調(diào)用Canvas的drawPath(path,paint) 將圖形繪制出來~常用方法如下:

          • addArc(RectF oval, float startAngle, float sweepAngle:為路徑添加一個(gè)多邊形
          • addCircle(float x, float y, float radius, Path.Direction dir):給path添加圓圈
          • addOval(RectF oval, Path.Direction dir):添加橢圓形
          • addRect(RectF rect, Path.Direction dir):添加一個(gè)區(qū)域
          • addRoundRect(RectF rect, float[] radii, Path.Direction dir):添加一個(gè)圓角區(qū)域
          • isEmpty():判斷路徑是否為空
          • transform(Matrix matrix):應(yīng)用矩陣變換
          • transform(Matrix matrix, Path dst):應(yīng)用矩陣變換并將結(jié)果放到新的路徑中,即第二個(gè)參數(shù)。

          更高級(jí)的效果可以使用PathEffect類!

          幾個(gè)To:

          • moveTo(float x, float y):不會(huì)進(jìn)行繪制,只用于移動(dòng)移動(dòng)畫筆
          • lineTo(float x, float y):用于直線繪制,默認(rèn)從(0,0)開始繪制,用moveTo移動(dòng)! 比如 mPath.lineTo(300, 300); canvas.drawPath(mPath, mPaint);
          • quadTo(float x1, float y1, float x2, float y2): 用于繪制圓滑曲線,即貝塞爾曲線,同樣可以結(jié)合moveTo使用!


          • rCubicTo(float x1, float y1, float x2, float y2, float x3, float y3) 同樣是用來實(shí)現(xiàn)貝塞爾曲線的。 (x1,y1) 為控制點(diǎn),(x2,y2)為控制點(diǎn),(x3,y3) 為結(jié)束點(diǎn)。 Same as cubicTo, but the coordinates are considered relative to the current point on this contour.就是多一個(gè)控制點(diǎn)而已~ 繪制上述的曲線: mPath.moveTo(100, 500); mPath.cubicTo(100, 500, 300, 100, 600, 500); 如果不加上面的那個(gè)moveTo的話:則以(0,0)為起點(diǎn),(100,500)和(300,100)為控制點(diǎn)繪制貝塞爾曲線


          • arcTo(RectF oval, float startAngle, float sweepAngle): 繪制弧線(實(shí)際是截取圓或橢圓的一部分)ovalRectF為橢圓的矩形,startAngle 為開始角度, sweepAngle 為結(jié)束角度。

          2.動(dòng)手試試:

          屬性那么多,肯定要手把手的擼一下,才能加深我們的映像是吧~ 嘿嘿,畫圖要么在View上畫,要么在SurfaceView上畫,這里我們?cè)赩iew上畫吧, 我們定義一個(gè)View類,然后再onDraw()里完成繪制工作!

          /**

          * Created by Jay on 2015/10/15 0015.

          */

          public class MyView extends View{

          private Paint mPaint;

          public MyView(Context context) {

          super(context);

          init();

          }

          public MyView(Context context, AttributeSet attrs) {

          super(context, attrs);

          init();

          }

          public MyView(Context context, AttributeSet attrs, int defStyleAttr) {

          super(context, attrs, defStyleAttr);

          init();

          }

          private void init(){

          mPaint = new Paint();

          mPaint.setAntiAlias(true); //抗鋸齒

          mPaint.setColor(getResources().getColor(R.color.puple));//畫筆顏色

          mPaint.setStyle(Paint.Style.FILL); //畫筆風(fēng)格

          mPaint.setTextSize(36); //繪制文字大小,單位px

          mPaint.setStrokeWidth(5); //畫筆粗細(xì)

          }

          //重寫該方法,在這里繪圖

          @Override

          protected void onDraw(Canvas canvas) {

          super.onDraw(canvas);

          }

          }

          然后布局那里設(shè)置下這個(gè)View就好,下述代碼都寫在onDrawable中~


          1)設(shè)置畫布顏色:

          canvas.drawColor(getResources().getColor(R.color.yellow)); //設(shè)置畫布背景顏色


          2)繪制圓形:

          canvas.drawCircle(200, 200, 100, mPaint); //畫實(shí)心圓


          3)繪制矩形:

          canvas.drawRect(0, 0, 200, 100, mPaint); //畫矩形


          4)繪制Bitmap:

          canvas.drawBitmap(BitmapFactory.decodeResource(getResources(), R.mipmap.ic_launcher), 0, 0, mPaint);


          5)繪制弧形區(qū)域:

          canvas.drawArc(new RectF(0, 0, 100, 100),0,90,true,mPaint); //繪制弧形區(qū)域

          假如true改為false:


          6)繪制圓角矩形

          canvas.drawRoundRect(new RectF(10,10,210,110),15,15,mPaint); //畫圓角矩形


          7)繪制橢圓

          canvas.drawOval(new RectF(0,0,200,300),mPaint); //畫橢圓


          8)繪制多邊形:

          Path path = new Path();

          path.moveTo(10, 10); //移動(dòng)到 坐標(biāo)10,10

          path.lineTo(100, 50);

          path.lineTo(200,40);

          path.lineTo(300, 20);

          path.lineTo(200, 10);

          path.lineTo(100, 70);

          path.lineTo(50, 40);

          path.close();

          canvas.drawPath(path,mPaint);


          9)繪制文字:

          canvas.drawText("最喜歡看曹神日狗了~",50,50,mPaint); //繪制文字

          你也可以沿著某條Path來繪制這些文字:

          Path path = new Path();

          path.moveTo(50,50);

          path.lineTo(100, 100);

          path.lineTo(200, 200);

          path.lineTo(300, 300);

          path.close();

          canvas.drawTextOnPath("最喜歡看曹神日狗了~", path, 50, 50, mPaint); //繪制文字


          10)繪制自定義的圖形:

          代碼來源于網(wǎng)上:

          protected void onDraw(Canvas canvas) {

          super.onDraw(canvas);

          canvas.translate(canvas.getWidth()/2, 200); //將位置移動(dòng)畫紙的坐標(biāo)點(diǎn):150,150

          canvas.drawCircle(0, 0, 100, mPaint); //畫圓圈

          //使用path繪制路徑文字

          canvas.save();

          canvas.translate(-75, -75);

          Path path = new Path();

          path.addArc(new RectF(0,0,150,150), -180, 180);

          Paint citePaint = new Paint(mPaint);

          citePaint.setTextSize(14);

          citePaint.setStrokeWidth(1);

          canvas.drawTextOnPath("繪制表盤~", path, 28, 0, citePaint);

          canvas.restore();

          Paint tmpPaint = new Paint(mPaint); //小刻度畫筆對(duì)象

          tmpPaint.setStrokeWidth(1);

          float y=100;

          int count = 60; //總刻度數(shù)

          for(int i=0 ; i <count ; i++){

          if(i%5 == 0){

          canvas.drawLine(0f, y, 0, y+12f, mPaint);

          canvas.drawText(String.valueOf(i/5+1), -4f, y+25f, tmpPaint);

          }else{

          canvas.drawLine(0f, y, 0f, y +5f, tmpPaint);

          }

          canvas.rotate(360/count,0f,0f); //旋轉(zhuǎn)畫紙

          }

          //繪制指針

          tmpPaint.setColor(Color.GRAY);

          tmpPaint.setStrokeWidth(4);

          canvas.drawCircle(0, 0, 7, tmpPaint);

          tmpPaint.setStyle(Paint.Style.FILL);

          tmpPaint.setColor(Color.YELLOW);

          canvas.drawCircle(0, 0, 5, tmpPaint);

          canvas.drawLine(0, 10, 0, -65, mPaint);

          }


          本節(jié)小結(jié):

          本節(jié)我們對(duì)android.graphics接口類下的三個(gè)繪圖API:Canvas(畫布),Paint(畫筆),Path(路徑)進(jìn)行 了學(xué)習(xí),方法有很多,別去死記,用到的時(shí)候查就好,這里我們先有個(gè)大概映像即可,自定義控件那里 我們?cè)賮砺m結(jié)~好的,就說這么多


          主站蜘蛛池模板: 精品一区二区三区在线观看| 国精产品一区二区三区糖心| 亚洲AV福利天堂一区二区三| 在线一区二区三区| 色狠狠AV一区二区三区| 国产日韩一区二区三区| 好吊妞视频一区二区| 色噜噜狠狠一区二区三区果冻| 精品性影院一区二区三区内射 | 久久一区二区三区免费播放| 97久久精品无码一区二区| 亚洲男人的天堂一区二区| 国产一区二区不卡老阿姨| 色偷偷av一区二区三区| 中文字幕亚洲一区二区三区| 日本一区二区三区精品国产| 精品一区二区三区在线播放| 日韩精品一区二区三区不卡 | 亚洲一区欧洲一区| 精品无码一区二区三区电影| 亚洲日韩国产欧美一区二区三区| 国精品无码一区二区三区在线| 国产一区二区三区在线观看影院| 78成人精品电影在线播放日韩精品电影一区亚洲 | 无码aⅴ精品一区二区三区浪潮| 亚洲中文字幕丝袜制服一区 | 国产成人AV一区二区三区无码| 日本韩国黄色一区二区三区| 亚洲av高清在线观看一区二区| 亚洲国产成人精品久久久国产成人一区二区三区综 | 日本在线电影一区二区三区 | 天堂资源中文最新版在线一区| 精品一区二区三区高清免费观看| 精品一区二区三区四区电影| 精品人体无码一区二区三区| 色欲AV无码一区二区三区| 中日av乱码一区二区三区乱码| 亚洲狠狠狠一区二区三区| 美女视频一区三区网站在线观看| 国产在线观看一区二区三区四区 | 一本色道久久综合一区|