美文网首页
技能树-android基础-自定义View

技能树-android基础-自定义View

作者: 6faef730638b | 来源:发表于2018-04-17 19:43 被阅读13次

自定义View可以大致分为三个阶段:绘制、布局和触摸反馈

绘制

掌握4个级别的知识

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

Canvas相关

1.颜色填充
Canvas.drawColor(@ColorInt int color)
canvas.drawRGB(100, 200, 100);
canvas.drawARGB(100, 100, 200, 100);
2.画圆
drawCircle(float centerX, float centerY, float radius, Paint paint)
3.画矩形
drawRect(float left, float top, float right, float bottom, Paint paint)
4.画点
drawPoint(float x, float y, Paint paint)
drawPoints(float[] pts, int offset, int count, Paint paint) / drawPoints(float[] pts, Paint paint)
5.画椭圆
drawOval(float left, float top, float right, float bottom, Paint paint)
6.画线
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)
7.画圆角矩形
drawRoundRect(float left, float top, float right, float bottom, float rx, float ry, Paint paint)
8.绘制弧形或扇形
drawArc(float left, float top, float right, float bottom, float startAngle, float sweepAngle, boolean useCenter, Paint paint)
9.画自定义图形
drawPath(Path path, Paint paint)
10.画 Bitmap
drawBitmap(Bitmap bitmap, float left, float top, Paint paint)
11.绘制文字
drawText(String text, float x, float y, Paint paint)

Paint相关

1.Paint.setColor(int color)用来设置绘制内容的颜色
2.Paint.setStyle(Paint.Style style)设置绘制Style
3.Paint.setStrokeWidth(float width)设置线条的宽度
4.Paint paint = new Paint(Paint.ANTI_ALIAS_FLAG); 抗锯齿

Paint 的完全攻略

颜色

有三层对颜色的处理
1.基本颜色设置
1.1 直接设置
paint.setColor(Color.parseColor("#009688"));
paint.setARGB(100, 255, 0, 0);

1.2 Shader设置

Shader可以实现渐变,不同子类实现不同的渐变

1.2.1 LinearGradient 线性渐变

LinearGradient(float x0, float y0, float x1, float y1, int color0, int color1, Shader.TileMode tile)

1.2.2 RadialGradient 辐射渐变

RadialGradient(float centerX, float centerY, float radius, int centerColor, int edgeColor, TileMode tileMode)

1.2.3 SweepGradient 扫描渐变
SweepGradient(float cx, float cy, int color0, int color1)

1.2.4 BitmapShader图片渐变
BitmapShader(Bitmap bitmap, Shader.TileMode tileX, Shader.TileMode tileY)

1.2.5 ComposeShader混合渐变
ComposeShader(Shader shaderA, Shader shaderB, PorterDuff.Mode mode)

=================================================

2.setColorFilter() 用来基于颜色进行过滤处理

为绘制的内容设置一个统一的过滤策略,对每个像素都进行过滤后再绘制出来

有三个不同实现的子类

2.1 LightingColorFilter
LightingColorFilter(int mul, int add)
参数里的 mul 和 add 都是和颜色值格式相同的 int 值
其中 mul 用来和目标像素相乘,add 用来和目标像素相加
计算公式:

R' = R * mul.R / 0xff + add.R  
G' = G * mul.G / 0xff + add.G  
B' = B * mul.B / 0xff + add.B 

2.2 PorterDuffColorFilter
作用是使用一个指定的颜色和一种指定的 PorterDuff.Mode 来与绘制对象进行合成
PorterDuffColorFilter(int color, PorterDuff.Mode mode)
其中的 color 参数是指定的颜色, mode 参数是指定的 Mode。同样也是 PorterDuff.Mode

2.3 ColorMatrixColorFilter
olorMatrixColorFilter 使用一个 ColorMatrix 来对颜色进行处理
ColorMatrix 这个类,内部是一个 4x5 的矩阵

=================================================

3.setXfermode() 用来处理源图像和 View 已有内容的关系

以绘制的内容作为源图像,以View中已有的内容作为目标图像,选取一个 PorterDuff.Mode 作为绘制内容的颜色处理方案

3.1 使用离屏缓冲(Off-screen Buffer)

把内容绘制在额外的层上,再把绘制好的内容贴回 View 中

//使用
int saved = canvas.saveLayer(null, null, Canvas.ALL_SAVE_FLAG);
canvas.restoreToCount(saved);

3.2 控制好透明区域

效果

效果类的 API ,指的就是抗锯齿、填充/轮廓、线条宽度等等这些。

1.设置抗锯齿
setAntiAlias (boolean aa)
===============================
2.设置填充模式
setStyle(Paint.Style style)
===============================
3.设置线条

3.1设置线条宽度
setStrokeWidth(float width)
3.2设置线头形状
setStrokeCap(Paint.Cap cap)
3.3设置拐角形状
setStrokeJoin(Paint.Join join),
3.4设置 MITER 型拐角的延长线的最大值
setStrokeMiter(float miter)
===============================
4.色彩优化

4.1设置抖动来优化色彩深度降低时的绘制效果
setDither(boolean dither)
4.2设置双线性过滤来优化 Bitmap 放大绘制的效果
setFilterBitmap(boolean filter)
===============================
5.设置轮廓效果

