博客
关于我
强烈建议你试试无所不能的chatGPT,快点击我
创建自定义控件2-自定义绘制
阅读量:4207 次
发布时间:2019-05-26

本文共 4326 字,大约阅读时间需要 14 分钟。

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

重写onDraw()

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

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

创建绘画对象


框架把绘图分成了两部分:

  • 画什么, 由处理

  • 怎么画, 由处理

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

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

1 2 3 4 5 6 7 8 9101112131415161718
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)); ...

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

处理布局事件


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

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

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

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

1 2 3 4 5 6 7 8 9101112
// Account for padding       float xpad = (float)(getPaddingLeft() + getPaddingRight());       float ypad = (float)(getPaddingTop() + getPaddingBottom());       // Account for the label       if (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()](http://docs.eoeandroid.com/reference/android/view/View.html#onMeasure(int,)方法. 这个方法的参数是值, 这个会告诉你你的视图的父元素想让你的视图有多大, 并且告诉你这个大小是否是最大值或只是一个建议. 作为优化, 这些值保存为整数的封装类型, 你可以用里的静态方法解析每个整数里面的信息.

下面是实现[int) onMeasure()](http://docs.eoeandroid.com/reference/android/view/View.html#onMeasure(int,)的例子. 在这个实现里面, PieChart尝试让它的面积大小足以让饼图可以标签一样大:

1 2 3 4 5 6 7 8 910111213
@Overrideprotected void onMeasure(int widthMeasureSpec, int heightMeasureSpec) {
// Try for a width based on our minimum int 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 can int 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()方法传递结果. 调用这个方法是强制的. 如果你省略这个, 类会抛出runtime exception

绘图


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

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

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

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

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

  • 绘制位图使用 .

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

1 2 3 4 5 6 7 8 91011121314151617181920212223242526
protected void onDraw(Canvas canvas) {
super.onDraw(canvas); // Draw the shadow canvas.drawOval( mShadowBounds, mShadowPaint ); // Draw the label text canvas.drawText(mData.get(mCurrentItem).mLabel, mTextX, mTextY, mTextPaint); // Draw the pie slices for (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 pointer canvas.drawLine(mTextX, mPointerY, mPointerX, mPointerY, mTextPaint); canvas.drawCircle(mPointerX, mPointerY, mPointerSize, mTextPaint);}

转载地址:http://cxlli.baihongyu.com/

你可能感兴趣的文章
科目二难点——倒车入库
查看>>
离合器 油门 刹车使用要领
查看>>
科目二考试
查看>>
离合器怎么踩 离合器的使用技巧
查看>>
科目二倒车入库学车技巧_学车必看_保过。
查看>>
怎么判断30公分?看我的图文传教就清楚了
查看>>
科目二经验之谈 10小时必过秘笈
查看>>
上海科目二经验总结
查看>>
科目二曲线行驶考试技巧
查看>>
图解侧方停车技巧2015高清版
查看>>
一看就会的侧方位停车技巧 见了就收了吧
查看>>
驾校学车,科目二坡路定点停车和起步操作技巧!
查看>>
车位置判断
查看>>
新规曲线行驶的图解技巧
查看>>
Freeform SQL (FFSQL) - Tip - How to create TEMP(Temporary) tables
查看>>
北大发布全国最好医院排名,详细到科室,关键救命
查看>>
上海2014科目二注意事项及经验浅谈(龙泉驾校)
查看>>
2016科目三满分通过,经验分享!
查看>>
汽车档位和速度关系
查看>>
c#读书笔记,与大家分享
查看>>