第一篇博客中,我已经Canvas、Paint、Shader、Xfermode这些对象做了总结,而现在这篇文章主要介绍BitmapShader位图渲染,Xfermode如何实际应用,还有形状的绘制。不过本文还是只重写onDraw一个方法,像OnMeasure、OnLayout暂时不去研究,工欲善其事必先利其器嘛,先把可能用到的东西研究清楚再说。

有什么其它问题以及建议,欢迎留言。

工具类:ViewHelper(View处理常用方法封装)
安卓自定义控件(一)Canvas、Paint、Shader、Xfermode
安卓自定义控件(二)BitmapShader、ShapeDrawable、Shape
安卓自定义控件(三)自定义View

椭圆形ImageView

源码

先写一个自定义控件,鼓励一下自己。

  1. /**
  2. * ShapeDrawable对象的使用
  3. * Created by ChenSS on 2016/11/24.
  4. */
  5. public class RectView extends View {
  6. private BitmapShader mBitmapShader;
  7. private ShapeDrawable mShapeDrawable;
  8. private Bitmap mBitmap;
  9. private Paint mPaint;
  10. private int mWidth, mHeight;
  11. public RectView(Context context) {
  12. super(context);
  13. //得到图像
  14. mBitmap = ViewHelper.findBitmapById(context, R.mipmap.view_shape);
  15. //构造渲染器BitmapShader,修改TileMode可以查看效果
  16. mBitmapShader = new BitmapShader(mBitmap, Shader.TileMode.MIRROR, Shader.TileMode.REPEAT);
  17. mPaint = new Paint();
  18. mPaint.setAntiAlias(true);
  19. mPaint.setColor(Color.GRAY);
  20. mWidth = mBitmap.getWidth();
  21. mHeight = mBitmap.getHeight();
  22. }
  23. @Override
  24. protected void onDraw(Canvas canvas) {
  25. super.onDraw(canvas);
  26. //加个描边
  27. canvas.drawOval(10, 10, mWidth - 290, mHeight - 50, mPaint);
  28. //构建ShapeDrawable对象并定义形状为椭圆
  29. mShapeDrawable = new ShapeDrawable(new OvalShape());
  30. //得到画笔并设置渲染器
  31. mShapeDrawable.getPaint().setShader(mBitmapShader);
  32. //设置显示区域
  33. mShapeDrawable.setBounds(20, 20, mWidth - 300, mHeight - 60);
  34. //绘制shapeDrawable
  35. mShapeDrawable.draw(canvas);
  36. }
  37. }

在Activity使用我们的自定义View:

  1. public class RectActivity extends AppCompatActivity {
  2. @Override
  3. protected void onCreate(Bundle savedInstanceState) {
  4. super.onCreate(savedInstanceState);
  5. setContentView(new RectView(this));
  6. }
  7. }


效果似乎还不错,如果学会了重写onMeasure大概就能自定义View了吧,心里有一些小激动。

小结:

这个Demo中,我们使用到了BitmapShader,ShapeDrawable,Shader.TileMode。

  1. Shader.TileMode在上一篇博客中,我简单提了一下,它有三种模式:CLAMP(拉伸)、REPEAT(重复)、MIRROR( 镜像);
  2. BitmapShader是一个位图渲染对象,他是Shader的子类;
  3. ShapeDrawable看名字就知道,是一个用于绘制形状的对象;
  4. 我们给ShapeDrawable的参数是OvalShape,OvalShape直译就是椭圆,所以是绘制椭圆的,查看API,发现OvalShape有一个父类Shape,OvalShape应该还有其它兄弟。

所以明确我们的学习目标:Shader.TileMode平铺模式的区别;Shape有哪些子类(我们能绘制哪些形状),我们怎么使用它?如果不使用ShapeDrawable可以实现上面的效果么?

Shader.TileMode平铺模式

Shape形状对象

API说明:
Defines a generic graphical “shape.” Any Shape can be drawn to a Canvas with its own draw() method, but more graphical control is available if you instead pass it to a ShapeDrawable.

