体育直播网站制作开发,seo教程网站优化推广排名,深圳百度推广优化,竞价单页制作教程原文地址#xff1a;http://android.xsoftlab.net/training/custom-views/custom-drawing.html#draw
自定义View最重要的部分就是它的样子了。自定义View的绘制根据应用的需要或者简单亦或者复杂。这节课的内容涵盖了大多数通用的知识点。
重写onDraw()方法
绘制自定义View…原文地址http://android.xsoftlab.net/training/custom-views/custom-drawing.html#draw
自定义View最重要的部分就是它的样子了。自定义View的绘制根据应用的需要或者简单亦或者复杂。这节课的内容涵盖了大多数通用的知识点。
重写onDraw()方法
绘制自定义View很重要的一个步骤就是重写它的onDraw()方法。该方法含有一个Canvas对象作为参数用来使View绘制它本身的内容。Canvas类定义了用于绘制文本线条位图以及许多其它基础的物理图形的方法。你可以在onDraw()方法中使用这些方法来创建属于你自己的UI效果。
在开始任何绘制之前必须先创建一个Paint对象。后面的部分会讨论Paint的相关知识。
创建绘制对象
android.graphics框架将绘制分为了两块区域
要绘制什么由Canvas控制如何绘制由Paint控制
举个例子Canvas提供了用于绘制线条的方法而Paint则定义了线条的颜色。Canvas拥有绘制矩形的方法而Paint则定义了是否要使颜色填充这个矩形。简而言之Canvas定义了你绘制在屏幕上的形状而Paint则定义了这些形状的颜色、风格以及字体等等。
所以在开始绘制任何事物之前你需要先创建一个或多个Paint对象。示例PieChart将这些工作放在了一个名为init的方法中它由构造方法调用
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));...
提前创建对象是一项非常重要的优化手段。View会很频繁的绘制创建绘制对象的开销十分高昂。在onDraw()方法中创建绘制对象会明显的降低应用的性能并可能会导致UI出现停顿。
处理布局事件
为了可以正确的绘制View首先需要知道View的尺寸。复杂一点的View经常需要执行多次布局计算。你永远不要假定View的尺寸就算是只有一款应用使用了你的View。因为APP需要处理不同的屏幕尺寸不同的屏幕密度以及在垂直模式及水平模式下不同的高宽比。
尽管View拥有很多测量尺寸的方法但是绝大多数是不需要重写的。如果View不需要特别控制它的尺寸你只需要重写一个方法onSizeChanged().
onSizeChanged()方法会在首次分配尺寸的时候调用如果尺寸再次变更时则会再次调用。我们在onSizeChanged()方法中计算View的位置、尺寸以及其它任何与尺寸相关的值而不是在每次绘制的时候重新计算它们。在示例PieChart中onSizeChanged()方法内部计算了饼图的矩形边框以及文本和其它可视元素的相对位置。
当View被分配了一个尺寸时布局管理器会假设该尺寸包含了View所有的内边距。所以在计算View的尺寸时要将View的内边距计算在内。下面的代码段展示了PieChart.onSizeChanged()是如何做的 // 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);
如果你想更精细的控制View布局的参数请实现onMeasure()方法。这个方法的两个参数都为View.MeasureSpec。它们用于告诉View的父布局希望View是多大这个View的尺寸是最大值还是只是一个建议值等等。随着优化这些值被存放在一个被包装后的整型值内你必须使用View.MeasureSpec的一个静态方法来提取存储在这个整型值内的信息。
下面是onMeasure()方法的一个示例。在这个实现中PieCart尝试将自己的区域扩大到内部标签的大小。
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);
}
这里有三个非常重要的点需要关注
这个公式将View的内边距一并计算在内。正如前面所说的这是View本身的职责。辅助方法resolveSizeAndState()用于创建最终的宽度值与高度值。这个辅助方法通过比较View的期望值与onMeasure()回调的spec值最后返回一个适当的View.MeasureSpec值。onMeasure()没有返回值。相反的该方法通过调用setMeasuredDimension()方法与外界交流。调用这个方法是强制要求的。如果你忽略了这个调用那么View类会抛出一个运行时异常。
绘制
完成对象创建代码与尺寸测量代码之后接下来就可以实现onDraw()方法了。每个View的onDraw()方法都不相同但是它们还是有一些相同特点存在的
使用drawText()方法绘制文本。通过setTypeface()方法指定字体类型通过setColor()方法设置文本颜色。通过drawRect()、drawOval()和drawArc()绘制基础图形。通过setStyle()更改图形是填充模式还是绘制轮廓模式或者两者都不是。通过Path类来绘制更加复杂的图形。通过给Path对象添加线条及曲线来定义形状然后通过drawPath()方法绘制这些形状。只是这些基础形状可以通过setStyle()方法来定义它们的Path风格。通过创建LinearGradient对象可以定义梯度填充模式。调用setShader()方法来填充形状。通过drawBitmap()方法绘制位图。
举个例子下面的代码用来绘制PieChart。它混合使用了文本、线条以及形状。
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);
}