Android进阶学习-使用Canvas自定义简单TextView(1)
2016-04-08 00:00
851 查看
效果图
说起View这个东西,一直都是令人头疼的事情,用起来好使,但有时候系统带的View不够用时,就要自己去编写了,这时候就呵呵了.下面我们来学习一下吧.
1.首先在res/values下面新建attr.xml,代码:
其中上面三行声明了一些属性,还有属性所对应的类型
declare-stylable声明了一个自定义属性的集合,name是对应的名字.可以想象成declare-stylable是一个箱子,里面放了很多属性.
1.自定义View
2.然后是我们的View的主要代码,三个构造器+onMeasure()+onDraw()方法
主角构造器:
3.下面是OnMeasure()方法
4.最后就是View的绘制onDraw()了
View的整体代码
布局文件:
参考链接: http://my.oschina.net/qiuhoude/blog/410809
http://blog.csdn.net/hursing/article/details/18703599
说起View这个东西,一直都是令人头疼的事情,用起来好使,但有时候系统带的View不够用时,就要自己去编写了,这时候就呵呵了.下面我们来学习一下吧.
1.首先在res/values下面新建attr.xml,代码:
[code=plain]<?xml version="1.0" encoding="utf-8"?> <resources> <attr name="mTitleText" format="string" /> <attr name="mTitleTextColor" format="color" /> <attr name="mTitleTextSize" format="dimension" /> <declare-styleable name="CustomTitleView"> <attr name="mTitleText" /> <attr name="mTitleTextColor" /> <attr name="mTitleTextSize" /> </declare-styleable> </resources>
其中上面三行声明了一些属性,还有属性所对应的类型
自定义样式
format是值该属性的取值类型一共有:string,color,demension,integer,enum,reference,float,boolean,fraction,flag;
"reference" //引用,ResourceID
"color" //颜色
"boolean" //布尔值
"dimension" //尺寸值
"float" //浮点值
"integer" //整型值
"string" //字符串
"fraction" //百分数,比如200%
declare-stylable声明了一个自定义属性的集合,name是对应的名字.可以想象成declare-stylable是一个箱子,里面放了很多属性.
1.自定义View
[code=plain]public class CustomTitleView extends View { private String mTitleText; private int mTitleTextColor; private int mTitleTextSize; /** * 分别对应我们的自定义属性的三个属性值,等下用来接收那些属性值 */ private Rect mBonds; private Paint mPaint; /** * Rect是我们要占据的空间,一个矩形嘛 * Paint是我们用来绘画View的画笔 */ }
2.然后是我们的View的主要代码,三个构造器+onMeasure()+onDraw()方法
[code=plain]public CustomTitleView(Context context) { this(context, null); } public CustomTitleView(Context context, AttributeSet attrs) { this(context, attrs, 0); }
主角构造器:
[code=plain] public CustomTitleView(Context context, AttributeSet attrs, int defStyleAttr) { super(context, attrs, defStyleAttr); TypedArray ta = context.getTheme().obtainStyledAttributes(attrs, R.styleable.CustomTitleView, defStyleAttr, 0); /** * TypedArray数组用于获取我们刚刚定义的attr属性文件 */ /** * 通过for循环,来遍历每个设置的属性,并用switch语句判断是哪个属性,用上面三个变量去接收 */ int n = ta.getIndexCount(); for (int i = 0; i < n; i++) { int attr = ta.getIndex(i); switch (attr) { case R.styleable.CustomTitleView_mTitleText: mTitleText = ta.getString(attr); break; case R.styleable.CustomTitleView_mTitleTextColor: mTitleTextColor = ta.getColor(attr, Color.RED); break; case R.styleable.CustomTitleView_mTitleTextSize: mTitleTextSize = ta.getDimensionPixelSize(attr, (int) TypedValue.applyDimension(TypedValue.COMPLEX_UNIT_SP, 16, getResources().getDisplayMetrics())); /** * mTitleTextSize把attr获取过来的值转换成对应的dp值 */ break; } } ta.recycle(); mPaint = new Paint(); mBonds = new Rect(); }
3.下面是OnMeasure()方法
[code=plain] /** * MeasureSpec的基础知识(必看):http://my.oschina.net/qiuhoude/blog/410809 * * @param widthMeasureSpec * @param heightMeasureSpec */ @Override protected void onMeasure(int widthMeasureSpec, int heightMeasureSpec) { int widthMode = MeasureSpec.getMode(widthMeasureSpec); int widthSize = MeasureSpec.getSize(widthMeasureSpec); int heightMode = MeasureSpec.getMode(heightMeasureSpec); int heightSize = MeasureSpec.getSize(heightMeasureSpec); int width; int height; if (widthMode == MeasureSpec.EXACTLY) { width = widthSize; } else { mPaint.setTextSize(mTitleTextSize); width = (int) mPaint.measureText(mTitleText, 0, mTitleText.length()); /** * 该模式下为wrap_content,需要自己去测量View需要占据的空间,通过以上方法结合字体大小即可算出宽度 */ } if (heightMode == MeasureSpec.EXACTLY) { height = heightSize; } else { mPaint.setTextSize(mTitleTextSize); height = getFontHeight(mPaint); /** * 与宽度类似,但是需要获取字体的高度去测量 */ } setMeasuredDimension(width + getPaddingLeft() + getPaddingRight(), height + getPaddingTop() + getPaddingBottom()); }
[code=plain] private int getFontHeight(Paint paint) { Paint.FontMetrics fm = paint.getFontMetrics(); return (int) (Math.ceil(fm.descent - fm.ascent)); }
4.最后就是View的绘制onDraw()了
[code=plain] @Override protected void onDraw(Canvas canvas) { mPaint.setColor(Color.YELLOW); canvas.drawRect(0, 0, getWidth(), getHeight(), mPaint); /** * 画那个View矩形 */ mPaint.setColor(mTitleTextColor); mPaint.setTextAlign(Paint.Align.LEFT); //设置基准线,与下下面drawText的Text绘制位置有很大关系,请看下面链接 mPaint.getTextBounds(mTitleText, 0, mTitleText.length(), mBonds); //测量字体所占的宽高,赋值给mBounds canvas.drawText(mTitleText, getWidth() / 2 - mBonds.width() / 2, getHeight() / 2 + mBonds.height() / 2, mPaint); //看http://blog.csdn.net/hursing/article/details/18703599 super.onDraw(canvas); }
View的整体代码
[code=plain]package com.example.august.customview; import android.content.Context; import android.content.res.TypedArray; import android.graphics.Canvas; import android.graphics.Color; import android.graphics.Paint; import android.graphics.Rect; import android.util.AttributeSet; import android.util.TypedValue; import android.view.View; /** * Created by August on 16/4/8. */ public class CustomTitleView extends View { private String mTitleText; private int mTitleTextColor; private int mTitleTextSize; private Rect mBonds; private Paint mPaint; public CustomTitleView(Context context) { this(context, null); } public CustomTitleView(Context context, AttributeSet attrs) { this(context, attrs, 0); } public CustomTitleView(Context context, AttributeSet attrs, int defStyleAttr) { super(context, attrs, defStyleAttr); TypedArray ta = context.getTheme().obtainStyledAttributes(attrs, R.styleable.CustomTitleView, defStyleAttr, 0); int n = ta.getIndexCount(); for (int i = 0; i < n; i++) { int attr = ta.getIndex(i); switch (attr) { case R.styleable.CustomTitleView_mTitleText: mTitleText = ta.getString(attr); break; case R.styleable.CustomTitleView_mTitleTextColor: mTitleTextColor = ta.getColor(attr, Color.RED); break; case R.styleable.CustomTitleView_mTitleTextSize: mTitleTextSize = ta.getDimensionPixelSize(attr, (int) TypedValue.applyDimension(TypedValue.COMPLEX_UNIT_SP, 16, getResources().getDisplayMetrics())); break; } } ta.recycle(); mPaint = new Paint(); mBonds = new Rect(); } @Override protected void onMeasure(int widthMeasureSpec, int heightMeasureSpec) { int widthMode = MeasureSpec.getMode(widthMeasureSpec); int widthSize = MeasureSpec.getSize(widthMeasureSpec); int heightMode = MeasureSpec.getMode(heightMeasureSpec); int heightSize = MeasureSpec.getSize(heightMeasureSpec); int width; int height; if (widthMode == MeasureSpec.EXACTLY) { width = widthSize; } else { mPaint.setTextSize(mTitleTextSize); width = (int) mPaint.measureText(mTitleText, 0, mTitleText.length()); } if (heightMode == MeasureSpec.EXACTLY) { height = heightSize; } else { mPaint.setTextSize(mTitleTextSize); height = getFontHeight(mPaint); } setMeasuredDimension(width + getPaddingLeft() + getPaddingRight(), height + getPaddingTop() + getPaddingBottom()); } @Override protected void onDraw(Canvas canvas) { mPaint.setColor(Color.YELLOW); canvas.drawRect(0, 0, getWidth(), getHeight(), mPaint); mPaint.setColor(mTitleTextColor); mPaint.setTextAlign(Paint.Align.LEFT); mPaint.getTextBounds(mTitleText, 0, mTitleText.length(), mBonds); canvas.drawText(mTitleText, getWidth() / 2 - mBonds.width() / 2, getHeight() / 2 + mBonds.height() / 2, mPaint); super.onDraw(canvas); } private int getFontHeight(Paint paint) { Paint.FontMetrics fm = paint.getFontMetrics(); return (int) (Math.ceil(fm.descent - fm.ascent)); } }
布局文件:
[code=plain]<?xml version="1.0" encoding="utf-8"?> <RelativeLayout xmlns:android="http://schemas.android.com/apk/res/android" xmlns:app="http://schemas.android.com/apk/res-auto" android:layout_width="match_parent" android:layout_height="match_parent"> <com.example.august.customview.CustomTitleView android:layout_width="wrap_content" android:layout_height="wrap_content" android:layout_centerInParent="true" android:padding="10dp" app:mTitleText="Hello world!" app:mTitleTextColor="#FF0000" app:mTitleTextSize="28sp" /> </RelativeLayout>
参考链接: http://my.oschina.net/qiuhoude/blog/410809
http://blog.csdn.net/hursing/article/details/18703599
相关文章推荐
- HTML5调用摄像头实例
- Canvas 在高清屏下绘制图片变模糊的解决方法
- 麻雀虽小五脏俱全 Dojo自定义控件应用
- WinForm自定义控件应用实例
- C++ 自定义控件的移植问题
- C#中 paint()与Onpaint()的区别
- C#实现用户自定义控件中嵌入自己的图标
- C#处理Paint事件的方法
- 使用canvas实现仿新浪微博头像截取上传功能
- js+HTML5实现canvas多种颜色渐变效果的方法
- javascript+HTML5的Canvas实现Lab单车动画效果
- js+canvas绘制矩形的方法
- JavaScript+html5 canvas制作的百花齐放效果完整实例
- jQuery+canvas实现的球体平抛及颜色动态变换效果
- html5 canvas js(数字时钟)实例代码
- JavaScript+canvas实现七色板效果实例
- javascript+canvas制作九宫格小程序
- 通过javascript把图片转化为字符画
- js+html5通过canvas指定开始和结束点绘制线条的方法
- 百度地图自定义控件分享