自定义绘制
自定义视图最重要的一件事是怎么让它在视图界面上显现,自定义绘制的复杂程度取决于你的应用的要求,下面我们来看看具体的步骤
覆写onDraw()方法
覆写onDraw()方法是绘制自定义视图的最重要的一步,onDraw()方法中的参数是一个
Canvas 对象,视图可以使用
Canvas 对象来绘制自己,
Canvas 类定义了一些方法用来绘制文本、线条、图片和许多其它的图元,你可以在onDraw()方法中使用这些方法来创建你自定义视图的界面,在你能够调用任何绘制方法前,你需要先创建一个
Paint
对象
创建绘制对象
所以,当你绘制任何东西之前,你需要创建一个或多个
Paint 对象
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()方法里去创建那些绘制对象,意味着程序性能的降低和缓慢的运行速度,所以你可以在View创建的时候去初始化那些绘制对象,而不要在onDraw()方法中
处理布局事件
为了正确的绘制我们自定义的视图,我们需要知道视图准确的大小,复杂的自定义视图经常需要在知道视图大小和形状的基础上进行一些复杂的计算,你永远不要去估量你的视图在屏幕上显示的大小,即使你自定义的视图只被一个应用使用,因为那个应用也需要处理不同屏幕大小的设备,多种屏幕密度和在横屏、竖屏模式下的各种横竖屏比率
尽管视图有很多方法来处理测量,当大多数你都不用进行覆写重新实现,如果你的视图不需要特殊的去控制大小,那么你只需要覆写
onSizeChanged() 一个方法
当你的视图分配了一个大小,布局管理器会假设你的视图大小包含了所有的填充区(上下左右),当你计算视图的大小时你必须处理填充区的大小值
// 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);
如果你想很好的控制你的视图的布局参数,需要实现覆写
onMeasure() ,从中我们可以得知自定义视图的父类控件期望我们的视图要显示成什么样和我们的视图大小的最大值或一个建议值,因为优化,传递给我们的信息被包装成了一个整数值,需要使用
View.MeasureSpec 来进行解包获取其中实际值
@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);}
需要注意的三点:
1、大小的计算考虑到了视图的填充区大小,正如前面说的,这个是视图的义务
绘制
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);}
|