自定义View实现步骤:
1、自定义View的属性。
2、在View的构造方法中获得我们自定义的属性。
3、重写onMesure(非必须)。
4、重写onDraw。
新建attrs.xml
布局中
xmlns:app="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="com.cjf.customview.MainActivity">
android:layout_height="wrap_content"
android:layout_centerInParent="true"
app:titleText="4396"
android:padding="10dp"
app:titleTextColor="#ff0000"
app:titleTextSize="40sp"
/>
具体实现代码:
package com.cjf.customview.cutomtitleView;
import android.content.Context;
import android.content.res.TypedArray;
import android.graphics.Canvas;
import android.graphics.Color;
import android.graphics.Paint;
import android.graphics.Rect;
import android.support.annotation.Nullable;
import android.util.AttributeSet;
import android.util.TypedValue;
import android.view.View;
import com.cjf.customview.R;
import java.util.HashSet;
import java.util.Random;
import java.util.Set;
_/**
- Created by jackchenfeng on 2017/4/21.
*/
_public class CustomTitleViewextends View {
privateString mTitleText;//文本
private intmTitleColor;//文字颜色
private intmTitleSize;//文字大小
_/**
- 绘制时控制文本绘制的范围
*/
_privateRect mBound;
private PaintmPaint;
public CustomTitleView(Context context) {
this(context, null);
}
publicCustomTitleView(Context context,@Nullable AttributeSet attrs) {
this(context,attrs,0);
}
publicCustomTitleView(Context context,@Nullable AttributeSet attrs, intdefStyleAttr) {
super(context,attrs,defStyleAttr);
TypedArray a = context.getTheme().obtainStyledAttributes(attrs,R.styleable.CustomTitleView,defStyleAttr,0);
int n = a.getIndexCount();
for (inti = 0;i < n;i++) {
intattr = a.getIndex(i);
switch (attr) {
caseR.styleable.CustomTitleView_titleText:
mTitleText= a.getString(attr);
break;
case R.styleable.CustomTitleView_titleTextColor:
mTitleColor= a.getColor(attr,Color.BLACK);
break;
case R.styleable.CustomTitleView_titleTextSize:
mTitleSize= (int) a.getDimension(attr,TypedValue.applyDimension(TypedValue.COMPLEX_UNIT_SP,16,getResources().getDisplayMetrics()));
break;
}
}
a.recycle();
mPaint= newPaint();
mPaint.setTextSize(mTitleSize);
mBound= newRect();
mPaint.getTextBounds(mTitleText,0,mTitleText.length(),mBound);
this.setOnClickListener(newOnClickListener() {
@Override
public voidonClick(View v) {
mTitleText= randomText();
postInvalidate();
}
});
}
privateString randomText() {
Random random = newRandom();
Set
while (set.size() <4) {
intrandomInt = random.nextInt(10);
set.add(randomInt);
}
StringBuffer sb = newStringBuffer();
for (Integer i : set) {
sb.append(""+ i);
}
returnsb.toString();
}
@Override
protected voidonMeasure(intwidthMeasureSpec, intheightMeasureSpec) {
_/**
- 重写之前先了解MeasureSpec的specMode,一共三种类型:
EXACTLY:一般是设置了明确的值或者是MATCH_PARENT
AT_MOST:表示子布局限制在一个最大值内,一般为WARP_CONTENT
UNSPECIFIED:表示子布局想要多大就多大,很少使用
*/
_intwidthMode = MeasureSpec.getMode(widthMeasureSpec);
int widthSize = MeasureSpec.getSize(widthMeasureSpec);
int heightMode = MeasureSpec.getMode(heightMeasureSpec);
int heghtSize = MeasureSpec.getSize(heightMeasureSpec);
int width;
int height;
if (widthMode == MeasureSpec.EXACTLY) {
width = widthSize;
}else {
mPaint.setTextSize(mTitleSize);
mPaint.getTextBounds(mTitleText,0,mTitleText.length(),mBound);
float textWidth =mBound.width();
int desired = (int) (getPaddingLeft() + textWidth + getPaddingRight());
width = desired;
}
if(heightMode == MeasureSpec.EXACTLY) {
height = heghtSize;
}else {
mPaint.setTextSize(mTitleSize);
mPaint.getTextBounds(mTitleText,0,mTitleText.length(),mBound);
float textHeight =mBound.height();
int desired = (int) (getPaddingTop() + textHeight + getPaddingBottom());
height = desired;
}
setMeasuredDimension(width,height);
}
@Override
protected voidonDraw(Canvas canvas) {
super.onDraw(canvas);
mPaint.setColor(Color.YELLOW);
canvas.drawRect(0,0,getMeasuredWidth(),getMeasuredHeight(),mPaint);
mPaint.setColor(mTitleColor);
//getwidth()获得整个view的宽度
canvas.drawText(mTitleText,getWidth() / 2- mBound.width() /2,getHeight() / 2+ mBound.height() /2,mPaint);
final int height = getHeight();
final int width = getWidth();
int[] point;
Random random =new Random();
for (inti = 0;i < 50;i++) {
intranColor = 0xff000000| random.nextInt(0x00ffffff);//随机颜色
mPaint.setColor(ranColor);
point = getPoint(height,width);
_/**
- drawCircle (float cx, float cy, float radius, Paint paint)
- float cx:圆心的x坐标。
- float cy:圆心的y坐标。
- float radius:圆的半径。
- Paint paint:绘制时所使用的画笔。
*/
_canvas.drawCircle(point[0],point[1],3,mPaint);
}
int[] line;
for (inti = 0;i < 5;i++) {
intranColor = 0xff000000| random.nextInt(0x00ffffff);//随机颜色
mPaint.setColor(ranColor);
line = getLine(height,width);
_/**
- startX:起始端点的X坐标。
*startY:起始端点的Y坐标。
*stopX:终止端点的X坐标。
*stopY:终止端点的Y坐标。
*paint:绘制直线所使用的画笔。
*/
_canvas.drawLine(line[0],line[1],line[2],line[3],mPaint);
}
}
private int[]getLine(intheight, intwidth) {
int[] tempCheckNum = {0,0,0,0};
for (inti = 0;i < 4;i += 2) {
tempCheckNum[i] = (int) (Math.random() * width);
tempCheckNum[i +1] = (int) (Math.random() * height);
}
returntempCheckNum;
}
private int[]getPoint(intheight, intwidth) {
int[] tempCheckNum = {0,0,0,0};
tempCheckNum[0] = (int) (Math.random() * width);
tempCheckNum[1] = (int) (Math.random() * height);
return tempCheckNum;
}
}
效果图:点击可随机产生数字