原文链接 :http://android.eoe.cn/topic/ui

自定义视图最重要的部分是它的外观.你可以根据应用的需求简单或复杂的实现它. 这个教程包含了最常见的操作.

重写onDraw()

绘制自定义视图里最重要的一步是重写onDraw())方法. onDraw())的参数是视图可以用来绘制自己的Canvas对象. Canvas定义用来绘制文本、线条、位图和其他图像单元. 你可以在onDraw())里使用这些方法创建你的自定义用户界面(UI).

不过, 在你调用任何绘画的方法之前, 你必须创建Paint对象. 下一章节将会探讨Paint的更多细节.

创建绘画对象


android.graphics框架把绘图分成了两部分:

  • 画什么, 由Canvas处理

  • 怎么画, 由Paint处理

例如, Canvas提供画线条的方法, 而Paint提供定义线条颜色的方法. Canvas提供画矩形的方法, 而Paint定义是否用颜色填充矩形或让它为空. 简而言之, Canvas定义你可以在屏幕上画的形状, 而Paint为你画的每个形状定义颜色、样式、字体等等.

所以, 在你画任何东西之前, 你需要创建一个或多个Paint对象. * PieChart_'(饼图)例子的'_init()* 方法里有这样的实现, 这个方法在构造函数里调用:

 123456789
10
11
12
13
14
15
16
17
18

private void init() {mTextPaint = new Paint(Paint.ANTI_ALIAS_FLAG);mTextPaint.setColor(mTextColor);if (mTextHeight == 0) {mTextHeight = mTextPaint.getTextSize();} else {mTextPaint.setTextSize(mTextHeight);}mPiePaint = new Paint(Paint.ANTI_ALIAS_FLAG);mPiePaint.setStyle(Paint.Style.FILL);mPiePaint.setTextSize(mTextHeight);mShadowPaint = new Paint(0);mShadowPaint.setColor(0xff101010);mShadowPaint.setMaskFilter(new BlurMaskFilter(8, BlurMaskFilter.Blur.NORMAL));...

提前创建对象是一个很重要的优化. 视图频繁的被重画, 并且许多绘图对象初始化需要消耗大量的资源. 在onDraw())方法里创建绘图对象会严重降低性能, 并可以让你的UI显得有些迟钝.

处理布局事件


为了正确的绘制你的自定义视图, 你需要知道它的大小. 复杂的自定义视图经常需要根据它的大小和在屏幕上的图形区域执行多次布局计算. 你永远不应该假设视图在屏上的大小. 即使只有一个应用使用你的视图, 应用也需要处理不同的屏幕尺寸, 多种屏幕分辨率, 以及在横屏和竖屏模式下的各种高宽比.

虽然View有很多处理尺寸大小的方法, 但是大部分的需要重写. 如果你的视图不需要特别控制它的大小, 你只需要重写方法: onSizeChanged() .

onSizeChanged()在你的视图第一次分配大小的时候调用, 如果你的视图因为任何原因改变了大小也会再次调用. 在该方法里计算位置、大小和其他一些与视图大小相关的值, 而不是你每次绘制的时候重新计算. 在PieChart(饼图)例子里, PieChar视图在onSizeChanged()里计算饼图的图形边界、文本标签的相对位置和其他视觉元素.

当你的视图分配了一个大小, 布局管理器会假设这个大小包含了所有视图的padding值. 你必须在计算你视图的大小的时候处理padding值. 下面是PieChart.onSizeChanged()中处理这个的代码片段:

 123456789
10
11
12

// Account for paddingfloat xpad = (float)(getPaddingLeft() + getPaddingRight());float ypad = (float)(getPaddingTop() + getPaddingBottom());// Account for the labelif (mShowText) xpad += mTextWidth;float ww = (float)w - xpad;float hh = (float)h - ypad;// Figure out how big we can make the pie.float diameter = Math.min(ww, hh);

如果你需要出色的控制你视图的布局参数, 实现int) onMeasure()方法. 这个方法的参数是View.MeasureSpec值, 这个会告诉你你的视图的父元素想让你的视图有多大, 并且告诉你这个大小是否是最大值或只是一个建议. 作为优化, 这些值保存为整数的封装类型, 你可以用View.MeasureSpec里的静态方法解析每个整数里面的信息.

