前言
曾经看过大牛任玉刚的一篇博客--Android学习路线指南,里面把自定义View定位到中级开发工程师应该掌握的技能之一。我说实话就在两三个月前吧,也已经搞android开发近两年了,但是一直没有真正意义上做过自定义view。其实开发时候就是只要实现功能就行了,所以就做过简单的组合自定义 view。面试的时候面试官要的是那种做过自己绘制,计算显示特殊效果的自定义 view,没做过不好意思只能把你定位到初级菜鸟,回去等通知吧,如果可以我们人事会给你打电话的。
然后我就开始学习自定义 view这一块,学习自定义view就像是学游泳学骑自行车。开始时感觉挺复杂,让人望而生畏。但是你一旦学会就会感觉自定义view没什么,难度也就那样。而且学成后的喜悦是难于言表的,就像是你第一次学会自行车,一个人在小路上自由自在的骑了好远那样。。。
自定义view
一旦学会自定义view,你就感觉自己掌握了游戏里的一个技能,可以随时发大招。下面是我使用自定义view实现的几个效果:
第一个显示字幕view,模仿一步影片里字幕那种向上斜飞而过的效果。这个代码在我的另一篇博客:博客链接
第二个是做过一个购物车的加减数量的view,就是我们使用饿了么或者小米商城上买东西时可以点击加号,减号然后数字变动的效果,下图为小米商城的效果
第三个是卡券View,这是跟着着别人的开源项目写的
第四个是显示订单的执行步骤的view,例如,下单-付款-出货-收货完成
牛刀小试
其实自定义view就像绘画,绘图,我们可以拿绘图做比较。比如我们需要先准备画笔,颜料,一张白纸。比如你想画一个红色的圆,在现实生活中,也许你需要一个圆规先做一个圆,然后使用画笔蘸一些红色颜料往里面描就行了,就可以描一个红色的圆。但是在Android里面也许更简单。
画圆
Paint circlePaint;//红色圆画笔
Paint bluePaint;//蓝色圆画笔
//初始化
private void init(Context context) {
circlePaint=new Paint();
bluePaint=new Paint();
bluePaint.setColor(Color.BLUE);
// 抗锯齿
bluePaint.setAntiAlias(true);
circlePaint.setColor(Color.RED);
}
在onDraw(Canvas canvas)方法里面,执行画操作,其中(100,100)是圆心坐标,30是半径,circlePaint是画笔
/**
* Draw the specified circle using the specified paint. If radius is <= 0,
* then nothing will be drawn. The circle will be filled or framed based
* on the Style in the paint.
*
* @param cx The x-coordinate of the center of the cirle to be drawn
* @param cy The y-coordinate of the center of the cirle to be drawn
* @param radius The radius of the cirle to be drawn
* @param paint The paint used to draw the circle
*/
public void drawCircle(float cx, float cy, float radius, @NonNull Paint paint) {
native_drawCircle(mNativeCanvasWrapper, cx, cy, radius, paint.getNativeInstance());
}
然后我们看一下canvas.drawCircle(float cx, float cy, float radius, @NonNull Paint paint)方法的源码里面的参数都是什么,看上面cx,cy分别为圆心的坐标x,y。radius为圆半径,paint是画圆的画笔
canvas.drawCircle(100,100,30,circlePaint);
canvas.drawCircle(220,100,50,bluePaint);
写文字
下面先画一个矩形,然后在里面写文字,效果如下:
实现这样的效果,就是先画一个矩形,然后写文字
Paint rectPaint;//矩形画笔
Paint textPaint;//文本画笔
rectPaint=newPaint();
rectPaint.setColor(Color.GRAY);
textPaint=newPaint();
textPaint.setAntiAlias(true);
textPaint.setColor(Color.BLUE);
textPaint.setTextSize(20);
canvas.drawRect(100,100,400,300,rectPaint);
canvas.drawRect(100,100,400,300,rectPaint);
还可以让文字居中显示,居中显示就比较复杂了,需要我们计算文字应该放置的位置,要实现计算我们需要一个Rect,这里也许你知道画笔是Paint,颜色是color,画布是canvas,可是这个Rect是什么鬼,可以先不要管它,只需要知道这里它怎么使用的就行,以后可以深入。学习程序开发就是这样,你要是想对每个类都刨根问底,你会发现你寸步难行,有些东西可以先不去管,等到后就回也许前面的就都豁然开朗,添加的代码如下:
private Rect textBound;//用于计算文本的宽高
//在初始化画笔的时候初始化Rect
textBound=new Rect();
//画图
canvas.drawRect(100,100,400,300,rectPaint);
String str="我是文字!";
textPaint.getTextBounds(str,0,str.length(),textBound);
canvas.drawText(str,250-textBound.width()/2,200+textBound.height()/6,textPaint);
我解释一下是怎么计算的,首先我已经画了一个矩形,然后我就知道矩形的中心点x坐标是(400+100)/2=250,这时文字的宽是通过textBound得到为textBound.width(),所以文字的开始文字x坐标就是250-textBound.width()/2,然后再说y坐标,矩形中心的y坐标是(300+100)/2=200;文字的高是textBound.height(),按道理说,这时文字的中心点坐标应该是200-textBound.height()/2,但是请看下面drawText()的方法源码,这个y让传递的是@param y The y-coordinate of the baseline of the text being drawn,这里的baseline就是相当于汉语拼音本上写四条线的第三条线。所以这个y参数应该传递的是200+textBound.height()/6
/**
* Draw the text, with origin at (x,y), using the specified paint. The
* origin is interpreted based on the Align setting in the paint.
*
* @param text The text to be drawn
* @param x The x-coordinate of the origin of the text being drawn
* @param y The y-coordinate of the baseline of the text being drawn
* @param paint The paint used for the text (e.g. color, size, style)
*/
public void drawText(@NonNull String text, float x, float y, @NonNull Paint paint) {
native_drawText(mNativeCanvasWrapper, text, 0, text.length(), x, y, paint.mBidiFlags,
paint.getNativeInstance(), paint.mNativeTypeface);
}
上面都是一些基础的实例,实际开发中肯定不会这么简单。但是原理都是相通的,只不过也许你要多定义几个画笔,计算上更加复杂,有的甚至计算过于复杂要关心对性能的影响等等
下面我会照着一个的View完整的实现过程写一篇文章--Android自定义View之总结二