android 开发进阶自定义控件 类似 TextView
开发自定义控件的步骤:
1. 继承View;
2.重写构造函数并构造方法中获得我们自定义的属性、
3. 重写onDraw,
4.重写onMeasure 等函数
一、自定义View的属性,首先在res/values/ 下建立一个attrs.xml , 在里面定义我们的属性和声明我们的整个样式。
<?xml version="1.0" encoding="utf-8"?> <resources> <declare-styleable name="ComstomView"> <attr name="textContent" format="string" /> <attr name="textColor" format="color" /> <attr name="textSize" format="dimension" /> </declare-styleable> </resources>
二、View类的构造方法
创建自定义控件的3种主要实现方式:
1)继承已有的控件来实现自定义控件: 主要是当要实现的控件和已有的控件在很多方面比较类似, 通过对已有控件的扩展来满足要求。
2)通过继承一个布局文件实现自定义控件,一般来说做组合控件时可以通过这个方式来实现。
注意此时不用onDraw方法,在构造广告中通过inflater加载自定义控件的布局文件,再addView(view),自定义控件的图形界面就加载进来了。
3)通过继承view类来实现自定义控件,使用GDI绘制出组件界面,一般无法通过上述两种方式来实现时用该方式。
import android.content.Context;
import android.content.res.TypedArray;
import android.graphics.Canvas;
import android.graphics.Color;
import android.graphics.Paint;
import android.graphics.Paint.Style;
import android.graphics.Rect;
import android.util.AttributeSet;
import android.util.TypedValue;
import android.view.View;
public class CustomView extends View {
private Paint mPaint; // 画笔,包含了画几何图形、文本等的样式和颜色信息
private String textContent;
private int textColor;
private int textSize;
// 绘制时控制文本绘制的范围
private Rect mBound;
public CustomView(Context context) {
this(context,null);
}
public CustomView(Context context, AttributeSet attrs) {
//R.style.AppTheme,设置此处,保证layout view 的属性生效,传递到
//CustomView(Context context, AttributeSet attrs, int defStyleAttr)
this(context, attrs,R.style.AppTheme);
}
public CustomView(Context context, AttributeSet attrs, int defStyleAttr) {
super(context, attrs, defStyleAttr);
mPaint = new Paint();
//mPaint.setColor(defStyleAttr);
getConfig(context, attrs);
mBound = new Rect();
mPaint.getTextBounds(textContent, 0, textContent.length(), mBound);
}
private void getConfig(Context context, AttributeSet attrs) {
// TypedArray是一个用来存放由context.obtainStyledAttributes获得的属性的数组
TypedArray ta = context.obtainStyledAttributes(attrs,
R.styleable.ComstomView);
// 属性的名称是styleable中的名称+“_”+属性名称
int n = ta.getIndexCount();
for (int i = 0; i < n; i++) {
int attr = ta.getIndex(i);
switch (attr) {
case R.styleable.ComstomView_textColor:
textColor = ta.getColor(attr, Color.BLACK); // 提供默认值,放置未指定
break;
case R.styleable.ComstomView_textContent:
textContent = ta.getString(attr);
break;
case R.styleable.ComstomView_textSize:
// 默认设置为15sp,TypeValue也可以把sp转化为px
textSize = ta.getDimensionPixelSize(attr,
(int) TypedValue.applyDimension(
TypedValue.COMPLEX_UNIT_SP, 15, getResources()
.getDisplayMetrics()));
mPaint.setTextSize(textSize);
break;
}
}
// 用完务必回收容器
ta.recycle();
}
public void onDraw(Canvas canvas) {
super.onDraw(canvas);
mPaint.setColor(textColor);
canvas.drawText(textContent, getWidth() / 2 - mBound.width() / 2,
getHeight() / 2 + mBound.height() / 2, mPaint);
}
}
在布局文件:中声明我们的自定义View
<RelativeLayout xmlns:android="http://schemas.android.com/apk/res/android"
xmlns:tools="http://schemas.android.com/tools"
xmlns:customview="http://schemas.android.com/apk/res/com.example.mycomstomview"
android:layout_width="match_parent"
android:layout_height="match_parent"
tools:context=".MainActivity" >
<com.example.mycomstomview.CustomView
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:background="@android:color/holo_orange_light"
android:padding="10dp"
customview:textContent="我是自定义View"
customview:textSize = "30sp"
customview:textColor="@android:color/white"
/>
</RelativeLayout>
Simple constructor to use when creating a view from code.
|
|
|
Constructor that is called when inflating a view from XML.
|
|
Perform inflation from XML and apply a class-specific base style.
|
三、自定义View增加属性的两种方法:
1)在View类中定义。通过构造函数中引入的AttributeSet 去查找XML布局的属性名称,然后找到它对应引用的资源ID去找值。
案例:实现一个带文字的图片(图片、文字是onDraw方法重绘实现)
package com.example.mycomstomview;import android.content.Context;
import android.content.res.TypedArray;
import android.graphics.Canvas;
import android.graphics.Color;
import android.graphics.Paint;
import android.graphics.Paint.Style;
import android.graphics.Rect;
import android.util.AttributeSet;
import android.util.TypedValue;
import android.view.View;
public class CustomView extends View {
private Paint mPaint; // 画笔,包含了画几何图形、文本等的样式和颜色信息
private String textContent;
private int textColor;
private int textSize;
// 绘制时控制文本绘制的范围
private Rect mBound;
public CustomView(Context context) {
this(context,null);
}
public CustomView(Context context, AttributeSet attrs) {
//R.style.AppTheme,设置此处,保证layout view 的属性生效,传递到
//CustomView(Context context, AttributeSet attrs, int defStyleAttr)
this(context, attrs,R.style.AppTheme);
}
public CustomView(Context context, AttributeSet attrs, int defStyleAttr) {
super(context, attrs, defStyleAttr);
mPaint = new Paint();
//mPaint.setColor(defStyleAttr);
getConfig(context, attrs);
mBound = new Rect();
mPaint.getTextBounds(textContent, 0, textContent.length(), mBound);
}
private void getConfig(Context context, AttributeSet attrs) {
// TypedArray是一个用来存放由context.obtainStyledAttributes获得的属性的数组
TypedArray ta = context.obtainStyledAttributes(attrs,
R.styleable.ComstomView);
// 属性的名称是styleable中的名称+“_”+属性名称
int n = ta.getIndexCount();
for (int i = 0; i < n; i++) {
int attr = ta.getIndex(i);
switch (attr) {
case R.styleable.ComstomView_textColor:
textColor = ta.getColor(attr, Color.BLACK); // 提供默认值,放置未指定
break;
case R.styleable.ComstomView_textContent:
textContent = ta.getString(attr);
break;
case R.styleable.ComstomView_textSize:
// 默认设置为15sp,TypeValue也可以把sp转化为px
textSize = ta.getDimensionPixelSize(attr,
(int) TypedValue.applyDimension(
TypedValue.COMPLEX_UNIT_SP, 15, getResources()
.getDisplayMetrics()));
mPaint.setTextSize(textSize);
break;
}
}
// 用完务必回收容器
ta.recycle();
}
public void onDraw(Canvas canvas) {
super.onDraw(canvas);
mPaint.setColor(textColor);
canvas.drawText(textContent, getWidth() / 2 - mBound.width() / 2,
getHeight() / 2 + mBound.height() / 2, mPaint);
}
}
在布局文件:中声明我们的自定义View
<RelativeLayout xmlns:android="http://schemas.android.com/apk/res/android"
xmlns:tools="http://schemas.android.com/tools"
xmlns:customview="http://schemas.android.com/apk/res/com.example.mycomstomview"
android:layout_width="match_parent"
android:layout_height="match_parent"
tools:context=".MainActivity" >
<com.example.mycomstomview.CustomView
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:background="@android:color/holo_orange_light"
android:padding="10dp"
customview:textContent="我是自定义View"
customview:textSize = "30sp"
customview:textColor="@android:color/white"
/>
</RelativeLayout>
让我们再来看看布局xml中需要注意的事项。
首先得声明一下:xmlns:customview=http://schemas.android.com/apk/res/com.example.mycomstomview
注意,“customview”可以换成其他的任何名字,后面的url地址必须最后一部分必须用上自定义组件的包名。自定义属性了,在属性名前加上“customview”即可。
最后看一下自定义View中方法的作用:
自定义View的方法
onFinishInflate() 回调方法,当应用从XML加载该组件并用它构建界面之后调用的方法
onMeasure() 检测View组件及其子组件的大小
onLayout() 当该组件需要分配其子组件的位置、大小时
onSizeChange() 当该组件的大小被改变时
onDraw() 当组件将要绘制它的内容时
onKeyDown 当按下某个键盘时
onKeyUp 当松开某个键盘时
onTrackballEvent 当发生轨迹球事件时
onTouchEvent 当发生触屏事件时
onWindowFocusChanged(boolean) 当该组件得到、失去焦点时
onAtrrachedToWindow() 当把该组件放入到某个窗口时
onDetachedFromWindow() 当把该组件从某个窗口上分离时触发的方法
onWindowVisibilityChanged(int): 当包含该组件的窗口的可见性发生改变时触发的方法