自定义View基础 - onMeasure、Paint类、C

2018-09-27  本文已影响0人  wayDevelop

onMeasure

这意味着我们的自定义View到了处理自己的大小的时候。这是非常重要的方法,因为在大多数情况下,你的View需要有特定的大小以适应你的布局。

当你重写此方法,需要记得的是,最终要设setMeasuredDimension(int width, int height) 。

当处理自定义View的大小时候,使用者可能通过layout.xml或者动态设置了具体的大小。要正确地计算它,我们需要做几件事情。

protected void onMeasure(int widthMeasureSpec, int heightMeasureSpec) {
    int widthMode = MeasureSpec.getMode(widthMeasureSpec);
    int widthSize = MeasureSpec.getSize(widthMeasureSpec);
    int heightMode = MeasureSpec.getMode(heightMeasureSpec);
    int heightSize = MeasureSpec.getSize(heightMeasureSpec);
}
int width;
if (widthMode == MeasureSpec.EXACTLY) {
  width = widthSize;
} else if (widthMode == MeasureSpec.AT_MOST) {
  width = Math.min(desiredWidth, widthSize);
} else {
  width = desiredWidth;
}

注意:
看看MeasureSpec的值:

在通过setMeasuredDimension设置最终值之前,以防万一,可以检查这些值不为负数。这可以避免在布局预览时一些问题。

View 更新

从View的生命周期图可以得知,可以重绘View自身有两种方法。invalidate()和requestLayout()方法会帮助你在运行时动态改变View状态。但为什么需要两个方法?

invalidate()用来简单重绘View。例如更新其文本,色彩或触摸交互性。View将只调用onDraw()方法再次更新其状态。

