有两个步骤:
(1) 定义View的属性,在xmls文件中
(2) 定义View的样式,在Java代码中
(3) 使用这个View,注意包的路径
下面详细说说。
(1)在res/values/ 下建立一个attrs.xml , 在里面定义我们的属性和声明我们的整个样式。比如
<?xml version="1.0" encoding="utf-8"?>
<resources>
<declare-styleable name="CustomTitleView">
<attr name="titleText" />
<attr name="titleTextColor" />
<attr name="titleTextSize" />
</declare-styleable>
</resources>
需要什么,就在declare-styleable标签中定义什么。方法网上有很多。
(2)在包下新建一个class,继承自View类,然后重写它的方法。主要重写的有5个方法,其中有3个是构造方法,一个是onDraw()方法,还有一个onMesure()。其中onMesure()可以调用系统的方法,但是另外4个方法必须重写。
构造方法一般如下:
/**
* 文本
*/
private String mTitleText;
/**
* 文本的颜色
*/
private int mTitleTextColor;
/**
* 文本的大小
*/
private int mTitleTextSize;
/**
* 绘制时控制文本绘制的范围
*/
private Rect mBound;
private Paint mPaint;
public CustomTitleView(Context context, AttributeSet attrs)
{
this(context, attrs, 0);
}
public CustomTitleView(Context context)
{
this(context, null);
}
/**
* 获得我自定义的样式属性
*
* @param context
* @param attrs
* @param defStyle
*/
public CustomTitleView(Context context, AttributeSet attrs, int defStyle)
{
super(context, attrs, defStyle);
/**
* 获得我们所定义的自定义样式属性
*/
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_titleTextColor:
// 默认颜色设置为黑色
mTitleTextColor = a.getColor(attr, Color.BLACK);
break;
case R.styleable.CustomTitleView_titleTextSize:
// 默认设置为16sp,TypeValue也可以把sp转化为px
mTitleTextSize = a.getDimensionPixelSize(attr, (int) TypedValue.applyDimension(
TypedValue.COMPLEX_UNIT_SP, 16, getResources().getDisplayMetrics()));
break;
}
}
a.recycle();
/**
* 获得绘制文本的宽和高
*/
mPaint = new Paint();
mPaint.setTextSize(mTitleTextSize);
// mPaint.setColor(mTitleTextColor);
mBound = new Rect();
mPaint.getTextBounds(mTitleText, 0, mTitleText.length(), mBound);
}
虽然有3个构造方法,但是为了减少代码的冗余度,前两个都是调用的第三个方法,所以只需要重写最后一个就可以了。
这里介绍下三个方法会被调用的场景,
- 第一个方法,一般我们这样使用时会被调用,View view = new View(context);
- 第二个方法,当我们在xml布局文件中使用View时,会在inflate布局时被调用,
<View
layout_width="match_parent"
layout_height="match_parent"/>。 - 第三个方法,跟第二种类似,但是增加style属性设置,这时inflater布局时会调用第三个构造方法。
<View
style="@styles/MyCustomStyle"
layout_width="match_parent"
layout_height="match_parent"/>。
onDraw()必须重写,onMeasure()需要重写时再重写,比如下面的例子,就只重写了onDraw().
@Override
protected void onMeasure(int widthMeasureSpec, int heightMeasureSpec)
{
super.onMeasure(widthMeasureSpec, heightMeasureSpec);
}
@Override
protected void onDraw(Canvas canvas)
{
mPaint.setColor(Color.YELLOW);
canvas.drawRect(0, 0, getMeasuredWidth(), getMeasuredHeight(), mPaint);
mPaint.setColor(mTitleTextColor);
canvas.drawText(mTitleText, getWidth() / 2 - mBound.width() / 2, getHeight() / 2 + mBound.height() / 2, mPaint);
}
(3) 下面就可以像正常使用系统的View一样使用你的自定义View了,但是要注意添加包的路径,路径就是这个View的Java代码的第一行,比如:
<?xml version="1.0" encoding="utf-8"?>
<LinearLayout
xmlns:android="http://schemas.android.com/apk/res/android"
xmlns:custom="http://schemas.android.com/apk/res-auto"
xmlns:tools="http://schemas.android.com/tools"
android:layout_width="match_parent"
android:layout_height="match_parent"
tools:context=".MainActivity">
<com.example.administrator.customview.CustomView
android:layout_width="200dp"
android:layout_height="100dp"
custom:titleText="3712"
custom:titleTextColor="#ff0000"
custom:titleTextSize="40sp" />
</LinearLayout>
这里,我自定义的View命名CustomView,包的路径就是java代码的第一行,
package com.example.administrator.customview;
这里有两个地方需要用到,一个是
xmlns:custom="http://schemas.android.com/apk/res-auto"
一个是
<com.example.administrator.customview.CustomView />
其实这两个是一样的,第一个xmls是在http://schemas.android.com/apk/res/后面加上路径,然后Android Studio给出的了修改建议,就改成了res-auto。
本文代码来自于:https://blog.youkuaiyun.com/lmj623565791/article/details/24252901
本文对View的三个构造函数的解释来自于:https://www.jianshu.com/p/84cee705b0d3
感谢!
完。