查看API发现,Shape有2个直接子类,3个间接子类,他们分别是:
PathShape, RectShape,ArcShape, OvalShape, RoundRectShape。

PathShape

多边形

上一篇博客我写了一个绘制多边形的Demo,用到了Path对象,相信机智的各位一下子就看懂了它的作用,Demo中,Path可以根据x、y值不停地画线,最后绘制出一个多边形,不过Path直译既然叫路径,肯定也能画其它线,大家可以自己研究一下。从Path的作用如此强大,PathShape肯定也不差,PathShape是一个自由度很高的、可以设置多种形状的Shape,想设计奇葩形状的时候考虑使用它(五角星、菱形、六边形等等)。

构造函数:
PathShape(path, stdWidth, stdHeight);

  • Path路径对象,来设定图形。
  • stdWidth:标准宽度
  • stdHeight:标准高度

RectShape

矩形,直接创建实例即可。
构造函数:
RectShape()

ArcShape

扇形
构造函数:
ArcShape(float startAngle, float sweepAngle)

  • startAngle:起始角度
  • sweepAngle:结束角度

OvalShape

椭圆,直接创建实例即可。
构造函数:
OvalShape()

RoundRectShape

圆角矩形,构造函数的三个参数根据需求设置,不想要可以设置为null,outerRadii和innerRadii需要长度至少为8的float类型数组,每两个float数决定了一个弧度值,一共4个弧度值,分别是: 左上、右上、右下、左下4个位置。
构造函数:
RoundRectShape(float[] outerRadii, RectF inset, float[] innerRadii)

  • outerRadii:外矩形 左上、右上、右下、左下圆角半径
  • inset:内嵌RectF矩形,4个参数为Margin
  • innerRadii:内矩形 左上、右上、右下、左下圆角半径

补充:RoundRectShape的使用Demo

