自定義繪制知識的四個級別
一、Canvas 的 drawXXX() 系列方法及 Paint 最常見的使用
? ? |--簡單圖形的繪制:canvas.drawXXX()及paint的一些常用參數設置
? ? |--自定義圖形繪制Path,它有兩類方法:
? ? ? |--直接描述路徑的
? ? ? ? ? |--添加子圖形 path.addXxx()
? ? ? ? ? |--畫線(直線或曲線)path.xxxTo(), close()或lineto()可圖形封閉蜜宪。特殊的方法:畫弧 arcTo() 和 addArc()
? ? ? |--輔助的設置或計算,其中一種setFillType(FillType fillType)产弹。FillType四中算法
? ? ? ? ? ? |--EVEN_ODD 奇偶原則(無方向要求):奇數难衰,則這個點被認為在圖形內部笆怠;如果是偶數堕虹,則這個點被認為在圖形外部
? ? ? ? ? ? |--WINDING (默認值)非零環(huán)繞數原則(有方向):以 0 初始值岂津,遇到順時針的交點結果加 1虱黄,遇到每個逆時針的交點把結果減 1,得到的結果不是 0吮成,這個點在圖形內部橱乱,為0在外部
? ? ? ? ? ? |--INVERSE_EVEN_ODD
? ? ? ? ? ? |--INVERSE_WINDING
? ? |--繪制圖像canvas.drawBitmap()
? ? |--繪制文字,三種方式
? ? ? ? |--drawText() 給出文字的內容和位置粱甫, Canvas 按要求去繪制文字泳叠,(x,y) 繪制的左下角,y為baseline
? ? ? ? |--drawTextRun()? 外國用
? ? ? ? |--drawTextOnPath() 沿著path繪制茶宵, 使用的 Path 拐彎處全用圓角危纫,別用尖角
? ? ? ? |--自動換行 staticLayout.draw(canvas);
二、paint 的完全攻略
Paint 的 API 大致可以分為 4 類:
? ? |--顏色
? ? ? ? |--基本顏色
? ? ? ? ? ? |--canvas.drawColor()等
? ? ? ? ? ? |--canvas.drawBitmap()
? ? ? ? ? ? |--通過paint設置乌庶,方法有兩種
? ? ? ? ? ? ? ? |--直接用 Paint.setColor/ARGB() 來設置顏色
? ? ? ? ? ? ? ? |--另一種是使用 Shader 來指定著色方案种蝶,paint.setShader()
? ? ? ? ? ? ? ? ? ? |--子類LinearGradient 線性漸變
? ? ? ? ? ? ? ? ? ? |--子類 RadialGradient 輻射漸變
? ? ? ? ? ? ? ? ? ? |--子類 SweepGradient 掃描漸變
? ? ? ? ? ? ? ? ? ? |--子類 BitmapShader 圖像著色
? ? ? ? ? ? ? ? ? ? |--子類ComposeShader 混合著色器,兩著色器疊加模式(PorterDuff.MODE.xxx瞒大,18種)
? ? ? ? |--ColorFilter 通過 paint.setColorFilter()
? ? ? ? ? ? |--LightingColorFilter 模擬簡單的光照效果
? ? ? ? ? ? |--PorterDuffColorFilter 使用一個指定的顏色和一種指定的 PorterDuff.Mode 來與繪制對象進行合成
? ? ? ? ? ? |--ColorMatrixColorFilter 使用一個 ColorMatrix 來對顏色進行處理
? ? ? ? |--Xfermode paint.setXfermode() 其實就是要你以繪制的內容作為源圖像蛤吓,以 View 中已有的內容作為目標圖像,選取一個? PorterDuff.Mode 作為繪制內容的顏色處理方案
? ? ? ? ? ? |--子類PorterDuffXfermode? 注意事項:
? ? ? ? ? ? ? ? |--1.使用離屏緩沖 Canvas.saveLayer()糠赦,繪制完restoreToCount(id)
? ? ? ? ? ? ? ? |--2.控制好透明區(qū)域会傲,必須足夠覆蓋到要和它結合繪制的內容
? ? |--效果 paint效果類的 API ,指的就是抗鋸齒拙泽、填充/輪廓淌山、線條寬度等等這些
? ? ? ? |--paint.setAntiAlias (boolean aa) 設置抗鋸齒
? ? ? ? |--paint.setStyle(Paint.Style style)圖形或線條風格
? ? ? ? |--設置線條形狀,有 4 個方法:
? ? ? ? ? ? |--setStrokeWidth(float width), 寬度
? ? ? ? ? ? |--setStrokeCap(Paint.Cap cap),? 設置線頭的形狀顾瞻。線頭形狀有三種:BUTT 平頭泼疑、ROUND 圓頭、SQUARE 方頭荷荤。默認為 BUTT
? ? ? ? ? ? |--setStrokeJoin(Paint.Join join), 設置拐角的形狀退渗。有三個值可以選擇:MITER 尖角、 BEVEL 平角和 ROUND 圓角蕴纳。默認為 MITER
? ? ? ? ? ? |--setStrokeMiter(float miter) 会油。這個方法是對于 setStrokeJoin() 的一個補充,它用于設置 MITER 型拐角的延長線的最大值古毛。超過角度時翻翩,尖角變平角
? ? ? ? |--色彩優(yōu)化
? ? ? ? ? ? |--paint.setDither(boolean dither)設置圖像的抖動
? ? ? ? ? ? |--paint.setFilterBitmap(boolean filter)設置是否使用雙線性過濾來繪制 Bitmap 都许。
? ? ? ? |--paint.setPathEffect(PathEffect effect) 使用 PathEffect 來給圖形的輪廓設置效果。對 Canvas 所有的圖形繪制有效
? ? ? ? ? ? |--CornerPathEffect 把所有拐角變成圓角
? ? ? ? ? ? |--DiscretePathEffect 把線條進行隨機的偏離嫂冻,讓輪廓變得亂七八糟胶征。
? ? ? ? ? ? |--DashPathEffect 使用虛線來繪制線條
? ? ? ? ? ? |--PathDashPathEffect 這個方法比 DashPathEffect 多一個前綴 Path ,所以顧名思義桨仿,它是使用一個 Path 來繪制「虛線」
? ? ? ? ? ? |--SumPathEffect 組合效果類的 PathEffect ,就是分別按照兩種 PathEffect 分別對目標進行繪制
? ? ? ? ? ? |--ComposePathEffect 組合效果類的 PathEffect ,先對目標 Path 使用一個 PathEffect睛低,然后再對這個改變后的 Path 使用另一個 PathEffect
? ? ? ? |--setShadowLayer() 在之后的繪制內容下面加一層陰影,即繪制層下方的附加效果
? ? ? ? |--setMaskFilter() 整個圖像的過濾,為之后的繪制設置 MaskFilter服傍,設置的是在繪制層上方的附加效果
? ? ? ? ? ? |--BlurMaskFilter 模糊效果的 MaskFilter钱雷,四種參數:NORMAL: 內外都模糊繪制 SOLID: 內部正常繪制,外部模糊 INNER: 內部模糊伴嗡,外部不繪制 OUTER: 內部不繪制急波,外部模糊(什么鬼从铲?)
? ? ? ? ? ? |--EmbossMaskFilter 浮雕效果的 MaskFilter瘪校。
? ? ? ? |--獲取繪制的 Path 根據 paint 的設置,計算出繪制 Path 或文字時的實際 Path
? ? ? ? ? ? |--getFillPath(Path src, Path dst)所謂實際 Path 名段,指的就是 drawPath() 的繪制內容的輪廓阱扬,要算上線條寬度和設置的 PathEffect。若使用默認線條寬度為0時伸辟,兩path相等
? ? ? ? ? ? |--getTextPath 文字的 Path」麻惶。文字的繪制,雖然是使用 Canvas.drawText() 方法信夫,但其實在下層窃蹋,文字信息全是被轉化成圖形,對圖形進行繪制的
? ? |--drawText()相關? Paint 有些設置是文字繪制相關的
? ? ? ? |--效果類
? ? ? ? ? ? |--setTextSize(float textSize) 設置文字大小静稻。
? ? ? ? ? ? |--setTypeface(Typeface typeface)設置字體警没。 paint.setTypeface(Typeface.createFromAsset(getContext().getAssets(), "Satisfy-Regular.ttf"))
? ? ? ? ? ? |--setFakeBoldText(boolean fakeBoldText) 是否使用偽粗體
? ? ? ? ? ? |--setStrikeThruText(boolean strikeThruText) 是否加刪除線
? ? ? ? ? ? |--setUnderlineText(boolean underlineText)是否加下劃線
? ? ? ? ? ? |--setTextSkewX(float skewX) 設置文字橫向錯切角度。其實就是文字傾斜度的啦
? ? ? ? ? ? |--setTextScaleX(float scaleX)設置文字橫向放縮振湾。也就是文字變胖變瘦杀迹。
? ? ? ? ? ? |--setLetterSpacing(float letterSpacing) 設置字符間距。默認值是 0
? ? ? ? ? ? |--setFontFeatureSettings(String settings)用 CSS 的 font-feature-settings 的方式來設置文字押搪。
? ? ? ? ? ? |--setTextAlign(Paint.Align align)設置文字的對齊方式树酪。一共有三個值:LEFT CETNER 和 RIGHT。默認值為 LEFT大州。
? ? ? ? ? ? |--setTextLocale(Locale locale) / setTextLocales(LocaleList locales)設置繪制所使用的 Locale续语。
? ? ? ? ? ? |--Locale 直譯是「地域」,其實就是你在系統里設置的「語言」或「語言區(qū)域」
? ? ? ? ? ? |--setLinearText(boolean linearText)
? ? ? ? |--測量文字尺寸類
? ? ? ? ? ? |--paint.getFontSpacing() 獲取推薦的行距
? ? ? ? ? ? |--paint.getFontMetrics() FontMetrics 是個相對專業(yè)的工具類厦画,它提供了幾個文字排印方面的數值:ascent,? ? descent, top,
? ? ? ? ? ? ? ? bottom,? leading绵载。另外,ascent 和 descent 這兩個值還可以通過 Paint.ascent() 和 Paint.descent() 來快捷獲取。
? ? ? ? ? ? ? ? FontMetrics 和 getFontSpacing()比娃豹,bottom - top + leading 的結果是要大于 getFontSpacing() 的返回值的.
? ? ? ? ? ? ? ? 但getFontSpacing顯示效果更好焚虱,一般使用getFontSpanceing
? ? ? ? ? ? |--paint.getTextBounds(String text, int start, int end, Rect bounds) 獲取文字的顯示范圍,放在bounds里(顯示)
? ? ? ? ? ? |--measureText(String text) 測量文字的寬度并返回(占用)
? ? ? ? ? ? |--getTextWidths(String text, float[] widths)獲取字符串中每個字符的寬度,并把結果填入參數 widths懂版。
? ? ? ? ? ? |--breakText() 這個方法也是用來測量文字寬度的鹃栽。但和 measureText() 的區(qū)別是, breakText() 是在給出寬
? ? ? ? ? ? ? ? 度上限的前提下測量文字的寬度躯畴。如果文字的寬度超出了上限民鼓,那么在臨近超限的位置截斷文字
? ? ? ? |--光標相關 EditText 以及類似的場景,會需要繪制光標蓬抄。API 23 引入了兩個新的方法:getRunAdvance() getOffsetForAdvance()
? ? ? ? |--hasGlyph(String string) 檢查指定的字符串中是否是一個單獨的字形 (glyph)
? ? |--初始化
? ? ? ? |--paint.reset()重置
? ? ? ? |--paint.set(Paint src) 把 src 的所有屬性全部復制過來
? ? ? ? |--setFlags(int flags) 批量設置 flags
---------------------
pathMeasure相關
pathMeasure.getLength() 獲取長度
pathMeasure.getSegment(200, 1000, dst, true);? //截取一部分存入dst中丰嘉,并且使用moveTo保持截取得到的Path第一個點位置不變。
pathMeasure.getPosTan(mLength,pos,tan); //獲取路徑某點的坐標(pos[0], pos[1])和正切值嚷缭,弧度值=atan2(tan[1], tan[0]),可求得角度 =弧度值*180/Math.PI;? ?
-------------------
三饮亏、Canvas 對繪制的輔助——范圍裁切和幾何變換
? ? |--范圍裁切:clipRect() 和 clipPath()。裁切方法之后的繪制代碼阅爽,都會被限制在裁切范圍內路幸。clipPath()時,記得要加上 Canvas.save() 和 Canvas.restore() 來及時恢復繪制范圍
? ? |--幾何變換:有三種
? ? ? ? |--使用 Canvas 來做常見的二維變換付翁;
? ? ? ? ? ? |--Canvas.translate(float dx, float dy) 平移
? ? ? ? ? ? |-- Canvas.rotate(float degrees, float px, float py) 旋轉
? ? ? ? ? ? |-- Canvas.scale(float sx, float sy, float px, float py) 放縮
? ? ? ? ? ? |-- skew(float sx, float sy) 錯切
? ? ? ? |--使用 Matrix 來做常見和不常見的二維變換简肴。
? ? ? ? ? ? ? ? 1.創(chuàng)建 Matrix 對象;
? ? ? ? ? ? ? ? 2.調用 Matrix 的 pre/postTranslate/Rotate/Scale/Skew() 方法來設置幾何變換百侧;
? ? ? ? ? ? ? ? 3.使用 Canvas.setMatrix() 或 Canvas.concat() 來把幾何變換應用到 Canvas砰识。
? ? ? ? ? ? |--常見變換:
? ? ? ? ? ? ? ? |--Canvas.setMatrix(matrix):用 Matrix 直接替換 Canvas 當前的變換矩陣,即拋棄
? ? ? ? ? ? ? ? Canvas 當前的變換佣渴,改用 Matrix 的變換(注:根據下面評論里以及我在微信公
? ? ? ? ? ? ? ? 眾號中收到的反饋辫狼,不同的系統中? setMatrix(matrix) 的行為可能不一致,所以
? ? ? ? ? ? ? ? 還是盡量用 concat(matrix) 吧)观话;
? ? ? ? ? ? ? ? |--Canvas.concat(matrix):用 Canvas 當前的變換矩陣和 Matrix 相乘予借,即基于 Canvas 當
? ? ? ? ? ? ? ? 前的變換,疊加上 Matrix 中的變換
? ? ? ? ? ? |--自定義變換:使用setPolyToPoly() 方法 用點對點映射的方式設置變換
? ? ? ? ? ? ? ? ? ? 把指定的點移動到給出的位置频蛔,從而發(fā)生形變灵迫,采集點的個數不超過4個
? ? ? ? |-- 使用 Camera 來做三維變換,Camera 的三維變換有三類:旋轉晦溪、平移瀑粥、移動相機
? ? ? ? ? ? |--Camera.rotate*() 三維旋轉
? ? ? ? ? ? |--Camera.translate(float x, float y, float z) 移動
? ? ? ? ? ? |--Camera.setLocation(x, y, z) 設置虛擬相機的位置
四、使用不同的繪制方法來控制繪制順序
繪制內容相互遮蓋的情況是很普遍的三圆,后繪制的模塊的覆蓋前面的繪制
繪制順序:背景色(設置backgroud)狞换、主體(ondraw())避咆、子view(dispatchDraw())、滑動邊緣漸變和滑動條(onDrawForeground())修噪、前景色(onDrawForeground())
draw() 指定繪制方法調用
onDraw() 主體
dispatchDraw() 子view
ondrawForeground() 前景
另有些ViewGroup會查库,會啟動繪制優(yōu)化,導致onDraw不執(zhí)行黄琼,直接繪制子view
--------------------------------------------------
屬性動畫 Property Animation,兩種方式:
? ? |--自帶的animate? 使用方式
? ? ? ? |-- view.animate.xxx
? ? |--ObjectAnimator? ,使用方式
? ? ? ? |--1.如果是自定義控件樊销,需要添加 setter / getter 方法;
? ? ? ? |--2.用 ObjectAnimator.ofXXX() 創(chuàng)建 ObjectAnimator 對象脏款;
? ? ? ? |--3.用 start() 方法執(zhí)行動畫围苫。
? ? |--ValueAnimator 最基本的輪子。很多時候撤师,你用不到它剂府,只是在你使用一些第三方庫的控件,而你想要做動畫的屬性卻沒有 setter / getter 方法的時候剃盾,會需要用到它
通用的屬性:
? ? |--setDuration(int duration) 設置動畫時長 單位是毫秒腺占。
? ? |--加速器
? ? ? ? |--AccelerateDecelerateInterpolator 先加速再減速。這是默認的 Interpolator
? ? ? ? |--LinearInterpolator 勻速万俗。
? ? ? ? |--AccelerateInterpolator 持續(xù)加速湾笛。
? ? ? ? |--DecelerateInterpolator 持續(xù)減速直到 0
? ? ? ? |--AnticipateInterpolator 先回拉一下再進行正常動畫軌跡饮怯。效果看起來有點像投擲物體或跳躍等動作前的蓄力
? ? ? ? |--OvershootInterpolator 動畫會超過目標值一些闰歪,然后再彈回來
? ? ? ? |--AnticipateOvershootInterpolator 上面這兩個的結合版:開始前回拉,最后超過一些然后回彈蓖墅。
? ? ? ? |--BounceInterpolator 在目標值處彈跳库倘,有點像玻璃球掉在地板上的效果。
? ? ? ? |--CycleInterpolator 這個也是一個正弦 / 余弦曲線论矾,不過它和 AccelerateDecelerateInterpolator 的區(qū)別是教翩,它可以自定義曲線的周期,所以動畫可以不到終點就結束贪壳,也可以到達終點后回彈饱亿,回彈的次數由曲線的周期決定,曲線的周期由 CycleInterpolator() 構造方法的參數決定
? ? ? ? |--PathInterpolator 自定義動畫完成度 / 時間完成度曲線闰靴。用這個 Interpolator 你可以定制出任何你想要的速度模型彪笼。定制的方式是使用一個 Path 對象來繪制出你要的動畫完成度 / 時間完成度曲線
? ? ? ? Android 5.0 (API 21)引入了三個新的 Interpolator 模型,并把它們加入了 support v4 包中蚂且。這三個新的 Interpolator 每個都和之前的某個已有的 Interpolator 規(guī)則相似配猫,只有略微的區(qū)別
? ? ? ? |--FastOutLinearInInterpolator 加速運動,只不過 FastOutLinearInInterpolator 的曲線公式是用的貝塞爾曲線杏死,而 AccelerateInterpolator 用的是指數曲線泵肄。具體來說捆交,它倆最主要的區(qū)別是? FastOutLinearInInterpolator 的初始階段加速度比 AccelerateInterpolator 要快一些
? ? ? ? |--FastOutSlowInInterpolator 先加速再減速 FastOutSlowInInterpolator 用的是貝塞爾曲線,AccelerateDecelerateInterpolator 用的是正弦 / 余弦曲線腐巢。具體來講品追, FastOutSlowInInterpolator 的前期加速度要快得多
? ? ? ? |--LinearOutSlowInInterpolator 持續(xù)減速。它和 DecelerateInterpolator 比起來冯丙,同為減速曲線诵盼,主要區(qū)別在于 LinearOutSlowInInterpolator 的初始速度更高
? ? |--監(jiān)聽器? 由于ObjectAnimator 支持使用 pause() 方法暫停,所以它還多了一個 addPauseListener() /? removePauseListener() 的支持银还;而 ViewPropertyAnimator 則獨有 withStartAction() 和 withEndAction() 方法风宁,可以設置一次性的動畫開始或結束的監(jiān)聽
? ? ? ? |--ViewPropertyAnimator.setListener() / ObjectAnimator.addListener(),四個回調方法
? ? ? ? ? ? |--onAnimationStart 當動畫開始執(zhí)行時方法被調用
? ? ? ? ? ? |--onAnimationEnd 當動畫結束時蛹疯,這個方法被調用
? ? ? ? ? ? |--onAnimationCancel 當動畫被通過 cancel() 方法取消時戒财,這個方法被調用。需要說明一下的是捺弦,就算動畫被取消饮寞,onAnimationEnd() 也會被調用。
? ? ? ? ? ? |--onAnimationRepeat 當動畫通過 setRepeatMode() / setRepeatCount() 或 repeat() 方法重復執(zhí)行時列吼,這個方法被調用幽崩。由于 ViewPropertyAnimator 不支持重復,所以這個方法對 ViewPropertyAnimator 相當于無效寞钥。
? ? ? ? |--ViewPropertyAnimator.setUpdateListener() / ObjectAnimator.addUpdateListener()慌申,一個回調方法
? ? ? ? ? ? |--onAnimationUpdate(ValueAnimator animation) 當動畫的屬性更新時(不嚴謹的說,即每過 10 毫秒理郑,動畫的完成度更新時)蹄溉,這個方法被調用
---------------------------
針對特殊類型的屬性來做屬性動畫,它可以讓你「做到本來做不到的動畫]?
? ? |--TypeEvaluator
? ? ? ? |--ArgbEvaluator 顏色的
? ? ? ? |--自定義 Evaluator 重新evaluate方法
? ? ? ? |--ofObject() 借助于 TypeEvaluator您炉,屬性動畫就可以通過 ofObject() 來對不限定類型的屬性做動畫
? ? ? ? ? ? |--1.為目標屬性寫一個自定義的 TypeEvaluator
? ? ? ? ? ? |--2.使用 ofObject() 來創(chuàng)建 Animator柒爵,并把自定義的 TypeEvaluator 作為參數填入
? ? ? ? |--ofMultiInt()/ofMultiFloat() 不常用
針對復雜的屬性關系來做屬性動畫,它可以讓你「能做到的動畫做起來更簡單」
? ? |--使用 PropertyValuesHolder 來對多個屬性同時做動畫
? ? |--使用 AnimatorSet 來同時管理調配多個動畫;按照要求的順序來工作
? ? |--PropertyValuesHolder 的進階使用:使用 PropertyValuesHolder.ofKeyframe() 來把一個屬性拆分成多段赚爵,執(zhí)行更加精細的屬性動畫棉胀。
-------------------------自定義view-布局
測量尺寸measure-->調用onMeasure()方法,方法里做的事不一樣
? ? |--子view進行測量
? ? |--遍歷所有子view冀膝,調用子view的measure唁奢,調用onMeasure
? ? ? ? |--子view進行測量
布局 layout
? ? |--子view,onLayout()空實現
? ? |--viewGroup,調用子view的layout方法?
重寫onMeasure,計算寬高尺寸,然后setMeasuredDimension()保存