美文网首页
Android自定义组件相关基础总结

Android自定义组件相关基础总结

作者: 海阔天空cqk | 来源:发表于2019-10-16 14:09 被阅读0次

    自定义绘制知识的四个级别

    一、Canvas 的 drawXXX() 系列方法及 Paint 最常见的使用

        |--简单图形的绘制:canvas.drawXXX()及paint的一些常用参数设置

        |--自定义图形绘制Path,它有两类方法:

          |--直接描述路径的

              |--添加子图形 path.addXxx()

              |--画线(直线或曲线)path.xxxTo(), close()或lineto()可图形封闭。特殊的方法:画弧 arcTo() 和 addArc()

          |--辅助的设置或计算,其中一种setFillType(FillType fillType)。FillType四中算法

                |--EVEN_ODD 奇偶原则(无方向要求):奇数,则这个点被认为在图形内部;如果是偶数,则这个点被认为在图形外部

                |--WINDING (默认值)非零环绕数原则(有方向):以 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.控制好透明区域,必须足够覆盖到要和它结合绘制的内容

        |--效果 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 型拐角的延长线的最大值。超过角度时,尖角变平角

            |--色彩优化

                |--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 直译是「地域」,其实就是你在系统里设置的「语言」或「语言区域」

                |--setLinearText(boolean linearText)

            |--测量文字尺寸类

                |--paint.getFontSpacing() 获取推荐的行距

                |--paint.getFontMetrics() FontMetrics 是个相对专业的工具类,它提供了几个文字排印方面的数值: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() 的区别是, 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.创建 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() 方法 用点对点映射的方式设置变换

                        把指定的点移动到给出的位置,从而发生形变,采集点的个数不超过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会,会启动绘制优化,导致onDraw不执行,直接绘制子view

    --------------------------------------------------

    属性动画 Property Animation,两种方式:

        |--自带的animate  使用方式

            |-- view.animate.xxx

        |--ObjectAnimator  ,使用方式

            |--1.如果是自定义控件,需要添加 setter / getter 方法;

            |--2.用 ObjectAnimator.ofXXX() 创建 ObjectAnimator 对象;

            |--3.用 start() 方法执行动画。

        |--ValueAnimator 最基本的轮子。很多时候,你用不到它,只是在你使用一些第三方库的控件,而你想要做动画的属性却没有 setter / getter 方法的时候,会需要用到它

    通用的属性:

        |--setDuration(int duration) 设置动画时长 单位是毫秒。

        |--加速器

            |--AccelerateDecelerateInterpolator 先加速再减速。这是默认的 Interpolator

            |--LinearInterpolator 匀速。

            |--AccelerateInterpolator 持续加速。

            |--DecelerateInterpolator 持续减速直到 0

            |--AnticipateInterpolator 先回拉一下再进行正常动画轨迹。效果看起来有点像投掷物体或跳跃等动作前的蓄力

            |--OvershootInterpolator 动画会超过目标值一些,然后再弹回来

            |--AnticipateOvershootInterpolator 上面这两个的结合版:开始前回拉,最后超过一些然后回弹。

            |--BounceInterpolator 在目标值处弹跳,有点像玻璃球掉在地板上的效果。

            |--CycleInterpolator 这个也是一个正弦 / 余弦曲线,不过它和 AccelerateDecelerateInterpolator 的区别是,它可以自定义曲线的周期,所以动画可以不到终点就结束,也可以到达终点后回弹,回弹的次数由曲线的周期决定,曲线的周期由 CycleInterpolator() 构造方法的参数决定

            |--PathInterpolator 自定义动画完成度 / 时间完成度曲线。用这个 Interpolator 你可以定制出任何你想要的速度模型。定制的方式是使用一个 Path 对象来绘制出你要的动画完成度 / 时间完成度曲线

            Android 5.0 (API 21)引入了三个新的 Interpolator 模型,并把它们加入了 support v4 包中。这三个新的 Interpolator 每个都和之前的某个已有的 Interpolator 规则相似,只有略微的区别

            |--FastOutLinearInInterpolator 加速运动,只不过 FastOutLinearInInterpolator 的曲线公式是用的贝塞尔曲线,而 AccelerateInterpolator 用的是指数曲线。具体来说,它俩最主要的区别是  FastOutLinearInInterpolator 的初始阶段加速度比 AccelerateInterpolator 要快一些

            |--FastOutSlowInInterpolator 先加速再减速 FastOutSlowInInterpolator 用的是贝塞尔曲线,AccelerateDecelerateInterpolator 用的是正弦 / 余弦曲线。具体来讲, FastOutSlowInInterpolator 的前期加速度要快得多

            |--LinearOutSlowInInterpolator 持续减速。它和 DecelerateInterpolator 比起来,同为减速曲线,主要区别在于 LinearOutSlowInInterpolator 的初始速度更高

        |--监听器  由于ObjectAnimator 支持使用 pause() 方法暂停,所以它还多了一个 addPauseListener() /  removePauseListener() 的支持;而 ViewPropertyAnimator 则独有 withStartAction() 和 withEndAction() 方法,可以设置一次性的动画开始或结束的监听

            |--ViewPropertyAnimator.setListener() / ObjectAnimator.addListener(),四个回调方法

                |--onAnimationStart 当动画开始执行时方法被调用

                |--onAnimationEnd 当动画结束时,这个方法被调用

                |--onAnimationCancel 当动画被通过 cancel() 方法取消时,这个方法被调用。需要说明一下的是,就算动画被取消,onAnimationEnd() 也会被调用。

                |--onAnimationRepeat 当动画通过 setRepeatMode() / setRepeatCount() 或 repeat() 方法重复执行时,这个方法被调用。由于 ViewPropertyAnimator 不支持重复,所以这个方法对 ViewPropertyAnimator 相当于无效。

            |--ViewPropertyAnimator.setUpdateListener() / ObjectAnimator.addUpdateListener(),一个回调方法

                |--onAnimationUpdate(ValueAnimator animation) 当动画的属性更新时(不严谨的说,即每过 10 毫秒,动画的完成度更新时),这个方法被调用

    ---------------------------

    针对特殊类型的属性来做属性动画,它可以让你「做到本来做不到的动画] 

        |--TypeEvaluator

            |--ArgbEvaluator 颜色的

            |--自定义 Evaluator 重新evaluate方法

            |--ofObject() 借助于 TypeEvaluator,属性动画就可以通过 ofObject() 来对不限定类型的属性做动画

                |--1.为目标属性写一个自定义的 TypeEvaluator

                |--2.使用 ofObject() 来创建 Animator,并把自定义的 TypeEvaluator 作为参数填入

            |--ofMultiInt()/ofMultiFloat() 不常用

    针对复杂的属性关系来做属性动画,它可以让你「能做到的动画做起来更简单」

        |--使用 PropertyValuesHolder 来对多个属性同时做动画

        |--使用 AnimatorSet 来同时管理调配多个动画;按照要求的顺序来工作

        |--PropertyValuesHolder 的进阶使用:使用 PropertyValuesHolder.ofKeyframe() 来把一个属性拆分成多段,执行更加精细的属性动画。

    -------------------------自定义view-布局

    测量尺寸measure-->调用onMeasure()方法,方法里做的事不一样

        |--子view进行测量

        |--遍历所有子view,调用子view的measure,调用onMeasure

            |--子view进行测量

    布局 layout

        |--子view,onLayout()空实现

        |--viewGroup,调用子view的layout方法 

    重写onMeasure,计算宽高尺寸,然后setMeasuredDimension()保存

    相关文章

      网友评论

          本文标题:Android自定义组件相关基础总结

          本文链接:https://www.haomeiwen.com/subject/kitumctx.html