自定义控件学习第一课
来源:互联网 发布:js窗口大小改变事件 编辑:程序博客网 时间:2024/06/05 19:21
自定义控件学习第一课
Android中的自定义控件是成为中高级程序员必须去克服的一个课题。学好自定义控件,需要你对View绘制的原理,触摸手势的处理,动画的运用等基础重要的知识点有较为深刻的认识和见解。
本人打算认真系统的学习下自定义控件,学习资料来自于大牛“鸿洋”(http://blog.csdn.net/lmj623565791),我用重新实现其中的实例,并把自己碰到的问题疑问和大家分享。进入正题:
Lesson 1:
第一步:
先定义自定义控件的属性(当然不是所有自定义控件都需要定义自己的属性)
本Markdown编辑器使用[StackEdit][6]修改而来,用它写博客,将会带来全新的体验哦:
<?xml version="1.0" encoding="utf-8"?><resources> <attr name="titleText" format="string" /><!-- 参数是字符串的属性 --> <attr name="titleColor" format="color" /><!-- 参数是颜色类型的属性 --> <attr name="titleSize" format="dimension" /><!-- 参数是尺寸类型的属性 --> <declare-styleable name="CustomTitleView"><!-- 一定和自定义控件的名字是一致的 --> <attr name="titleText" /> <attr name="titleColor" /> <attr name="titleSize" /> </declare-styleable></resources>
第二步:
继承View,重写onMeasure,onDraw这个方法,其中onMeasure主要是做了测量控件需要的大小的工作,onDraw就是绘制view的工作,当然还需要解析自定义的一些属性
public class CustomTitleView extends View { private String mTitleText;// 显示的文字 private int mTitleColor;// 文字的颜色 private int mTitleSize;// 文字的尺寸 private Paint mPaint;// 画笔 /** * 绘制时控制文本绘制的范围 */ private Rect mBound; public CustomTitleView(Context context) { this(context, null); // TODO Auto-generated constructor stub } /** * 默认的布局文件调用的是两个参数的构造方法 * * @param context * @param attrs */ public CustomTitleView(Context context, AttributeSet attrs) { this(context, attrs, 0); // TODO Auto-generated constructor stub } /** * 在三个参数的构造中获得自定义属性 * * @param context * @param attrs * @param defStyle */ public CustomTitleView(Context context, AttributeSet attrs, int defStyle) { super(context, attrs, defStyle); // TODO Auto-generated constructor stub // 获取我们自定义的属性 TypedArray a = context.getTheme().obtainStyledAttributes(attrs, R.styleable.CustomTitleView, defStyle, 0); int n = a.getIndexCount();// 属性的个数 // 循环处理每个属性 for (int i = 0; i < n; i++) { int attr = a.getIndex(i); switch (attr) { case R.styleable.CustomTitleView_titleText: mTitleText = a.getString(attr); break; case R.styleable.CustomTitleView_titleColor: mTitleColor = a.getColor(attr, android.R.color.black);// 默认颜色设置为黑色 break; case R.styleable.CustomTitleView_titleSize: mTitleSize = a.getDimensionPixelSize(attr, (int) TypedValue .applyDimension(TypedValue.COMPLEX_UNIT_SP, 16, getResources().getDisplayMetrics()));// 默认设置为16sp,TypeValue也可以把sp转化为px break; } } a.recycle();// 释放属性 // 初始化画笔 mPaint = new Paint(); mPaint.setTextSize(mTitleSize); /** * 获得绘制文本的宽和高 */ mBound = new Rect(); mPaint.getTextBounds(mTitleText, 0, mTitleText.length(), mBound); } @Override protected void onMeasure(int widthMeasureSpec, int heightMeasureSpec) { // TODO Auto-generated method stub int width; int height; int widthMode = MeasureSpec.getMode(widthMeasureSpec); int widthSize = MeasureSpec.getSize(widthMeasureSpec); int heightMode = MeasureSpec.getMode(heightMeasureSpec); int heightSize = MeasureSpec.getSize(heightMeasureSpec); if(widthMode == MeasureSpec.EXACTLY){ width = widthSize; }else{ float textWidth = mBound.width(); width = (int)(textWidth+getPaddingLeft()+getPaddingRight()); } if(heightMode == MeasureSpec.EXACTLY){ height = heightSize; }else{ float textHeight = mBound.height(); height = (int)(textHeight+getPaddingTop()+getPaddingBottom()); } setMeasuredDimension(width, height); } @Override protected void onDraw(Canvas canvas) { // TODO Auto-generated method stub Log.i("info", "getMeasuredWidth()="+getMeasuredWidth()+",getMeasuredHeight()="+getMeasuredHeight()); Log.i("info", "getWidth()="+getWidth()+",getHeight()="+getHeight()); // 画背景 mPaint.setColor(Color.YELLOW); canvas.drawRect(0, 0, getMeasuredWidth(), getMeasuredHeight(), mPaint); // 画字符串 mPaint.setColor(mTitleColor); canvas.drawText(mTitleText, getWidth() / 2 - mBound.width() / 2, getHeight() / 2 + mBound.height() / 2, mPaint); }}
重写onMeasure先要了解的知识点:
了解MeasureSpec的specMode,一共三种类型:
EXACTLY:一般是设置了明确的值或者是MATCH_PARENT
AT_MOST:表示子布局限制在一个最大值内,一般为WARP_CONTENT
UNSPECIFIED:表示子布局想要多大就多大,很少使用
学习时还遇到一个小疑问:
getWidth()和getMeasuredWidth()这两个方法有什么区别呢?从字面上看getMeasuredWidth()是测量的宽度,getWidth()就是宽度,所以一般情况下两者是相同的,比如本例中就是相同的,但是也有一些不一样的情况,比如一些可以滚动的视图,getMeasuredWidth()往往比getWidth()要大。
总结:
getWidth(): View在设定好布局后整个View的宽度。
getMeasuredWidth(): 对View上的内容进行测量后得到的View内容占据的宽度,前提是你必须在父布局的onLayout()方法或者此View的onDraw()方法里调用measure(0,0);(measure中的参数的值你自己可以定义),否则你得到的结果和getWidth()得到的结果是一样的。
第三步:
在布局文件中运用:
<RelativeLayout xmlns:android="http://schemas.android.com/apk/res/android" xmlns:tools="http://schemas.android.com/tools" android:layout_width="match_parent" android:layout_height="match_parent" xmlns:app="http://schemas.android.com/apk/res/com.loubf.customview"> <com.loubf.customview.CustomTitleView android:layout_width="wrap_content" android:layout_height="wrap_content" app:titleText="12530" app:titleColor="#FF0000" app:titleSize="20sp" android:padding="10dp" android:layout_centerInParent="true" > </com.loubf.customview.CustomTitleView></RelativeLayout>
这样一个简单的自定义控件就算完成了
- 自定义控件学习第一课
- CTreeCtrl控件学习第一课
- JSF 学习之 编写自定义控件(第一部分)
- 自定义控件学习第二课
- android_自定义控件第一炮
- 自定义控件2.第一个自定义view
- [Android自定义控件] Android自定义控件 第一期基本讲解
- dotnet 自定义控件学习
- 自定义控件学习
- 唉,学习自定义控件
- [自定义控件学习]Textview
- 学习日志--自定义控件
- 学习自定义控件
- 学习笔记:自定义控件
- 创建自定义控件学习
- 自定义控件学习Topbar
- android 自定义控件学习
- Android自定义控件学习
- CentOS安装nagios
- CSS文字环绕图片,文中图效果
- CNN基础及开发环境搭建(综合参考)
- 【c#源码】基于TCP通信的客户端断线重连
- vim 常用配置
- 自定义控件学习第一课
- UVA 1204 Fun Game(状压dp)
- 解读林锐-高质量C,C++编程指南
- 计算几何--两圆的位置关系(求交点个数及交点坐标)
- iOS CGContextRef画图小结
- Hibernate——以面向对象的思维操作关系数据库(一)
- OC里的继承和重写
- oracle中获取系统时间
- 【头脑风暴】要创建一家会被科技巨头收购的公司,你需要怎么做?