requestLayout()方法,你可以看到其将会从`onMeasure()开始更新View。这意味着你的View更新后,它改变它的大小,你需要再次测量它,并依赖于新的大小来重新绘制。

动画

在自定义View中,动画是一帧一帧的过程。这意味着,如果你想使一个圆半径从小变大,你将需要逐步增加半径并调用invalidate()来重绘它。

在自定义View动画中,ValueAnimator是你的好朋友。下面这个类将帮助你从任何值开始执行动画到最后,甚至支持Interpolator(如果需要)。

ValueAnimator animator = ValueAnimator.ofInt(0, 100);
animator.setDuration(1000);
animator.setInterpolator(new DecelerateInterpolator());
animator.addUpdateListener(new ValueAnimator.AnimatorUpdateListener() {
  public void onAnimationUpdate(ValueAnimator animation) {
    int newRadius = (int) animation.getAnimatedValue();
  }
});

注意:
当每一次新的动画值出来时,不要忘记调用invalidate()。

Paint类

Paint画笔对象,这个类中包含了如何绘制几何图形、文字和位图的样式和颜色信息,指定了如何绘制文本和图形。画笔对象右很多设置方法,大体上可以分为两类:一类与图形绘制有关,一类与文本绘制有关。

Paint类中有如下方法:

1、图形绘制:

  setStyle(Paint.Style s):设置画笔的样式:FILL实心;STROKE空心;FILL_OR_STROKE同时实心与空心;
  setStrokeCap(Paint.Cap c):当设置画笔样式为STROKE或FILL_OR_STROKE时,设置笔刷的图形样式;
  setStrokeWidth(float w):当画笔样式为STROKE或FILL_OR_STROKE时,设置笔刷的粗细度;
  setAlpha(int a):设置绘制的图形的透明度;
  setColor(int color):设置绘制的颜色;

  setAntiAlias(boolean a):设置是否使用抗锯齿功能,抗锯齿功能会消耗较大资源,绘制图形的速度会减慢;
  setArgb(int a, int r, int g, int b):设置绘制的颜色,a表示透明度,r、g、b表示颜色值;
  setDither(boolean b):设置是否使用图像抖动处理,会使图像颜色更加平滑饱满,更加清晰;
  setFileterBitmap(Boolean b):设置是否在动画中滤掉Bitmap的优化,可以加快显示速度;
  setMaskFilter(MaskFilter mf):设置MaskFilter来实现滤镜的效果;
  setColorFilter(ColorFilter cf):设置颜色过滤器,可以在绘制颜色时实现不同颜色的变换效果;
  setPathEffect(PathEffect pe):设置绘制的路径的效果;
  setShader(Shader s):设置Shader绘制各种渐变效果;
  setShadowLayer(float r, int x, int y, int c):在图形下面设置阴影层,r为阴影角度,x和y为阴影在x轴和y轴上的距离,c为阴影的颜色;
  setStrokeJoin(Paint.Join j):设置绘制时各图形的结合方式;
  setXfermode(Xfermode m):设置图形重叠时的处理方式;

2、文本绘制:

1)  setTextAlign(Path.Align a):设置绘制的文本的对齐方式;
2)  setTextScaleX(float s):设置文本在X轴的缩放比例,可以实现文字的拉伸效果;
3)  setTextSize(float s):设置字号;
4)  setTextSkewX(float s):设置斜体文字,s是文字倾斜度;
5)  setTypeFace(TypeFace tf):设置字体风格,包括粗体、斜体等;
6)  setUnderlineText(boolean b):设置绘制的文本是否带有下划线效果;
7)  setStrikeThruText(boolean b):设置绘制的文本是否带有删除线效果;
8)  setFakeBoldText(boolean b):模拟实现粗体文字,如果设置在小字体上效果会非常差;
9)  setSubpixelText(boolean b):如果设置为true则有助于文本在LCD屏幕上显示效果;

3、其他方法:

1) getTextBounds(String t, int s, int e, Rect b):将页面中t文本从s下标开始到e下标结束的所有字符所占的区域宽高封装到b这个矩形中;
2)  clearShadowLayer():清除阴影层;
3)  measureText(String t, int s, int e):返回t文本中从s下标开始到e下标结束的所有字符所占的宽度;
4)  reset():重置画笔为默认值。

这里需要就几个方法解释一下:

1、setPathEffect(PathEffect pe):设置绘制的路径的效果:

常见的有以下几种可选方案:

1)  CornerPathEffect:可以用圆角来代替尖锐的角;
2)  DathPathEffect:虚线,由短线和点组成;
3)  DiscretePathEffect:荆棘状的线条;
4)  PathDashPathEffect:定义一种新的形状并将其作为原始路径的轮廓标记;
5)  SumPathEffect:在一条路径中顺序添加参数中的效果;
6)  ComposePathEffect:将两种效果组合起来,先使用第一种效果,在此基础上应用第二种效果。

2、setXfermode(Xfermode m):设置图形重叠时的处理方式:

关于Xfermode的多种效果,我们可以参考下面一张图:


image.png

 在使用的时候,我们需要通过paint. setXfermode(new PorterDuffXfermode(PorterDuff.Mode.XXX))来设置,XXX是上图中的某种模式对应的常量参数,如DST_OUT。

这16中情况的具体解释如下:

1.PorterDuff.Mode.CLEAR:所绘制不会提交到画布上。
2.PorterDuff.Mode.SRC:显示上层绘制图片
3.PorterDuff.Mode.DST:显示下层绘制图片
4.PorterDuff.Mode.SRC_OVER:正常绘制显示,上下层绘制叠盖。
5.PorterDuff.Mode.DST_OVER:上下层都显示。下层居上显示。
6.PorterDuff.Mode.SRC_IN:取两层绘制交集。显示上层。
7.PorterDuff.Mode.DST_IN:取两层绘制交集。显示下层。
8.PorterDuff.Mode.SRC_OUT:上层绘制非交集部分。
9.PorterDuff.Mode.DST_OUT:取下层绘制非交集部分。
10.PorterDuff.Mode.SRC_ATOP:取下层非交集部分与上层交集部分
11.PorterDuff.Mode.DST_ATOP:取上层非交集部分与下层交集部分
12.PorterDuff.Mode.XOR:异或:去除两图层交集部分
13.PorterDuff.Mode.DARKEN:取两图层全部区域,交集部分颜色加深
14.PorterDuff.Mode.LIGHTEN:取两图层全部,点亮交集部分颜色
15.PorterDuff.Mode.MULTIPLY:取两图层交集部分叠加后颜色
16.PorterDuff.Mode.SCREEN:取两图层全部区域,交集部分变为透明色

Canvas类

Canvas即画布,其上可以使用Paint画笔对象绘制很多东西。

Canvas对象中可以绘制:

1)  drawArc():绘制圆弧;
2)  drawBitmap():绘制Bitmap图像;
3)  drawCircle():绘制圆圈;
4)  drawLine():绘制线条;
5)  drawOval():绘制椭圆;
6)  drawPath():绘制Path路径;
7)  drawPicture():绘制Picture图片;
8)  drawRect():绘制矩形;
9)  drawRoundRect():绘制圆角矩形;
10) drawText():绘制文本;
11) drawVertices():绘制顶点。

Canvas对象的其他方法:

1)  canvas.save():把当前绘制的图像保存起来,让后续的操作相当于是在一个新图层上绘制;
2)  canvas.restore():把当前画布调整到上一个save()之前的状态;
3)  canvas.translate(dx, dy):把当前画布的原点移到(dx, dy)点,后续操作都以(dx, dy)点作为参照;
4)  canvas.scale(x, y):将当前画布在水平方向上缩放x倍,竖直方向上缩放y倍;
5)  canvas.rotate(angle):将当前画布顺时针旋转angle度。
其他知识点

比如,我们写状态栏中的时钟的View,在onAttachedToWindow这方法中做初始化工作,比如注册一些广播等等……

与onAttachedToWindow 相反的则是这个方法:

上一篇下一篇

猜你喜欢

热点阅读