下面是实现int) onMeasure()的例子. 在这个实现里面, PieChart尝试让它的面积大小足以让饼图可以标签一样大:

 123456789
10
11
12
13

@Override
protected void onMeasure(int widthMeasureSpec, int heightMeasureSpec) {// Try for a width based on our minimumint minw = getPaddingLeft() + getPaddingRight() + getSuggestedMinimumWidth();int w = resolveSizeAndState(minw, widthMeasureSpec, 1);// Whatever the width ends up being, ask for a height that would let the pie// get as big as it canint minh = MeasureSpec.getSize(w) - (int)mTextWidth + getPaddingBottom() + getPaddingTop();int h = resolveSizeAndState(MeasureSpec.getSize(w) - (int)mTextWidth, heightMeasureSpec, 0);setMeasuredDimension(w, h);
}

在这段代码中有三个重点需要注意:

    • 计算需要考虑视图的padding. 如上所述, 这个是视图的职责.
    • 方法resolveSizeAndState()用来创建最终的宽和高. 这个方法通过比较视图的期望大小返回一个合适的View.MeasureSpec值传入int) onMeasure()
    • onMeasure()方法没有返回值. 相反, 这个方法通过调用int) setMeasureDismension()方法传递结果. 调用这个方法是强制的. 如果你省略这个, View类会抛出runtime exception

绘图


一旦你有了创建的对象和定义了测绘布局的代码, 你可以实现方法onDraw()) . 每个视图实现不同的onDraw()) , 但是这里有些大多数视图常用的操作:

  • 使用drawText()画文本, setTypeface())指定字体, setColor())指定文本颜色

  • 画基本的形状用drawRect()) 、drawOval()) 、drawArc()) . 不论改变图形的填充样式还是边框样式还是都修改, 都是调用setStyle())

  • 绘制复杂的形状用Path类. 通过给Path对象增加线条和曲线定义形状, 然后使用drawPath())绘制形状. 就像基本的形状一样, Path可以设置填充样式、边框样式、或者都设置, 都依靠setStyle())

  • 定义渐变的填充样式通过创建LinearGradient对象. 在要填充的形状上通过调用setShader())使用LinearGradient对象

  • 绘制位图使用drawBitmap()) .

例如, 这是是画PieChart的代码. 它混合使用了文本、线条、图形.

 123456789
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26

protected void onDraw(Canvas canvas) {super.onDraw(canvas);// Draw the shadowcanvas.drawOval(mShadowBounds,mShadowPaint);// Draw the label textcanvas.drawText(mData.get(mCurrentItem).mLabel, mTextX, mTextY, mTextPaint);// Draw the pie slicesfor (int i = 0; i < mData.size(); ++i) {Item it = mData.get(i);mPiePaint.setShader(it.mShader);canvas.drawArc(mBounds,360 - it.mEndAngle,it.mEndAngle - it.mStartAngle,true, mPiePaint);}// Draw the pointercanvas.drawLine(mTextX, mPointerY, mPointerX, mPointerY, mTextPaint);canvas.drawCircle(mPointerX, mPointerY, mPointerSize, mTextPaint);
}

转载于:https://www.cnblogs.com/vus520/archive/2013/06/09/3129451.html

