自定义View(一) 初识自定义view

时间:2023-02-09 14:43:56

转载请注明出处:http://blog.csdn.net/darling_R/article/details/54861805
本文出自:哎呀小嘿的博客

今天练习了一下自定义view,效果图如下:
自定义View(一) 初识自定义view
那么就来先了解一下一些属性的类型,方便后面使用:string , integer , dimension , reference , color…
1. reference:参考某一资源ID。
2. color:颜色值。
3. boolean:布尔值。
4. dimension:尺寸值。
5. float:浮点值。
6. integer:整型值。
7. string:字符串。
8. fraction:百分数。
9. enum:枚举值。
10. flag:位或运算。

注意:
属性定义时可以指定多种类型值。
(1)属性定义:

<declare-styleable name = "名称">
<attr name = "background" format = "reference|color" />
</declare-styleable>

(2)属性使用:

<ImageView
android:layout_width = "42dip"
android:layout_height = "42dip"
android:background = "@drawable/图片ID|#00FF00"/>

自定义view步骤可分为以下几步:

1。自定义属性
首先在res/value 文件夹下新建一个attrs.xml文件,在里面定义一些可以供用户自定义的一些属性。
例如,提取自定义控件的几个属性,分别为大圆的背景色,进度条颜色,进度条宽度,百分比字体大小,百分比字体颜色,圆的半径。

    <declare-styleable name="CirclePercentView">
<attr name="circleBg" format="color" />
<attr name="progressColor" format="color" />
<attr name="progressWidth" format="dimension" />
<attr name="percentSize" format="dimension" />
<attr name="percentColor" format="color" />
<attr name="radius" format="dimension" />
</declare-styleable>

2。新建一个类MyTextView继承View,重写三个构造方法。
这里要注意一点,自动生成的构造方法,里面是 super(),要把前两个改成 this(context,null)和this(context,attrs,0);或者在每个构造方法里都初始化一下也行;

    public CirclePercentView(Context context) {
this(context, null);
}

public CirclePercentView(Context context, AttributeSet attrs) {
this(context, attrs, 0);
}

public CirclePercentView(Context context, AttributeSet attrs, int defStyleAttr) {
super(context, attrs, defStyleAttr);
}

在第三个构造方法里面获取自定义的属性,在最后位置一定要记得调用 typedArray.recycle() 释放;

        TypedArray ta = context.obtainStyledAttributes(attrs, R.styleable.CirclePercentView, defStyleAttr, 0);

mCirColor = ta.getColor(R.styleable.CirclePercentView_circleBg, 0xff3d3d3d);//默认黑灰色

mPerTextColor = ta.getColor(R.styleable.CirclePercentView_percentColor, 0xffff3030);
mPerTextSize = ta.getDimensionPixelSize(R.styleable.CirclePercentView_percentSize, DensityUtils.sp2px(context, 14));

mProWidth = ta.getDimensionPixelSize(R.styleable.CirclePercentView_progressWidth, DensityUtils.dp2px(context, 5));
mProColor = ta.getColor(R.styleable.CirclePercentView_progressColor, 0xfff0f0f0);

mRadius = ta.getDimensionPixelSize(R.styleable.CirclePercentView_radius, DensityUtils.dp2px(context, 100));

ta.recycle();

紧接着,初始化一些所需要的画笔,便于后面绘制使用:

        mCirPaint = new Paint();
mCirPaint.setColor(mCirColor);

mPerPaint = new Paint();
mPerPaint.setColor(mPerTextColor);
mPerPaint.setTextSize(mPerTextSize);


mProPaint = new Paint();
mProPaint.setStyle(Paint.Style.STROKE);
mProPaint.setColor(mProColor);
mProPaint.setStrokeWidth(mProWidth);

mBounds = new Rect();
mRectF = new RectF();

3。这里就可以重写onMeasure了,计算自定义控件的宽高;

 @Override
protected void onMeasure(int widthMeasureSpec, int heightMeasureSpec) {
setMeasuredDimension(measureDimension(widthMeasureSpec), measureDimension(heightMeasureSpec));
}

private int measureDimension(int measureSpec) {
int result;
int specMode = MeasureSpec.getMode(measureSpec);
int specSize = MeasureSpec.getSize(measureSpec);
if (specMode == MeasureSpec.EXACTLY) {//指定宽高了
result = specSize;
} else {// 一般为WARP_CONTENT
result = 2 * mRadius;
if (specMode == MeasureSpec.AT_MOST) {
result = Math.min(result, specSize);
}
}
return result;
}

准备工作做完了,就可以把控件内容画出来了
4,重写onDraw方法,

    @Override
protected void onDraw(Canvas canvas) {
//画背景圆
canvas.drawCircle(getWidth() / 2, getHeight() / 2, mRadius, mCirPaint);
//画进度条
mRectF.set(getWidth() / 2 - mRadius + mProWidth / 2, getHeight() / 2 - mRadius + mProWidth / 2, getWidth() / 2 + mRadius - mProWidth / 2, getHeight() / 2 + mRadius - mProWidth / 2);
canvas.drawArc(mRectF, 270, 360 * mCurPercent / 100, false, mProPaint);
//画百分比文本
String text = mCurPercent + "%";
mPerPaint.getTextBounds(text, 0, text.length(), mBounds);
canvas.drawText(text, getWidth() / 2 - mBounds.width() / 2, getHeight() / 2 + mBounds.height() / 2, mPerPaint);

}

到这里,自定义的一个view就算完事了,下面就可以调用了;
在xml布局文件里这样引用:

<!-- 注意添加下面第二行,cust:是名字,可以随便叫-->
<LinearLayout xmlns:android="http://schemas.android.com/apk/res/android"
xmlns:cust="http://schemas.android.com/apk/res-auto"
xmlns:tools="http://schemas.android.com/tools"
android:id="@+id/activity_main"
android:layout_width="match_parent"
android:layout_height="match_parent"
android:gravity="center"
android:orientation="vertical"
tools:context="com.yh.customviewone.MainActivity">

<!--在这里引用attrs里面的属性名,设置属性值-->
<com.yh.customviewone.CirclePercentView
android:id="@+id/circleView"
android:layout_width="200dp"
android:layout_height="200dp"
cust:circleBg="#3d3d3d"
cust:percentColor="#ff0000"
cust:percentSize="50sp"
cust:progressColor="#0efefe"
cust:progressWidth="5dp"
cust:radius="100dp" />

</LinearLayout>

ps:

<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>

类似于生命全局变量一样,把共有的属性提取出来,在标签里引用就行,方便有多个自定义view时,重复多个属性,这样可以减少代码量

附上代码地址:https://github.com/XiaoHeia/CirclePercentView/tree/master