5.1把所有拐角变成圆角
PathEffect pathEffect = new CornerPathEffect(20);
paint.setPathEffect(pathEffect);
5.2线条进行随机的偏离,让轮廓变得乱七八糟
PathEffect pathEffect = new DiscretePathEffect(20, 5);
paint.setPathEffect(pathEffect);
5.3虚线线条
PathEffect pathEffect = new DashPathEffect(new float[]{20, 10, 5, 10}, 0);
paint.setPathEffect(pathEffect);
5.4Path线条
PathDashPathEffect(Path shape, float advance, float phase, PathDashPathEffect.Style style)
5.5两种 PathEffect绘制同时
new SumPathEffect(dashEffect, discreteEffect);
5.6 两种 PathEffect绘制先后
new ComposePathEffect(dashEffect, discreteEffect);
===============================
6.设置阴影层
setShadowLayer(float radius, float dx, float dy, int shadowColor)
===============================
7.设置绘制层上方附加效果

setMaskFilter(MaskFilter maskfilter)
7.1模糊效果
paint.setMaskFilter(new BlurMaskFilter(50, BlurMaskFilter.Blur.NORMAL));
7.2浮雕效果
paint.setMaskFilter(new EmbossMaskFilter(new float[]{0, 1, 1}, 0.2f, 8, 10));
===============================
8.获取Path
8.1获取实际 Path
实际 Path ,指的就是 drawPath() 的绘制内容的轮廓,要算上线条宽度和设置的 PathEffect。
getFillPath(Path src, Path dst)
8.2获取的就是目标文字所对应的 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)

文本

初始化

1.reset()
重置 Paint 的所有属性为默认值。相当于重新 new 一个,不过性能当然高一些

2.set(Paint src)
把 src 的所有属性全部复制过来。相当于调用 src 所有的 get 方法,然后调用这个 Paint 的对应的 set 方法来设置它们。

3.setFlags(int flags)
paint.setFlags(Paint.ANTI_ALIAS_FLAG | Paint.DITHER_FLAG);
等价
paint.setAntiAlias(true);
paint.setDither(true);

Canvas 对绘制的辅助——范围裁切和几何变换。

使用不同的绘制方法来控制绘制顺序

布局

触摸反馈


额外知识-动画

动画在实现自定义view时尤为重要 特归于此类

视图动画

提供的简单动画API
大致分为四种,可以使用AnimationSet进行组合动画

缩放ScaleAnimation

Animation animation = new ScaleAnimation(fromXScale, toScaleX, fromYScale, toScaleY);
Animation animation = new ScaleAnimation(
fromXScale, toScaleX,
fromYScale, toScaleY,
pivotX, pivotY
);

平移TranslateAnimation

Animation animation = new TranslateAnimation(fromXDelta, toXDelta, fromYDelta, toYDelta);

渐变AlphaAnimation

Animation animation = new AlphaAnimation(fromAlpha, toAlpha);

旋转RotateAnimation

Animation animation = new RotateAnimation(0, 60);

逐帧动画

顺序显示多张一定时间的图片

属性动画

属性变换 在这个过程中不断更新view的属性并刷新视图 达到动画的效果

ViewPropertyAnimator

进行一些简单动画的属性view

view.animate()//返回ViewPropertyAnimator
.setTranslationX();//写多个方法改变多个属性

ObjectAnimator

ObjectAnimator animator=ObjectAnimator.ofFloat(view,"translationX",startvalue,endvalue);//Float指的是属性的类型
"translationX" 会根据你的字符串拼接成 setTranslationX(后面的参数) 调用
animator.start()执行动画

在自定义的setter中进行重绘 下一帧使用新的属性

插值器

动画完成度 与 时间完成度的关系模型

image.png

1.LinearInterpolator 线性插值器 匀速

2.AccelerateInterpolator 持续加速

3.DecelerateInterpolator 持续减速直到 0

4.AccelerateDecelerateInterpolator 先加速再减速

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

6.OvershootInterpolator
动画会超过目标值一些,然后再弹回来。效果看起来有点像你一屁股坐在沙发上后又被弹起来一点的感觉。

7.AnticipateOvershootInterpolator
开始前回拉,最后超过一些然后回弹

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

9.CycleInterpolator
自定义曲线的周期

10.PathInterpolator
自定义动画完成度 / 时间完成度曲线。

使用Path 对象来绘制出你要的动画完成度 / 时间完成度曲线
x轴为时间完成度0-1 y轴为动画完成度0-1

监听器

onAnimationStart(Animator animation)
onAnimationEnd(Animator animation)
onAnimationCancel(Animator animation)
onAnimationRepeat(Animator animation)
onAnimationUpdate(ValueAnimator animation)

1.ViewPropertyAnimator
ViewPropertyAnimator.withStartAction/EndAction()

2.ObjectAnimator
addListener()
addUpdateListener()
移除监听器则是通过 remove[Update]Listener()

重要函数解析

1.requestLayout()、invalidate()与postInvalidate()有什么区别?

requestLayout():该方法会递归调用父窗口的requestLayout()方法,直到触发ViewRootImpl的performTraversals()方法,此时mLayoutRequestede为true,会触发onMesaure()与onLayout()方法,不一定会触发onDraw()方法。

invalidate():该方法递归调用父View的invalidateChildInParent()方法,直到调用ViewRootImpl的invalidateChildInParent()方法,最终触发ViewRootImpl的performTraversals()方法,此时mLayoutRequestede为false,不会触发onMesaure()与onLayout()方法,当时会触发onDraw()方法。

postInvalidate():该方法功能和invalidate()一样,只是它可以在非UI线程中调用。
一般说来需要重新布局就调用requestLayout()方法,需要重新绘制就调用invalidate()方法。

相关文章

网友评论

      本文标题:技能树-android基础-自定义View

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