自定义View精简学习笔记(一)

自定义控件一直是让很多人包括我头疼的地方,难度较高 且学习资料零碎 直到我发现扔物线大神的HenCoder进阶手册.

这篇文章记录一下学习过程,以及途中经过精简的内容.便于日后查阅

1.1 绘制基础

关键词语: onDraw()方法 Canvas 画布 Paint画笔

一切的开始:

绘制圆形:

Paint paint = new Paint();

@Override
protected void onDraw(Canvas canvas) {  
    super.onDraw(canvas);
    // 绘制一个圆
    canvas.drawCircle(300, 300, 200, paint);
}
  • 1.Canvas 类下的所有 draw- 打头的方法,例如 drawCircle() drawBitmap()。
  • 2.Paint 类的几个最常用的方法。具体是:

Paint.setStyle(Style style) 设置绘制模式

Paint.setColor(int color) 设置颜色

Paint.setStrokeWidth(float width) 设置线条宽度

Paint.setTextSize(float textSize) 设置文字大小

Paint.setAntiAlias(boolean aa) 设置抗锯齿开关

Canvas.drawColor(@ColorInt int color) 颜色填充.这是最基本的 drawXXX() 方法:在整个绘制区域统一涂上指定的颜色(可以这么理解: 画布整个染上了某种颜色), 这类颜色填充方法一般用于在绘制之前设置底色,或者在绘制之后为界面设置半透明蒙版。

类似方法(作用一致) : drawRGB(int r, int g, int b) 和 drawARGB(int a, int r, int g, int b)

drawCircle(float centerX, float centerY, float radius, Paint paint) 画圆,参数:圆心xy坐标 半径 画笔.原点是View 左上角的那个点;水平方向是 x 轴,右正左负

例:canvas.drawCircle(300, 300, 200, paint) 如下图:

绘制圆

划重点 : 一些独有信息(就是只有它有,别人没有的信息.例如画圆:圆心 半径) 都会直接作为参数写进 drawXXX() 方法里的(比如 drawCircle(centerX, centerY, radius, paint) 的前三个参数)。
而除此之外,其他的都是公有信息。比如图形的颜色、空心实心这些,你不管是画圆还是画方都有可能用到的,这些信息则是统一放在 paint 参数里的

  • drawRect(float left, float top, float right, float bottom, Paint paint) 画矩形

  • drawPoint(float x, float y, Paint paint) 画点

  • drawPoints(float[] pts, int offset, int count, Paint paint) / drawPoints(float[] pts, Paint paint) 画点(批量)

  • drawOval(float left, float top, float right, float bottom, Paint paint) 画椭圆

  • drawLine(float startX, float startY, float stopX, float stopY, Paint paint) 画线

  • drawLines(float[] pts, int offset, int count, Paint paint) / drawLines(float[] pts, Paint paint) 画线(批量)

  • drawRoundRect(float left, float top, float right, float bottom, float rx, float ry, Paint paint) 画圆角矩形

  • drawArc(float left, float top, float right, float bottom, float startAngle, float sweepAngle, boolean useCenter, Paint paint) 绘制弧形或扇形

  • drawPath(Path path, Paint paint) 画自定义图形

    Path 方法第一类:直接描述路径。

    * 第一组 : addXxx() ——添加子图形  
    eg:addCircle(float x, float y, float radius, Direction dir) 添加圆 还可以添加椭圆 矩形 圆角矩形
    
    * 第二组 : xxxTo() ——画线(直线或曲线)
    eg:lineTo(float x, float y) / rLineTo(float x, float y)前缀 r 代表 relatively 「相对地」 画直线.
    quadTo(float x1, float y1, float x2, float y2) / rQuadTo(float dx1, float dy1, float dx2, float dy2) 画二次贝塞尔曲线.
    moveTo(float x, float y) / rMoveTo(float x, float y) 移动到目标位置
    两个特殊的方法: arcTo() 和 addArc()。它们也是用来画线的,但并不使用当前位置作为弧线的起点。
    特殊1:arcTo(RectF oval, float startAngle, float sweepAngle, boolean forceMoveTo) / arcTo(float left, float top, float right, float bottom,
    float startAngle, float sweepAngle, boolean forceMoveTo) / arcTo(RectF oval, float startAngle, float sweepAngle) 画弧形
    特殊2:addArc(float left, float top, float right, float bottom, float startAngle, float sweepAngle) / addArc(RectF oval, float startAngle, float sweepAngle)
    
    close() 封闭当前子图形它的作用是把当前的子图形封闭,即由当前位置向当前子图形的起点绘制一条直线。
    

    Path 方法第二类:辅助的设置或计算(场景比较少,只讲其中一个方法: setFillType(FillType fillType)。)

    Path.setFillType(Path.FillType ft) 设置填充方式
    FillType 的取值有四个:
    EVEN_ODD(原理:奇偶原则)
    WINDING (非零环绕数原则)(默认值)
    INVERSE_EVEN_ODD
    INVERSE_WINDING
    
  • drawBitmap(Bitmap bitmap, float left, float top, Paint paint) 画 Bitmap

  • drawText(String text, float x, float y, Paint paint) 绘制文字(Paint.setTextSize(float textSize)设置文字大小)

