Android自定义控件
2015-12-31 23:23
579 查看
前言:实在没想到2015年就这么过去了,真真实实的是颓废了一年,感觉自己没什么进步啊,而且退步明显。现在都已经半年没怎么写过代码了,趁着跨年的时间点回望了一下过去,在博客里突然发现还有好几篇大半年以前或一年以前写的文章还没有发布的,本想删了算了,犹豫了一下还是发布出来吧,毕竟那也是曾经的我啊~要是叫现在的我来写这篇文章的话还不一定写得出来,好多知识点都忘了。2016年得好好奋斗了,还得填了2015年留下的坑,出来混迟早要还的……
在Android 开发中,系统自带控件的功能和效果常常不满足于需求,因此需要创造一个一个的“新”控件来实现新功能。
Android中实现自定义控件的方式大体上就两种:
1、继承已有控件实现自定义控件。
2、继承View或ViewGroup,重新绘制新的控件。
其实已有控件都是继承自View的,因此自定义控件的本质可以说是对View的扩展。
自定义View的步骤大体如下:
定义自定义属性
在布局文件中引用自定义的命名空间,类似系统控件般的设置属性。
继承View,重写构造函数、onMesure、onDraw等函数。(有时候不止这三个,但一般情况下够了)并获取其自定义属性。
3.x:(对第3步进行说明)
测量:onMeasure 设置自己显示在屏幕上的宽高
布局:onLayout 设置自己显示在屏幕上的位置(只有在自定义ViewCroup中才用到)
绘制:onDraw 控制显示在屏幕上的样子(自定义Viewgroup时不需要这个)
下面就来实现一个简单的自定义View。
定义自定义属性:
这些资源通常是放在res/values/attrs.xm文件里。
这些代码声明了三个自定义属性:"showText"和"textSize"以及“contentText”,他们属于一个叫做PieChart的样式实体。按照惯例,样式实体的名字是和声明的自定义view类名是相同的。尽管遵循这个惯例不是绝对必要的,但很多有名的代码编写者都基于这个命名惯例来提供声明。
这里的format是自定义属性的值的类型。其类型共有10种:reference,float,string,color,demension,integer,enum,boolean,fraction,flag。
这里有一篇关于format的类型的文章,可以看看。http://www.cnblogs.com/rayray/p/3442026.html
在布局文件中引用自定义的命名空间,类似系统控件般的设置属性:
在布局文件activity_main.xml中实现如下:
其中xmlns:custom="http://schemas.android.com/apk/res/com.example.customview"是自定义的命名空间,其名称为custom。
其中custom:contentText="你好" custom:showText="true" custom:textSize="50sp"就是我们之前设置的属性。
注意:用来向布局中添加自定义view的XML标签的名字。这是自定义view类的完全表述。如果view内是一个内部类,必须使用外部类的名字进一步限定它。例如,PieChart类有一个叫做PieView的内部类。为了使用这个类中的自定义属性,必须使用标签com.example.customviews.charting.PieChart$PieView。
接下来,我们创建一个View包,新建一个PieChart类。如图所示:
View Code
好吧,这篇文章就到此为止吧,主要是对自定义View做一个简单的了解。(虽然很简单,讲得也不是很清楚,我尽力了。)
参考文献:Android官网。
在Android 开发中,系统自带控件的功能和效果常常不满足于需求,因此需要创造一个一个的“新”控件来实现新功能。
Android中实现自定义控件的方式大体上就两种:
1、继承已有控件实现自定义控件。
2、继承View或ViewGroup,重新绘制新的控件。
其实已有控件都是继承自View的,因此自定义控件的本质可以说是对View的扩展。
自定义View的步骤大体如下:
定义自定义属性
在布局文件中引用自定义的命名空间,类似系统控件般的设置属性。
继承View,重写构造函数、onMesure、onDraw等函数。(有时候不止这三个,但一般情况下够了)并获取其自定义属性。
3.x:(对第3步进行说明)
测量:onMeasure 设置自己显示在屏幕上的宽高
布局:onLayout 设置自己显示在屏幕上的位置(只有在自定义ViewCroup中才用到)
绘制:onDraw 控制显示在屏幕上的样子(自定义Viewgroup时不需要这个)
下面就来实现一个简单的自定义View。
定义自定义属性:
这些资源通常是放在res/values/attrs.xm文件里。
<?xml version="1.0" encoding="utf-8"?> <resources> <declare-styleable name="PieChart"> <attr name="showText" format="boolean" /> <attr name="textSize" format="dimension"></attr> <attr name="contentText" format="string"></attr> </declare-styleable> </resources>
这些代码声明了三个自定义属性:"showText"和"textSize"以及“contentText”,他们属于一个叫做PieChart的样式实体。按照惯例,样式实体的名字是和声明的自定义view类名是相同的。尽管遵循这个惯例不是绝对必要的,但很多有名的代码编写者都基于这个命名惯例来提供声明。
这里的format是自定义属性的值的类型。其类型共有10种:reference,float,string,color,demension,integer,enum,boolean,fraction,flag。
这里有一篇关于format的类型的文章,可以看看。http://www.cnblogs.com/rayray/p/3442026.html
在布局文件中引用自定义的命名空间,类似系统控件般的设置属性:
在布局文件activity_main.xml中实现如下:
<RelativeLayout xmlns:android="http://schemas.android.com/apk/res/android" xmlns:tools="http://schemas.android.com/tools" xmlns:custom="http://schemas.android.com/apk/res/com.example.customview" android:layout_width="match_parent" android:layout_height="match_parent" tools:context="com.example.customview.MainActivity" > <com.example.customview.view.PieChart android:layout_width="250dp" android:layout_height="250dp" android:layout_centerInParent="true" android:background="@android:color/holo_blue_light" custom:contentText="你好" custom:showText="true" custom:textSize="50sp" /> </RelativeLayout>
其中xmlns:custom="http://schemas.android.com/apk/res/com.example.customview"是自定义的命名空间,其名称为custom。
其中custom:contentText="你好" custom:showText="true" custom:textSize="50sp"就是我们之前设置的属性。
注意:用来向布局中添加自定义view的XML标签的名字。这是自定义view类的完全表述。如果view内是一个内部类,必须使用外部类的名字进一步限定它。例如,PieChart类有一个叫做PieView的内部类。为了使用这个类中的自定义属性,必须使用标签com.example.customviews.charting.PieChart$PieView。
接下来,我们创建一个View包,新建一个PieChart类。如图所示:
public class PieChart extends View { private boolean mShowText; private int mTextSize; private String mContentText; private Paint mTextPaint; private Rect mBound; private int mAscent; public PieChart(Context context, AttributeSet attrs) { super(context, attrs); TypedArray a = context.getTheme().obtainStyledAttributes(attrs, R.styleable.PieChart, 0, 0); try { mShowText = a.getBoolean(R.styleable.PieChart_showText, false); // mTextSize = // a.getInteger(R.styleable.PieChart_textSize,12);//这是错误的获取方式 mTextSize = a.getDimensionPixelSize(R.styleable.PieChart_textSize, (int) TypedValue.applyDimension(TypedValue.COMPLEX_UNIT_SP, 12, getResources().getDisplayMetrics())); mContentText = a.getString(R.styleable.PieChart_contentText); } finally { a.recycle(); } init(); } public boolean ismShowText() { return mShowText; } public void setmShowText(boolean mShowText) { this.mShowText = mShowText; invalidate(); requestLayout(); } // setShowText调用了invalidate()和requestLayout() 。这些调用关键是为了保证view行为是可靠的。 // 你必须在改变这个可能改变外观的属性后废除这个view,这样系统才知道需要重绘。 // 同样,如果属性的变化可能影响尺寸或者view的形状,您需要请求一个新的布局。 // 忘记调用这些方法可能导致难以寻找的bug。 @Override protected void onMeasure(int widthMeasureSpec, int heightMeasureSpec) { setMeasuredDimension(measureWidth(widthMeasureSpec), measureHeight(heightMeasureSpec)); } @Override protected void onDraw(Canvas canvas) { // TODO Auto-generated method stub super.onDraw(canvas); if (mShowText)// 根据我们获取的设置的自定义属性,判断是否显示文本 canvas.drawText(mContentText, getWidth() / 2 - mBound.width() / 2, getHeight() / 2 + mBound.height() / 2, mTextPaint); // getWidth() / 2 - mBound.width() / 2,getHeight() / 2 + mBound.height() // / 2 // 这是为了使文本居中 else canvas.drawText("内容为空", getWidth() / 2 - mBound.width() / 2, getHeight() / 2 + mBound.height() / 2, mTextPaint); } /** * Determines the width of this view * * @param measureSpec * A measureSpec packed into an int * @return The width of the view, honoring constraints from measureSpec */ private int measureWidth(int measureSpec) { int result = 0; int specMode = MeasureSpec.getMode(measureSpec); int specSize = MeasureSpec.getSize(measureSpec); if (specMode == MeasureSpec.EXACTLY) { // We were told how big to be result = specSize; } else { // Measure the text result = (int) mTextPaint.measureText(mContentText) + getPaddingLeft() + getPaddingRight(); if (specMode == MeasureSpec.AT_MOST) { // Respect AT_MOST value if that was what is called for by // measureSpec result = Math.min(result, specSize); } } return result; } /** * Determines the height of this view * * @param measureSpec * A measureSpec packed into an int * @return The height of the view, honoring constraints from measureSpec */ private int measureHeight(int measureSpec) { int result = 0; int specMode = MeasureSpec.getMode(measureSpec); int specSize = MeasureSpec.getSize(measureSpec); mAscent = (int) mTextPaint.ascent(); if (specMode == MeasureSpec.EXACTLY) { // We were told how big to be result = specSize; } else { // Measure the text (beware: ascent is a negative number) result = (int) (-mAscent + mTextPaint.descent()) + getPaddingTop() + getPaddingBottom(); if (specMode == MeasureSpec.AT_MOST) { // Respect AT_MOST value if that was what is called for by // measureSpec result = Math.min(result, specSize); } } return result; } public int getmTextSize() { return mTextSize; } public void setmTextSize(int mTextSize) { this.mTextSize = mTextSize; invalidate(); requestLayout(); } public String getmContentText() { return mContentText; } public void setmContentText(String mContentText) { this.mContentText = mContentText; invalidate(); requestLayout(); } private void init() { mTextPaint = new Paint(Paint.ANTI_ALIAS_FLAG); mTextPaint.setTextSize(mTextSize); mTextPaint.setStyle(Paint.Style.FILL); mTextPaint.setColor(0xff101010); mBound = new Rect(); mTextPaint .getTextBounds(mContentText, 0, mContentText.length(), mBound); } }
View Code
好吧,这篇文章就到此为止吧,主要是对自定义View做一个简单的了解。(虽然很简单,讲得也不是很清楚,我尽力了。)
参考文献:Android官网。
相关文章推荐
- 安卓中的开发框架
- Android ListView显示底部的分割线
- Android ListView显示底部的分割线
- java.lang.illegalargumentexception view android.widget.listview is not a sliding drawer
- Android 自定义控件 轻松实现360软件详情页
- Android开发必知--使用View.setId的正确姿势
- Android 媒体 III-媒体路由提供者
- Android编程实用代码合集
- Android native splash for game
- Android逆向反编译之smali基础
- Android的事件分发源码分析,告别事件冲突。
- AndroidStudio 1.4配置NDK
- 生产实习(Android)八
- Android Studio 快捷键 for Mac OS X 10.5+
- Android Intent 的几种跳转
- ubuntu下android studio生成的unaligned apk的zipalign处理
- Android自定义属性时format选项可以取用的值
- Android打造listview万能适配器(下)
- Android打包提示Export Aborted
- Android极光推送入门