1 背景 前面分析那么多系统源码了,也该暂停下来休息一下,趁昨晚闲着看见一个有意思的需求就操练一下分析源码后的实例演练—-自定义控件。
这个实例很适合新手入门自定义控件。先看下效果图:
横屏模式如下:
竖屏模式如下:
看见没有,这个控件完全自定义的,连文字等都是自定义的,没有任何图片等资源,就仅仅是一个小的java文件,这个界面只有一个控件。如下咱们看下实现代码。
!!!!!!! 下载Demo工程源码点击我
【工匠若水 http://blog.csdn.net/yanbober 转载烦请注明出处,尊重分享成果】
2 实例代码 如下就是整个工程的源码了。
自定义上面展示的控件AreaChartsView源码:
`<span class="hljs-javadoc">/** * Author : yanbo * Date : 2015-06-03 * Time : 09:22 * Description : 自定义区域描述图表View */</span> <span class="hljs-keyword">public</span> <span class="hljs-class"><span class="hljs-keyword">class</span> <span class="hljs-title">AreaChartsView</span> <span class="hljs-keyword">extends</span> <span class="hljs-title">View</span> {</span> <span class="hljs-keyword">private</span> Paint mPaint; <span class="hljs-keyword">private</span> <span class="hljs-keyword">int</span>[] mZeroPos = <span class="hljs-keyword">new</span> <span class="hljs-keyword">int</span>[<span class="hljs-number">2</span>]; <span class="hljs-keyword">private</span> <span class="hljs-keyword">int</span>[] mMaxYPos = <span class="hljs-keyword">new</span> <span class="hljs-keyword">int</span>[<span class="hljs-number">2</span>]; <span class="hljs-keyword">private</span> <span class="hljs-keyword">int</span>[] mMaxXPos = <span class="hljs-keyword">new</span> <span class="hljs-keyword">int</span>[<span class="hljs-number">2</span>]; <span class="hljs-keyword">private</span> <span class="hljs-keyword">int</span> mWidth, mHight; <span class="hljs-keyword">private</span> <span class="hljs-keyword">int</span> mRealWidth, mRealHight; <span class="hljs-keyword">private</span> String mTitleY, mTitleX; <span class="hljs-keyword">private</span> ArrayList<Integer> mXLevel = <span class="hljs-keyword">new</span> ArrayList<>(); <span class="hljs-keyword">private</span> ArrayList<Integer> mYLevel = <span class="hljs-keyword">new</span> ArrayList<>(); <span class="hljs-keyword">private</span> ArrayList<String> mGridLevelText = <span class="hljs-keyword">new</span> ArrayList<>(); <span class="hljs-keyword">private</span> ArrayList<Integer> mGridColorLevel = <span class="hljs-keyword">new</span> ArrayList<>(); <span class="hljs-keyword">private</span> ArrayList<Integer> mGridTxtColorLevel = <span class="hljs-keyword">new</span> ArrayList<>(); <span class="hljs-keyword">private</span> <span class="hljs-keyword">int</span> mGridLevel = mXLevel.size() - <span class="hljs-number">1</span>; <span class="hljs-comment">//title字符大小</span> <span class="hljs-keyword">private</span> <span class="hljs-keyword">int</span> mXYTitleTextSize = <span class="hljs-number">40</span>; <span class="hljs-keyword">private</span> <span class="hljs-keyword">int</span> mMeasureXpos, mMeasureYpos; <span class="hljs-keyword">public</span> <span class="hljs-title">AreaChartsView</span>(Context context, AttributeSet attrs) { <span class="hljs-keyword">super</span>(context, attrs); mPaint = <span class="hljs-keyword">new</span> Paint(Paint.ANTI_ALIAS_FLAG); mPaint.setAntiAlias(<span class="hljs-keyword">true</span>); mPaint.setFilterBitmap(<span class="hljs-keyword">true</span>); } <span class="hljs-annotation">@Override</span> <span class="hljs-keyword">protected</span> <span class="hljs-keyword">void</span> <span class="hljs-title">onLayout</span>(<span class="hljs-keyword">boolean</span> changed, <span class="hljs-keyword">int</span> left, <span class="hljs-keyword">int</span> top, <span class="hljs-keyword">int</span> right, <span class="hljs-keyword">int</span> bottom) { <span class="hljs-keyword">super</span>.onLayout(changed, left, top, right, bottom); mWidth = getWidth(); mHight = getHeight(); } <span class="hljs-annotation">@Override</span> <span class="hljs-keyword">protected</span> <span class="hljs-keyword">void</span> <span class="hljs-title">onDraw</span>(Canvas canvas) { <span class="hljs-keyword">super</span>.onDraw(canvas); initPosition(); drawXYTitle(canvas); drawXYLine(canvas); drawContent(canvas); } <span class="hljs-keyword">private</span> <span class="hljs-keyword">void</span> <span class="hljs-title">initPosition</span>() { <span class="hljs-comment">//初始化坐标图的xy交点原点坐标</span> mZeroPos[<span class="hljs-number">0</span>] = mXYTitleTextSize * <span class="hljs-number">2</span>; mZeroPos[<span class="hljs-number">1</span>] = mHight - mXYTitleTextSize * <span class="hljs-number">4</span>; <span class="hljs-comment">//初始化坐标图的X轴最大值坐标</span> mMaxXPos[<span class="hljs-number">0</span>] = mWidth; mMaxXPos[<span class="hljs-number">1</span>] = mHight - mXYTitleTextSize * <span class="hljs-number">4</span>; <span class="hljs-comment">//初始化坐标图的Y轴最大值坐标</span> mMaxYPos[<span class="hljs-number">0</span>] = mXYTitleTextSize * <span class="hljs-number">2</span>; mMaxYPos[<span class="hljs-number">1</span>] = mXYTitleTextSize * <span class="hljs-number">2</span>; } <span class="hljs-keyword">private</span> <span class="hljs-keyword">void</span> <span class="hljs-title">drawXYTitle</span>(Canvas canvas) { mPaint.setColor(Color.parseColor(<span class="hljs-string">"#1FB0E7"</span>)); mPaint.setTextSize(mXYTitleTextSize); mPaint.setTextAlign(Paint.Align.LEFT); <span class="hljs-comment">//画Y轴顶的title</span> canvas.drawText(mTitleY, mMaxYPos[<span class="hljs-number">0</span>] - mXYTitleTextSize * <span class="hljs-number">2</span>, mMaxYPos[<span class="hljs-number">1</span>] - mXYTitleTextSize, mPaint); mPaint.setTextAlign(Paint.Align.RIGHT); <span class="hljs-comment">//画X轴顶的title</span> canvas.drawText(mTitleX, mMaxXPos[<span class="hljs-number">0</span>], mMaxXPos[<span class="hljs-number">1</span>] + mXYTitleTextSize * <span class="hljs-number">2</span>, mPaint); } <span class="hljs-keyword">private</span> <span class="hljs-keyword">void</span> <span class="hljs-title">drawXYLine</span>(Canvas canvas) { mPaint.setColor(Color.DKGRAY); mPaint.setTextAlign(Paint.Align.RIGHT); <span class="hljs-comment">//画XY轴</span> canvas.drawLine(mMaxYPos[<span class="hljs-number">0</span>], mMaxYPos[<span class="hljs-number">1</span>], mZeroPos[<span class="hljs-number">0</span>], mZeroPos[<span class="hljs-number">1</span>], mPaint); canvas.drawLine(mZeroPos[<span class="hljs-number">0</span>], mZeroPos[<span class="hljs-number">1</span>], mMaxXPos[<span class="hljs-number">0</span>], mMaxXPos[<span class="hljs-number">1</span>], mPaint); } <span class="hljs-keyword">private</span> <span class="hljs-keyword">void</span> <span class="hljs-title">drawContent</span>(Canvas canvas) { mGridLevel = mXLevel.size() - <span class="hljs-number">1</span>; <span class="hljs-comment">//计算出偏移title等显示尺标后的真实XY轴长度,便于接下来等分</span> mRealWidth = (mWidth - mXYTitleTextSize * <span class="hljs-number">2</span>); mRealHight = (mHight - mXYTitleTextSize * <span class="hljs-number">4</span>); <span class="hljs-comment">//算出等分间距</span> <span class="hljs-keyword">int</span> offsetX = mRealWidth/(mGridLevel); <span class="hljs-keyword">int</span> offsetY = mRealHight/(mGridLevel+<span class="hljs-number">1</span>); <span class="hljs-comment">//循环绘制content</span> <span class="hljs-keyword">for</span> (<span class="hljs-keyword">int</span> index=<span class="hljs-number">0</span>; index<mGridLevel+<span class="hljs-number">1</span>; index++) { mPaint.setColor(Color.DKGRAY); mPaint.setTextAlign(Paint.Align.RIGHT); mPaint.setTextSize(mXYTitleTextSize-<span class="hljs-number">5</span>); <span class="hljs-comment">//绘制X轴的那些坐标区间点,包含0点坐标</span> canvas.drawText(String.valueOf(mXLevel.get(index)), mZeroPos[<span class="hljs-number">0</span>]+(index*offsetX), mZeroPos[<span class="hljs-number">1</span>] + mXYTitleTextSize, mPaint); <span class="hljs-keyword">if</span> (index != <span class="hljs-number">0</span>) { <span class="hljs-comment">//绘制Y轴坐标区间点,不包含0点坐标,X轴已经画过了</span> canvas.drawText(String.valueOf(mYLevel.get(index)), mZeroPos[<span class="hljs-number">0</span>], mZeroPos[<span class="hljs-number">1</span>]-(index*offsetY), mPaint); } <span class="hljs-keyword">if</span> (index == mGridLevel) { <span class="hljs-comment">//坐标区间 = 真实区间 + 1</span> <span class="hljs-keyword">break</span>; } mPaint.setColor(mGridColorLevel.get(mGridLevel - <span class="hljs-number">1</span> - index)); mPaint.setStyle(Paint.Style.FILL); <span class="hljs-comment">//绘制区间叠加图谱方块,从远到0坐标,因为小的图会覆盖大的图</span> canvas.drawRect(mMaxYPos[<span class="hljs-number">0</span>], mMaxYPos[<span class="hljs-number">1</span>] + index*offsetY, mMaxXPos[<span class="hljs-number">0</span>]-index*offsetX, mMaxXPos[<span class="hljs-number">1</span>], mPaint); mPaint.setColor(mGridTxtColorLevel.get(index)); mPaint.setTextAlign(Paint.Align.RIGHT); mPaint.setTextSize(mXYTitleTextSize); <span class="hljs-comment">//绘制每个方块状态区间的提示文字</span> canvas.drawText(mGridLevelText.get(index), mMaxXPos[<span class="hljs-number">0</span>] - index * offsetX - mXYTitleTextSize, mMaxYPos[<span class="hljs-number">1</span>] + index * offsetY + mXYTitleTextSize, mPaint); } <span class="hljs-comment">//绘制当前坐标</span> drawNotice(canvas, offsetX, offsetY); } <span class="hljs-keyword">private</span> <span class="hljs-keyword">void</span> <span class="hljs-title">drawNotice</span>(Canvas canvas, <span class="hljs-keyword">int</span> offsetX, <span class="hljs-keyword">int</span> offsetY) { <span class="hljs-keyword">int</span> realPosX = <span class="hljs-number">0</span>; <span class="hljs-keyword">int</span> realPosY = <span class="hljs-number">0</span>; <span class="hljs-comment">//计算传入的x值与真实屏幕坐标的像素值的百分比差值转换</span> <span class="hljs-keyword">for</span> (<span class="hljs-keyword">int</span> index=<span class="hljs-number">0</span>; index<mGridLevel; index++) { <span class="hljs-keyword">if</span> (mMeasureXpos >= mXLevel.get(index) && mMeasureXpos < mXLevel.get(index+<span class="hljs-number">1</span>)) { <span class="hljs-keyword">int</span> subValue = mMeasureXpos - mXLevel.get(index); <span class="hljs-keyword">int</span> offset = mXLevel.get(index+<span class="hljs-number">1</span>) - mXLevel.get(index); realPosX = mZeroPos[<span class="hljs-number">0</span>] + index*offsetX + (subValue / offset); <span class="hljs-keyword">break</span>; } } <span class="hljs-comment">//计算传入的y值与真实屏幕坐标的像素值的百分比差值转换</span> <span class="hljs-keyword">for</span> (<span class="hljs-keyword">int</span> index=<span class="hljs-number">0</span>; index<mGridLevel; index++) { <span class="hljs-keyword">if</span> (mMeasureYpos >= mYLevel.get(index) && mMeasureYpos < mYLevel.get(index+<span class="hljs-number">1</span>)) { <span class="hljs-keyword">int</span> subValue = mMeasureYpos - mYLevel.get(index); <span class="hljs-keyword">int</span> offset = mYLevel.get(index+<span class="hljs-number">1</span>) - mYLevel.get(index); realPosY = mZeroPos[<span class="hljs-number">1</span>] - index*offsetY - (offsetY - (subValue / offset)); <span class="hljs-keyword">break</span>; } } <span class="hljs-comment">//画我们传入的坐标点的标记小红点</span> mPaint.setColor(Color.RED); mPaint.setStyle(Paint.Style.FILL); canvas.drawCircle(realPosX, realPosY, <span class="hljs-number">8</span>, mPaint); <span class="hljs-keyword">int</span>[] centerPos = {mZeroPos[<span class="hljs-number">0</span>] + mRealWidth/<span class="hljs-number">2</span>, mZeroPos[<span class="hljs-number">1</span>] - mRealHight/<span class="hljs-number">2</span>}; mPaint.setColor(Color.WHITE); mPaint.setStyle(Paint.Style.FILL_AND_STROKE); RectF rectF = <span class="hljs-keyword">null</span>; Path path = <span class="hljs-keyword">new</span> Path(); <span class="hljs-comment">//画红点旁边的提示框和文字,有四个区域,然后提示框的小三角指标方位不同</span> <span class="hljs-keyword">if</span> (realPosX <= centerPos[<span class="hljs-number">0</span>] && realPosY >= centerPos[<span class="hljs-number">1</span>]) { <span class="hljs-comment">//left-bottom</span> <span class="hljs-comment">//画三角形</span> path.moveTo(realPosX+<span class="hljs-number">5</span>, realPosY+<span class="hljs-number">5</span>); path.lineTo(realPosX+<span class="hljs-number">15</span>, realPosY+<span class="hljs-number">15</span>); path.lineTo(realPosX+<span class="hljs-number">15</span>, realPosY-<span class="hljs-number">15</span>); <span class="hljs-comment">//画矩形背景</span> rectF = <span class="hljs-keyword">new</span> RectF(realPosX+<span class="hljs-number">15</span>, realPosY-<span class="hljs-number">40</span>, realPosX+<span class="hljs-number">200</span>, realPosY + <span class="hljs-number">30</span>); canvas.drawRoundRect(rectF, <span class="hljs-number">15</span>, <span class="hljs-number">15</span>, mPaint); <span class="hljs-comment">//画提示框的文字</span> mPaint.reset(); mPaint.setColor(Color.RED); mPaint.setTextSize(mXYTitleTextSize - <span class="hljs-number">5</span>); canvas.drawText(<span class="hljs-string">"("</span>+mMeasureXpos+<span class="hljs-string">", "</span>+mMeasureYpos+<span class="hljs-string">")"</span>, realPosX+<span class="hljs-number">30</span>, realPosY, mPaint); } <span class="hljs-keyword">else</span> <span class="hljs-keyword">if</span> (realPosX <= centerPos[<span class="hljs-number">0</span>] && realPosY < centerPos[<span class="hljs-number">1</span>]) { <span class="hljs-comment">//left-top</span> path.moveTo(realPosX+<span class="hljs-number">5</span>, realPosY+<span class="hljs-number">5</span>); path.lineTo(realPosX+<span class="hljs-number">15</span>, realPosY+<span class="hljs-number">15</span>); path.lineTo(realPosX + <span class="hljs-number">15</span>, realPosY - <span class="hljs-number">15</span>); rectF = <span class="hljs-keyword">new</span> RectF(realPosX+<span class="hljs-number">15</span>, realPosY - <span class="hljs-number">20</span>, realPosX+<span class="hljs-number">200</span>, realPosY + <span class="hljs-number">50</span>); canvas.drawRoundRect(rectF, <span class="hljs-number">15</span>, <span class="hljs-number">15</span>, mPaint); mPaint.reset(); mPaint.setColor(Color.RED); mPaint.setTextSize(mXYTitleTextSize - <span class="hljs-number">5</span>); canvas.drawText(<span class="hljs-string">"("</span>+mMeasureXpos+<span class="hljs-string">", "</span>+mMeasureYpos+<span class="hljs-string">")"</span>, realPosX+<span class="hljs-number">30</span>, realPosY+<span class="hljs-number">20</span>, mPaint); } <span class="hljs-keyword">else</span> <span class="hljs-keyword">if</span> (realPosX > centerPos[<span class="hljs-number">0</span>] && realPosY >= centerPos[<span class="hljs-number">1</span>]) { <span class="hljs-comment">//right-bottom</span> path.moveTo(realPosX-<span class="hljs-number">5</span>, realPosY+<span class="hljs-number">5</span>); path.lineTo(realPosX-<span class="hljs-number">15</span>, realPosY+<span class="hljs-number">15</span>); path.lineTo(realPosX - <span class="hljs-number">15</span>, realPosY - <span class="hljs-number">15</span>); rectF = <span class="hljs-keyword">new</span> RectF(realPosX-<span class="hljs-number">200</span>, realPosY-<span class="hljs-number">40</span>, realPosX-<span class="hljs-number">15</span>, realPosY + <span class="hljs-number">30</span>); canvas.drawRoundRect(rectF, <span class="hljs-number">15</span>, <span class="hljs-number">15</span>, mPaint); mPaint.reset(); mPaint.setColor(Color.RED); mPaint.setTextSize(mXYTitleTextSize - <span class="hljs-number">5</span>); canvas.drawText(<span class="hljs-string">"("</span>+mMeasureXpos+<span class="hljs-string">", "</span>+mMeasureYpos+<span class="hljs-string">")"</span>, realPosX-<span class="hljs-number">180</span>, realPosY, mPaint); } <span class="hljs-keyword">else</span> <span class="hljs-keyword">if</span> (realPosX > centerPos[<span class="hljs-number">0</span>] && realPosY < centerPos[<span class="hljs-number">1</span>]) { <span class="hljs-comment">//right-top</span> path.moveTo(realPosX-<span class="hljs-number">5</span>, realPosY+<span class="hljs-number">5</span>); path.lineTo(realPosX-<span class="hljs-number">15</span>, realPosY+<span class="hljs-number">15</span>); path.lineTo(realPosX - <span class="hljs-number">15</span>, realPosY - <span class="hljs-number">15</span>); rectF = <span class="hljs-keyword">new</span> RectF(realPosX-<span class="hljs-number">200</span>, realPosY - <span class="hljs-number">20</span>, realPosX-<span class="hljs-number">15</span>, realPosY + <span class="hljs-number">50</span>); canvas.drawRoundRect(rectF, <span class="hljs-number">15</span>, <span class="hljs-number">15</span>, mPaint); mPaint.reset(); mPaint.setColor(Color.RED); mPaint.setTextSize(mXYTitleTextSize - <span class="hljs-number">5</span>); canvas.drawText(<span class="hljs-string">"("</span>+mMeasureXpos+<span class="hljs-string">", "</span>+mMeasureYpos+<span class="hljs-string">")"</span>, realPosX-<span class="hljs-number">180</span>, realPosY+<span class="hljs-number">30</span>, mPaint); } path.close(); mPaint.setColor(Color.WHITE); mPaint.setStyle(Paint.Style.FILL_AND_STROKE); canvas.drawPath(path, mPaint); } <span class="hljs-comment">//设置当前比值</span> <span class="hljs-keyword">public</span> <span class="hljs-keyword">void</span> <span class="hljs-title">updateValues</span>(<span class="hljs-keyword">int</span> x, <span class="hljs-keyword">int</span> y) { mMeasureXpos = x; mMeasureYpos = y; postInvalidate(); } <span class="hljs-comment">//设置XY轴顶角的title字体大小</span> <span class="hljs-keyword">public</span> <span class="hljs-keyword">void</span> <span class="hljs-title">setTitleTextSize</span>(<span class="hljs-keyword">int</span> size) { mXYTitleTextSize = size; } <span class="hljs-comment">//初始化X轴的坐标区间点值,可以不均等分</span> <span class="hljs-keyword">public</span> <span class="hljs-keyword">void</span> <span class="hljs-title">initXLevelOffset</span>(ArrayList<Integer> list) { mXLevel.clear(); mXLevel.addAll(list); } <span class="hljs-comment">//初始化Y轴的坐标区间点值,可以不均等分</span> <span class="hljs-keyword">public</span> <span class="hljs-keyword">void</span> <span class="hljs-title">initYLevelOffset</span>(ArrayList<Integer> list) { mYLevel.clear(); mYLevel.addAll(list); } <span class="hljs-comment">//初始化每个区间的提示文字,如果不想显示可以设置""</span> <span class="hljs-keyword">public</span> <span class="hljs-keyword">void</span> <span class="hljs-title">initGridLevelText</span>(ArrayList<String> list) { mGridLevelText.clear(); mGridLevelText.addAll(list); } <span class="hljs-comment">//初始化每个区间的颜色</span> <span class="hljs-keyword">public</span> <span class="hljs-keyword">void</span> <span class="hljs-title">initGridColorLevel</span>(ArrayList<Integer> list) { mGridColorLevel.clear(); mGridColorLevel.addAll(list); } <span class="hljs-comment">//初始化每个区间的提示文字颜色</span> <span class="hljs-keyword">public</span> <span class="hljs-keyword">void</span> <span class="hljs-title">initGridTxtColorLevel</span>(ArrayList<Integer> list) { mGridTxtColorLevel.clear(); mGridTxtColorLevel.addAll(list); } <span class="hljs-comment">//初始化XY轴title</span> <span class="hljs-keyword">public</span> <span class="hljs-keyword">void</span> <span class="hljs-title">initTitleXY</span>(String x, String y) { mTitleX = x; mTitleY = y; } }` 再来看下布局文件:
...