本文章参考了部分Android 自定义View (一)并结合我自己的完善和思考后得出
界面部分一直是我比较薄弱的地方,所以为了填补我的这份弱点,在自我学习的过程中,自定义View的熟悉与熟练,就成了我的必经之路,那么这次我就开始一步一步了解自定义View
那么,自定义View需要做哪些事情呢?
一、继承一个View
这种方式很多人都熟悉,继承Layout,继承系统的组件如TextView等,最基础的就是继承一个View,例如
public class MyView extends View{
public MyView(Context context, AttributeSet attrs) {
super(context, attrs);
}
}
这样就有了一个最简单的自定义View,当然这个View现在还不能显示,还需要下面的第二步第三步等步骤才能显示,
但是,现在的这个View是只能显示一片白的,什么都没有的
在我们使用的时候,当然会希望有我们自己要显示的内容,这时候就会需要我们知道几个方法
View框架中大量的on函数基本上都应用到了Template模式(模板模式),掌握这一模式对于理解这些框架大有裨益(找时间去了解一下)
注:View在ViewGroup中被分配的位置大小如何,这由onLayout()决定
参数说明:参数changed表示view有新的尺寸或位置;参数left表示相对于父view的Left位置;参数top表示相对于父view的Top位置;参数right表示相对于父view的Right位置;参数bottom表示相对于父view的Bottom位置
@Override
protected void onLayout(boolean changed, int left, int top, int right,
int bottom) {
super.onLayout(changed, left, top, right, bottom);
}
注:View本身大小多少,这由onMeasure()决定
widthMeasureSpec, heightMeasureSpec这两个参数,这两个参数由ViewGroup中的layout_width,layout_height和padding以及View自身的layout_margin共同决定。权值weight也是尤其需要考虑的因素,有它的存在情况可能会稍微复杂点
@Override
protected void onMeasure(int widthMeasureSpec, int heightMeasureSpec) {
super.onMeasure(widthMeasureSpec, heightMeasureSpec);
}
注:绘制View,onDraw()定义了如何绘制这个View
@Override
protected void onDraw(Canvas canvas) {
super.onDraw(canvas);
}
二、布局中声明View
就像系统提供的组件一样,我们的自定义组件也要这样
在res/values/ 下建立一个attrs.xml , 在里面定义我们的属性和声明我们的整个样式
<RelativeLayout xmlns:android="http://schemas.android.com/apk/res/android"
xmlns:tools="http://schemas.android.com/tools"
xmlns:myview="http://schemas.android.com/apk/res/com.example.testview"
android:layout_width="match_parent"
android:layout_height="match_parent" >
<com.example.customview01.view.CustomTitleView
android:layout_width="200dp"
android:layout_height="100dp"
myview:titleText="3712"
myview:titleTextColor="#ff0000"
myview:titleTextSize="40sp" />
</RelativeLayout>
那么,这个配置里面又有哪些需要注意的呢,我来做一张图解
这张图我是从网上直接拷过来做了一下注解
在实际使用中,自定义属性的配置其实用的不算频繁,很多人直接是写在View里面直接写在内部的
三、自定义属性的获取
其实,到了上面两步配置好后,已经可以直接运行显示自定义View了,这一步的话是用于上图中用绿色标注出来的
自定义属性的配置的,写的完善的话,就跟TextView这种组件一样使用了,那么,要类似于这种组件的属性配置的话,需要做哪些事情呢
1、自定义View的属性,首先在res/values/ 下建立一个attrs.xml , 在里面定义我们的属性和声明我们的整个样式。
<?xml version="1.0" encoding="utf-8"?>
<resources>
<attr name="titleText" format="string" />
<attr name="titleTextColor" format="color" />
<attr name="titleTextSize" format="dimension" />
<declare-styleable name="CustomTitleView">
<attr name="titleText" />
<attr name="titleTextColor" />
<attr name="titleTextSize" />
</declare-styleable>
</resources>
我定义了字体,字体颜色,字体大小3个属性,format是值该属性的取值类型:
一共有:string,color,demension,integer,enum,reference,float,boolean,fraction,flag;
然后就是在布局文件中的使用了
<LinearLayout xmlns:android="http://schemas.android.com/apk/res/android"
xmlns:tools="http://schemas.android.com/tools"
xmlns:myview="http://schemas.android.com/apk/res/com.example.testview"
android:layout_width="match_parent"
android:layout_height="match_parent"
android:orientation="vertical"
tools:context=".MainActivity" >
<TextView
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:text="@string/hello_world" />
<com.example.testview.MyView
android:layout_width="wrap_content"
android:layout_height="wrap_content"
myview:titleText="我是文字内容"
myview:titleTextColor="#ff0000"
myview:titleTextSize="40sp"
/>
</LinearLayout>
这是我自己在家实验的时候写的了
在布局文件写好之后,就是在代码中显示了,我这里就直接贴出我的测试代码了
public class MyView extends View{
/**
* 文本
*/
private String mTitleText;
/**
* 文本的颜色
*/
private int mTitleTextColor;
/**
* 文本的大小
*/
private float mTitleTextSize;
/**
* 绘制时控制文本绘制的范围
*/
private Rect mBound;
private Rect mBound2;
private Paint mPaint;
private Paint mPaint2;
public MyView(Context context) {
this(context,null);
}
public MyView(Context context, AttributeSet attrs) {
this(context, attrs,0);
}
public MyView(Context context, AttributeSet attrs, int defStyleAttr) {
super(context, attrs, defStyleAttr);
initMyViewData(context, attrs);
}
private void initMyViewData(Context context,AttributeSet attrs){
//这里获取到我们在attrs.xml设置的declare-styleable
TypedArray array = context.obtainStyledAttributes(attrs, R.styleable.MyView);
//然后通过declare-styleable获取到之前定义在里面的几个属性
mTitleText = array.getString(R.styleable.MyView_titleText);
mTitleTextColor = array.getColor(R.styleable.MyView_titleTextColor, Color.BLACK);
mTitleTextSize = array.getDimension(R.styleable.MyView_titleTextSize, 36);
array.recycle(); //一定要调用,否则这次的设定会对下次的使用造成影响
/**
* 获得绘制文本的宽和高
*/
mPaint = new Paint();
mPaint2 = new Paint();
mPaint.setTextSize(mTitleTextSize);
mPaint2.setTextSize(mTitleTextSize);
// mPaint.setColor(mTitleTextColor);
mBound = new Rect();
mBound2 = new Rect();
//这句话我自己的理解是在mBound的矩形内,适配mTitleText第一个字符到最后一个字符的范围,这里是我第二和第三个参数填的0和字符串长度所以是第一个字符到最后一个字符的宽度范围
mPaint.getTextBounds(mTitleText, 0, mTitleText.length(), mBound);
Log.i("main", "结果:" + mBound.left + ",右边:" + mBound.right + ",上面:" + mBound.top + ",下面:" + mBound.bottom);
mPaint2.getTextBounds("我是第二行吗", 0, 6, mBound2);
}
@Override
protected void onLayout(boolean changed, int left, int top, int right,
int bottom) {
// TODO Auto-generated method stub
super.onLayout(changed, left, top, right, bottom);
}
@Override
protected void onMeasure(int widthMeasureSpec, int heightMeasureSpec) {
// TODO Auto-generated method stub
super.onMeasure(widthMeasureSpec, heightMeasureSpec);
}
@Override
protected void onDraw(Canvas canvas) {
// TODO Auto-generated method stub
super.onDraw(canvas);
Log.i("main", "开始画画");
mPaint.setColor(Color.YELLOW);
//在画布的x、y、right、bottom范围内画,画笔为mPaint
canvas.drawRect(0, 0, getMeasuredWidth(), getMeasuredHeight(), mPaint);
//设置画笔颜色
mPaint.setColor(mTitleTextColor);
// canvas.drawText(text, x, y, paint),第一个参数是我们需要绘制的文本,第三个参数是我们的画笔,
// 这两个不用多说,主要是第二和第三个参数的含义,这两个参数在不同的情况下的值还是不一样的,x默认是这个字符串的左边在屏幕的位置,
// 如果设置了paint.setTextAlign(Paint.Align.CENTER);那就是字符的中心,y是指定这个字符baseline在屏幕上的位置
canvas.drawText(mTitleText, 0, mBound2.height(), mPaint);
canvas.drawText("我是第二行吗", getWidth() / 2 - mBound2.width() / 2, getHeight() / 2 + mBound2.height() / 2, mPaint2);
}
}
在这里面我还是进行了一点实验的,不过都是针对方法的熟悉,并且在注释中已经有所体现,就不一一说明了,下面放出效果图
那么第一篇就到这里,这里主要是对环境方面的配置以及方法的初步功能识别,具体的细化研究就等以后几篇深入研究了