Android自定义View教程(二)
来源:互联网 发布:金山数据恢复手机版 编辑:程序博客网 时间:2024/04/30 10:45
自定义绘图
自定义View最重要的一部分就是它的外观了。自定义绘图可以使简单的,也可以是复杂的,这取决于你的应用需求。这篇教程将包含一些最常用的操作。
覆写 onDraw()
绘制自定义View最重要的一步就是覆写onDraw()
方法。Ondraw()
方法的参数是一个可以用于绘制自身的canvas
对象。Canvas
定义了很多绘制方法,比如:Text, lines, bitmaps,还有一些其他的显示基类。你能够在onDraw()
中使用这些方法来创建你的自定义UI。
在你调用任何一个绘制方法之前,你必须创建一个Paint
对象。下一个章节将会更加详细地讨论Paint
。
创建绘制对象
android.graphics
框架被分为了两部分:
- 绘制什么,由
Canvas
来操作 - 怎样绘制,由
Paint
来操作
具体来说,Canvas
提供绘制line的方法,而Paint
来提供line的颜色定义。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));
提前创建对象是一种很重要的优化方式。Views会经常重绘,并且很多绘制对象需要很繁重的初始化。在onDraw()
中创建绘制对象会显著地降低性能,让你的UI变得很缓慢。
处理Layout事件
为了适当地绘制你的自定义view,你需要知道它的size有多大。复杂的自定义view经常会需要执行多次layout计算,者取决于它们屏幕区域的大小,形状。你永远也不要去假设你的view在屏幕上的大小,即使只有一个APP使用你的view。这个APP需要处理不同的屏幕大小,不同的屏幕密度,以及各种多样的比例和landscape模式。
即使View有很多方法来处理测量过程,它们其中的绝大部分不需要覆写。加入你的view不需要特别去控制它的大小,你只需要覆写一个方法onSizeChanged()
。
onSizeChanged()
在你的view第一次被分配大小的时候调用,并且在你的view大小因为任何原因发生了变化的时候再一次调用。你可以在onSizeChanged()
中计算你的view的位置,尺寸以及其他任何和你的view大小有关系的值。,不同于在你每次绘制的时候重新计算,在PieChart这个例子中,onSizeChanged()
才是计算这些的地方。
当你的view被分配了大小的时候,Layout管理器会假定大小包含了所有的view的padding值。你必须处理你的padding值,在你计算你的view的大小的时候。以下的代码块是来自PieChart.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);
假如你需要更好地去控制你的view的Layout参数,那么实现onMeasure()
方法。这个方法的参数是View.MeasureSpec
,这是用来告诉你,你的view的父类希望你的view是多大,和这个大小是真正的最大值还是建议值。作为一种优化,这些值被打包储存在了integer之中,你需要使用静态方法View.MeasureSpec
去解包出存储在每一个Integer中的信息。
以下是一个实现了onMeasure()
的例子,在这个实现中,PieChart 企图让它的大小足够大以此让pie达到和它的标签中所描述的设定的大小:
@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);}
在以上的代码中有几个值得注意的东西:
- 计算中包含了view的padding值,就和前面所提到的那样,这是一个view的责任。
- 辅助类
resolveSizeAndState()
用来创建最终的宽,高值。这个辅助类通过比较view在onMeasure()
中想要的大小返回了一个适当的View.MeasureSpec
值。 onMeasure()
并没有返回值,相对地,这个方法调用了setMeasuredDimension()
以用来传递它的结果值。这个方法的调用时强制性的,如果你忽略了这个调用,那么,view类将会抛出运行时异常。
Draw!
一旦你定义好了你的对象的创建以及测量代码,你就能实现 onDraw()
.每个view的onDraw()
实现都不相同,但是在它们之间还是有一些相同的操作的,绝大部分view都会这么做:
- 使用
drawText()
来绘制text.用setTypeface()
来指定字体,用setColor()
来指定text的颜色。 - 原始的形状绘制使用
drawRect()
,drawOval()
,drawArc()
。用setStyle()
来改变形状是否填充,轮廓。 - 用
LinearGradient
对象来定义梯度值,调用setShader()
来使用你定义的梯度值到你定义的形状中去。 - 用
drawBitmap()
来绘制Bitmap。
举个例子吧,以下的代码是用来进行绘制的:
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);}
- Android自定义View教程(二)
- Android 自定义View (二)
- Android 自定义View (二)
- Android 自定义View (二)
- Android 自定义View (二)
- android 自定义view二
- Android自定义View(二)
- Android 自定义View 二
- Android 自定义View教程(一)
- Android自定义View教程(三)
- Android自定义View教程(四)
- Android 自定义View (二) 进阶
- Android 自定义View (二) 进阶
- Android 自定义View (二) 进阶
- Android 自定义View (二) 进阶
- android自定义View(二)
- Android 自定义View (二) 进阶
- Android 自定义View (二) 进阶
- 数据结构1
- Maven+Nexus+Myeclipse集成
- Android 自定义View教程(一)
- python爬虫入门之爬取贴吧标题
- [JS]删除链表的重复结点2
- Android自定义View教程(二)
- VS2010连接MySQL数据库的平台搭建(C/C++)
- Android自定义View教程(三)
- 计算机视觉、机器学习相关领域论文和源代码大集合
- iOS 10 UICollectionView 性能优化
- Android自定义View教程(四)
- 技术技能树
- iOS 键盘通知(NSNotificationCenter)正确使用
- 既感叹开发都的聪明智慧的同时也激励着自己不断学习新事物