总结:1.1绘制基础: Canvas 的 drawXXX() 系列方法和 Paint 的基本使用,就到这里

想看1.1详细原文请戳这里,里面还有练习项目...

1.2 Paint详解

emm....这期的内容,只要做到「知道有这么个东西」,在需要用到的时候能想起来这个功能能不能做、大致用什么做就好,至于具体的实现,到时候拐回来再翻一次就行了。

Paint 的 API 大致可以分为 4 类:

1.颜色

1.1 基本颜色
* 直接设置颜色 : setColor(int color) setARGB(int a, int r, int g, int b)
* 设置着色器 : setShader(Shader shader) 
        > LinearGradient 线性渐变
            Shader shader = new LinearGradient(100, 100, 500, 500, Color.parseColor("#E91E63"),Color.parseColor("#2196F3"),Shader.TileMode.CLAMP);
        > RadialGradient 辐射渐变(从中心向周围)
            Shader shader = new RadialGradient(300, 300, 200, Color.parseColor("#E91E63"), Color.parseColor("#2196F3"), Shader.TileMode.CLAMP);
        > SweepGradient 扫描渐变
            Shader shader = new SweepGradient(300, 300, Color.parseColor("#E91E63"),Color.parseColor("#2196F3"));
        > BitmapShader 用 Bitmap 的像素来作为图形或文字的填充
            Bitmap bitmap = BitmapFactory.decodeResource(getResources(), R.drawable.batman);  
            Shader shader = new BitmapShader(bitmap, Shader.TileMode.CLAMP, Shader.TileMode.CLAMP);  
        > ComposeShader 混合着色器
            // 第一个 Shader:头像的 Bitmap
            Bitmap bitmap1 = BitmapFactory.decodeResource(getResources(), R.drawable.batman);  
            Shader shader1 = new BitmapShader(bitmap1, Shader.TileMode.CLAMP, Shader.TileMode.CLAMP);
            // 第二个 Shader:从上到下的线性渐变(由透明到黑色)
            Bitmap bitmap2 = BitmapFactory.decodeResource(getResources(), R.drawable.batman_logo);  
            Shader shader2 = new BitmapShader(bitmap2, Shader.TileMode.CLAMP, Shader.TileMode.CLAMP);
            // ComposeShader:结合两个 Shader
            Shader shader = new ComposeShader(shader1, shader2, PorterDuff.Mode.SRC_OVER); 
        
1.2 设置颜色过滤器 setColorFilter(ColorFilter colorFilter)
        > LightingColorFilter 模拟光照效果
            ColorFilter lightingColorFilter = new LightingColorFilter(0x00ffff, 0x000000);  
        > PorterDuffColorFilter 使用一个指定的颜色和一种指定的 PorterDuff.Mode 来与绘制对象进行合成
            PorterDuffColorFilter(int color, PorterDuff.Mode mode) 
        > ColorMatrixColorFilter 使用一个 ColorMatrix 来对颜色进行处理。 ColorMatrix 这个类,内部是一个 4x5 的矩阵(厉害了)
1.3 setXfermode(Xfermode xfermode)  以绘制的内容作为源图像,以 View 中已有的内容作为目标图像,选取一个  PorterDuff.Mode 作为绘制内容的颜色处理方案

2.效果

2.1 setAntiAlias (boolean aa) 设置抗锯齿
2.2 setStyle(Paint.Style style) 设置填充模式
2.3 线条形状,四个方法:
    >  setStrokeWidth(float width)设置线条宽度。单位为像素,默认值是 0。
    >  setStrokeCap(Paint.Cap cap)设置线头的形状。线头形状有三种:BUTT 平头、ROUND 圆头、SQUARE 方头。默认为 BUTT。
    >  setStrokeJoin(Paint.Join join)设置拐角的形状。有三个值可以选择:MITER 尖角、 BEVEL 平角和 ROUND 圆角。默认为 MITER。
    >  setStrokeMiter(float miter)这个方法是对于 setStrokeJoin() 的一个补充,它用于设置 MITER 型拐角的延长线的最大值。
2.4 色彩优化.Paint 的色彩优化有两个方法: setDither(boolean dither) 和 setFilterBitmap(boolean filter)    
    >  setDither(boolean dither)设置图像的抖动。
    >  setFilterBitmap(boolean filter)设置是否使用双线性过滤来绘制 Bitmap 。
2.5 setPathEffect(PathEffect effect)使用 PathEffect 来给图形的轮廓设置效果。
2.6 setShadowLayer(float radius, float dx, float dy, int shadowColor)在之后的绘制内容下面加一层阴影。
2.7 setMaskFilter(MaskFilter maskfilter)为之后的绘制设置 MaskFilter。 有BlurMaskFilter模糊效果 EmbossMaskFilter浮雕效果 
2.8 获取绘制的 Path.根据 paint 的设置,计算出绘制 Path 或文字时的实际 Path。
    >  getFillPath(Path src, Path dst) 获取实际path
    >  getTextPath(String text, int start, int end, float x, float y, Path path) / getTextPath(char[] text, int index, int count, float x, float y, Path path)获取文字path