【eoe教程】Android中自定义视图的绘制方法相关推荐

  1. Android中自定义视图View

    标签: 前言 好长时间没写blog了,心里感觉有点空荡荡的,今天有时间就来写一个关于自定义视图的的blog吧.关于这篇blog,网上已经有很多案例了,其实没什么难度的.但是我们在开发的过程中有时候会用 ...

  2. Android中自定义视图View之---前奏篇

    前言 好长时间没写blog了,心里感觉有点空荡荡的,今天有时间就来写一个关于自定义视图的的blog吧.关于这篇blog,网上已经有很多案例了,其实没什么难度的.但是我们在开发的过程中有时候会用到一些自 ...

  3. android sqlite自定义函数,Android中自定义一个View的方法详解

    本文实例讲述了Android中自定义一个View的方法.分享给大家供大家参考,具体如下: Android中自定义View的实现比较简单,无非就是继承父类,然后重载方法,即便如此,在实际编码中难免会遇到 ...

  4. Android中贝塞尔曲线的绘制方法

    贝塞尔曲线,很多人可能不太了解,什么叫做贝塞尔曲线呢?这里先做一下简单介绍:贝塞尔曲线也可以叫做贝济埃曲线或者贝兹曲线,它由线段与节点组成,节点是可拖动的支点,线段像可伸缩的皮筋.一般的矢量图形软件常 ...

  5. Android中自定义view的onMeasure()方法详谈

    背景 理解MeasureSpec MeasureSpec 情况分析 结合图例分析 总结 A little bit of progress every day!Come on! 背景 首先关于自定义vi ...

  6. Android Studio自定义视图无法预览

    Android Studio自定义视图没有办法预览 我想大家应该都和我一样,如果看到布局的编码的时候如果右边能够非常直观地显示出对应的视图,心里会非常舒心,像官方提供的tools命名空间就是为了这个目 ...

  7. Android 中自定义View 裁剪扇形图片

    Android 中自定义View 裁剪扇形图片 当需要裁剪图片为扇形区域时,使用Canvas.clipPath(path)方法可以裁剪为扇形区域 ps:此方法会导致绘制图片边缘有锯齿,暂无解决方法(知 ...

  8. android 自定义弹窗diss,Android中自定义PopupWindow,动态弹窗。

    我的第一篇博客,咱们直奔主题.先上个效果图 在android中自定义PopupWindow: 1.首先定义好你想要显示的窗口的布局文件,再实例化一个View对象:窗口布局可灵活变化,dialog_la ...

  9. android 自定义进度条_第一百八十九回:Android中自定义ProgressBar三

    各位看官们大家好,上一回中咱们说的是Android中自定义ProgressBar的例子,这一回咱们继续说该例子.闲话休提,言归正转.让我们一起Talk Android吧! 看官们,我们在上一回是通过自 ...

最新文章

  1. window使用笔记
  2. C typedef功能介绍(内附函数指针和指针函数的区别)
  3. mysql创建表时遇到的问题_MySQL语言创建表时遇到了问题,请问我错在哪里了?...
  4. F - 阿汤的疑惑(模拟取余+分解质因数)
  5. jquery与ajax的XMLHttpRequest对象介绍
  6. java.lang.String cannot be cast to org.apache.flink.table.data.StringData
  7. python 爬取贝壳网小区名称_如何使用 python 爬取全国小区名称
  8. 宝塔linux 做负载均衡,利用BT宝塔面板做网站多服务器负载均衡图文教程
  9. Java 文件流操作.,互联网 面试官 如何面试
  10. ios charts显示固定个数_上次挂在了百度iOS二面不服气, 三月之期已到,这次终于拿下offer!...
  11. 51单片机c语言头文件大全,单片机stc89(STC89C52,C51)系列头文件.doc.doc
  12. css3 浪花,掘金:Canvas 实现画中画动画效果--网易娱乐年度盘点H5动画解密
  13. 116.填充同一层的兄弟节点
  14. 视频 |【2019】Power BI 8月产品功能更新讲解
  15. Opencv的使用教程,opencv比较全的基础教程
  16. linux raid卡驱动添加到内核,CentOS安装RAID卡驱动总结
  17. 压力换算公斤单位换算_压力与重量换算(公斤换算压力)
  18. Python爬虫搜索全网音乐并下载
  19. 小象学院python数据分析课程怎么样_小象学院大数据分析集训营试听知识点整理-正则表达式...
  20. Steaming SQL for Apache Kafka 学习

热门文章

  1. 我的第一篇博客,以此写写内心的独白
  2. jquery 验证控件
  3. ZOJ Monthly, January 2013
  4. Mac+docker+flask
  5. TRIZ系列-创新原理-23-反馈原理
  6. 【dmp文件还原到oralce数据库】
  7. BZOJ1409 : Password
  8. struts2 ibatis Spring系统架构图
  9. javascript基础整理
  10. 设计模式-UML图简单介绍