因为RoundRectShape参数看起来不好理解,加一个Demo,如果不设置inset、innerRadii这两个参数,那么他就是圆角矩形了,设置之后,就像从中间挖了一个洞。

  1. /**
  2. * ShapeDrawable对象的使用
  3. * Created by ChenSS on 2016/11/24.
  4. */
  5. public class RectView extends View {
  6. private BitmapShader mBitmapShader;
  7. private ShapeDrawable mShapeDrawable;
  8. private Shape mShape;
  9. private Bitmap mBitmap;
  10. public RectView(Context context) {
  11. super(context);
  12. //得到位图
  13. mBitmap = ViewHelper.findBitmapById(context, R.mipmap.view_shape);
  14. //构造渲染器BitmapShader,修改TileMode测试效果
  15. mBitmapShader = new BitmapShader(mBitmap, Shader.TileMode.REPEAT, Shader.TileMode.REPEAT);
  16. //外矩形 左上、右上、右下、左下 圆角半径
  17. float[] outerRadii = {20, 20, 20, 20, 60, 70, 80, 200};
  18. //内矩形与外矩形的边距,左、上、右、下
  19. RectF inset = new RectF(100, 100, 200, 200);
  20. //内矩形 圆角半径
  21. float[] innerRadii = {20, 20, 20, 20, 20, 20, 20, 20};
  22. //这三个参数根据需求设置
  23. mShape = new RoundRectShape(outerRadii, inset, innerRadii);
  24. //构建ShapeDrawable对象并定义形状为圆角矩形
  25. mShapeDrawable = new ShapeDrawable(mShape);
  26. }
  27. @Override
  28. protected void onDraw(Canvas canvas) {
  29. super.onDraw(canvas);
  30. //得到画笔并设置渲染器
  31. mShapeDrawable.getPaint().setShader(mBitmapShader);
  32. //设置显示区域
  33. mShapeDrawable.setBounds(20, 20, 1000, 1000);
  34. //绘制shapeDrawable
  35. mShapeDrawable.draw(canvas);
  36. }

Xfermode实现圆形ImageView

在文章开头的小结中,我们提出了一个问题:能否不用Shape对象绘制形状,答案肯定是可以的:使用Xfermode对象。在上一篇博客中,我们简单地认识了一下Xfermode,他有18种模式可供选择,而且,我们还有了个画圆的思路,现在就来实现一下。

思路:
我们先画一个圆,然后再给他一张Bitmap,然后通过Xfermode,把Bitmap圆形的部分显示出来。

  1. /**
  2. * Xfermode对象的使用
  3. * Created by ChenSS on 2016/11/24.
  4. */
  5. public class RectView extends View {
  6. private PorterDuffXfermode xfermode;
  7. private Paint mPaint;
  8. private Bitmap mBitmap;
  9. private int mWidth, mHeight;
  10. public RectView(Context context) {
  11. super(context);
  12. //得到图像
  13. mBitmap = ViewHelper.findBitmapById(context, R.mipmap.view_shape);
  14. xfermode = new PorterDuffXfermode(PorterDuff.Mode.SRC_IN);
  15. mPaint = new Paint();
  16. mPaint.setAntiAlias(true);
  17. mPaint.setColor(Color.GRAY);
  18. mWidth = mBitmap.getWidth();
  19. mHeight = mBitmap.getHeight();
  20. }
  21. @Override
  22. protected void onDraw(Canvas canvas) {
  23. super.onDraw(canvas);
  24. //加个描边
  25. canvas.drawOval(0, 0, mWidth+10, mHeight+10, mPaint);
  26. //将绘制操作保存到新的图层(离屏缓存)
  27. int sc = canvas.saveLayer(10, 10, mWidth, mHeight, null, Canvas.ALL_SAVE_FLAG);
  28. //使用遮罩图层(画一个圆,再给一个Bitmap)
  29. canvas.drawOval(10, 10, mWidth, mHeight, mPaint);
  30. mPaint.setXfermode(xfermode);
  31. canvas.drawBitmap(mBitmap, 10, 10, mPaint);
  32. mPaint.setXfermode(null);
  33. // 还原画布
  34. canvas.restoreToCount(sc);
  35. }
  36. }

文章的排版改了又改,最后就决定这样了,文章到这里,已经把大部分的绘制方法都罗列出来了,我已经写了:Canvas(画布)、Paint(画笔)、Color(颜色)、Shader(着色器)、Shape(形状)、Xfermode(遮罩图层)。

onDraw中可能用到的东西我也就介绍到这,当然,还有类似Bitmap啊、属性动画啊、补间动画啊什么的,都介绍的话,那样篇幅就太多了。下一篇博客,我就开始介绍onMeasure方法,让我们的这些View真正投入实战。

安卓自定义控件(二)BitmapShader、ShapeDrawable、Shape的更多相关文章

  1. 安卓自定义控件(三)实现自定义View

    前面两篇博客,把View绘制的方法说了一下,但是,我们只在onDraw里面做文章,控件都是直接传入一个Context,还不能在布局文件里使用自定义View.这一篇博客,就不再讲绘制,在我们原先的基础上 ...

  2. 安卓自定义控件(一)Canvas、Paint、Shader、Xfermode

    关于自定义控件,之前就写过一篇自定义控件,上图下字的Button,图片任意指定大小,但是使用效果还是让人感觉不幸福,这次索性彻彻底底地对自定义控件做一次彻彻底底的总结. 我会花4篇博客来介绍自定义控件 ...

  3. Qt编写自定义控件二动画按钮

    现在的web发展越来越快,很多流行的布局样式,都是从web开始的,写惯了Qt widgets 项目,很多时候想改进一下现有的人机交互,尤其是在现有的按钮上加一些动画的效果,例如鼠标移上去变大,移开还原 ...

  4. android 自定义控件二之仿QQ长按删除

    自定义Dialog 1.先上个效果图:

  5. android自定义控件(二) 入门,继承View

    转载请注明地址:http://blog.csdn.net/ethan_xue/article/details/7313788 ps: 可根据apidemo里LableView,list4,list6学 ...

  6. 安卓自定义控件(五)触控基础MotionEvent

    之前去面试,人家说,我这个事件拦截机制写得太少了,还有一个MotionEvent没写,这个确实也很重要,后来我考虑了一下,决定将这篇文章放到自己定义控件里. 先简单再提一下事件分发,事件分发和拦截主要 ...

  7. 安卓自定义控件(四)实现自定义Layout

    本来我是不准备写这篇文章的,我实在想不出有什么样奇怪的理由,会去继承ViewGroup然后自定义一个布局,大概是我的项目经验还不够吧,想了好久,想到了这样一个需求: 需求 如图:在项目中经常有一个这样 ...

  8. 老猪带你玩转android自定义控件二——自定义索引栏listview

    带索引栏的listview,在android开发非常普遍,方便用户进行字母索引,就像微信通讯录这样: 今天,我们就从零到一实现这个具有索引栏的listview. 怎么实现这个控件了,我们应当梳理出一个 ...

  9. 玩转android自定义控件二——自定义索引栏listview

    带索引栏的listview,在android开发非常普遍,方便用户进行字母索引,就像微信通讯录这样: 今天,我们就从零到一实现这个具有索引栏的listview. 怎么实现这个控件了,我们应当梳理出一个 ...

随机推荐

  1. [问题记录]父元素position:relative的深坑

    个人博客迁移至:https://blog.plcent.com/欢迎大家访问 今天在写全屏切换的时候,发现一个问题就是切换时只能滚动第一屏,其他屏死都不动, 全屏滚动的原理: 是每次滚动父元素向上滚动 ...

  2. BZOJ-1045-[HAOI2008] 糖果传递(中位数原理)

    Description 有n个小朋友坐成一圈,每人有ai个糖果.每人只能给左右两人传递糖果.每人每次传递一个糖果代价为1. Input 第一行一个正整数nn<=1'000'000,表示小朋友的个 ...

  3. Maven Install指令构建时出现找不到符号

    检查引用的JRE编译的版本,可能由于JRE编译版本太低导致的  

  4. git 一口气带你走完git之旅

    1.git是目前世界上最先进的分布式版本控制系统.svn是集成式版本控制系统,那么问题来了,什么叫分布式管理和集中式管理? 首先,svn 需要有一个中央服务器,协同开发者需要同中央服务器连接,所有的版 ...

  5. svn的简介

    Svn(Subversion)是近年来崛起的版本管理工具,在当前的开源项目里(J2EE),几乎95%以上的项目都用到了SVN.Subversion项目的初衷是为了替换当年开源社区最为流行的版本控制软件 ...

  6. LeetCode 381. Insert Delete GetRandom O(1) - Duplicates allowed (插入删除和获得随机数 常数时间 允许重复项)

    Design a data structure that supports all following operations in average O(1) time. Note: Duplicate ...

  7. 编译错误:expected an indented block

    python 对缩进要求非常严格,当运行时出现以下几种情况时,就需要修改缩进: 1.expected an indented block 直接缩进4个space空格或者一个tab.

  8. Java调用C++类库--JNI

    JNI是Java平台中的一个重要的功能,这里我把我做的Demo总结一下,分享一下,我会把每个步骤尽量的详细的展现出来. 这里我就不讲解JNI的原理了,google,百度一下,到处都是 好了,直接来讲步 ...

  9. AngularJS学习篇(三)

    创建自定义的指令 除了 AngularJS 内置的指令外,我们还可以创建自定义指令. 你可以使用 .directive 函数来添加自定义的指令. 要调用自定义指令,HTML 元素上需要添加自定义指令名 ...

  10. javascript中自定义事件

    自定义事件:用户可以指定事件类型,这个类型实际上就是一个字符串,然后为这个类型的事件指定事件处理函数,可以注册多个事件处理函数(用数组管理),调用时,从多个事件处理函数中找到再调用. function ...