3.drawText() 相关

方法太多,下一节里单独讲;

4.初始化

它们是用来初始化 Paint 对象,或者是批量设置 Paint 的多个属性的方法
4.1 reset() 重置 Paint 的所有属性为默认值。相当于重新 new 一个,不过性能当然高一些啦。
4.2 set(Paint src) 把 src 的所有属性全部复制过来。相当于调用 src 所有的 get 方法,然后调用这个 Paint 的对应的  set 方法来设置它们。
4.3 setFlags(int flags)  批量设置 flags。相当于依次调用它们的 set 方法。例如:

最后再强调一遍:这期的内容没必要全部背会,只要看懂、理解,记住有这么个东西就行了。以后在用到的时候,再拐回来翻一翻就行了。

原文及练习传送门

©著作权归作者所有,转载或内容合作请联系作者
  • 序言:七十年代末,一起剥皮案震惊了整个滨河市,随后出现的几起案子,更是在滨河造成了极大的恐慌,老刑警刘岩,带你破解...
    沈念sama阅读 205,132评论 6 478
  • 序言:滨河连续发生了三起死亡事件,死亡现场离奇诡异,居然都是意外死亡,警方通过查阅死者的电脑和手机,发现死者居然都...
    沈念sama阅读 87,802评论 2 381
  • 文/潘晓璐 我一进店门,熙熙楼的掌柜王于贵愁眉苦脸地迎上来,“玉大人,你说我怎么就摊上这事。” “怎么了?”我有些...
    开封第一讲书人阅读 151,566评论 0 338
  • 文/不坏的土叔 我叫张陵,是天一观的道长。 经常有香客问我,道长,这世上最难降的妖魔是什么? 我笑而不...
    开封第一讲书人阅读 54,858评论 1 277
  • 正文 为了忘掉前任,我火速办了婚礼,结果婚礼上,老公的妹妹穿的比我还像新娘。我一直安慰自己,他们只是感情好,可当我...
    茶点故事阅读 63,867评论 5 368
  • 文/花漫 我一把揭开白布。 她就那样静静地躺着,像睡着了一般。 火红的嫁衣衬着肌肤如雪。 梳的纹丝不乱的头发上,一...
    开封第一讲书人阅读 48,695评论 1 282
  • 那天,我揣着相机与录音,去河边找鬼。 笑死,一个胖子当着我的面吹牛,可吹牛的内容都是我干的。 我是一名探鬼主播,决...
    沈念sama阅读 38,064评论 3 399
  • 文/苍兰香墨 我猛地睁开眼,长吁一口气:“原来是场噩梦啊……” “哼!你这毒妇竟也来了?” 一声冷哼从身侧响起,我...
    开封第一讲书人阅读 36,705评论 0 258
  • 序言:老挝万荣一对情侣失踪,失踪者是张志新(化名)和其女友刘颖,没想到半个月后,有当地人在树林里发现了一具尸体,经...
    沈念sama阅读 42,915评论 1 300
  • 正文 独居荒郊野岭守林人离奇死亡,尸身上长有42处带血的脓包…… 初始之章·张勋 以下内容为张勋视角 年9月15日...
    茶点故事阅读 35,677评论 2 323
  • 正文 我和宋清朗相恋三年,在试婚纱的时候发现自己被绿了。 大学时的朋友给我发了我未婚夫和他白月光在一起吃饭的照片。...
    茶点故事阅读 37,796评论 1 333
  • 序言:一个原本活蹦乱跳的男人离奇死亡,死状恐怖,灵堂内的尸体忽然破棺而出,到底是诈尸还是另有隐情,我是刑警宁泽,带...
    沈念sama阅读 33,432评论 4 322
  • 正文 年R本政府宣布,位于F岛的核电站,受9级特大地震影响,放射性物质发生泄漏。R本人自食恶果不足惜,却给世界环境...
    茶点故事阅读 39,041评论 3 307
  • 文/蒙蒙 一、第九天 我趴在偏房一处隐蔽的房顶上张望。 院中可真热闹,春花似锦、人声如沸。这庄子的主人今日做“春日...
    开封第一讲书人阅读 29,992评论 0 19
  • 文/苍兰香墨 我抬头看了看天上的太阳。三九已至,却和暖如春,着一层夹袄步出监牢的瞬间,已是汗流浃背。 一阵脚步声响...
    开封第一讲书人阅读 31,223评论 1 260
  • 我被黑心中介骗来泰国打工, 没想到刚下飞机就差点儿被人妖公主榨干…… 1. 我叫王不留,地道东北人。 一个月前我还...
    沈念sama阅读 45,185评论 2 352
  • 正文 我出身青楼,却偏偏与公主长得像,于是被迫代替她去往敌国和亲。 传闻我的和亲对象是个残疾皇子,可洞房花烛夜当晚...
    茶点故事阅读 42,535评论 2 343

推荐阅读更多精彩内容