自定义View之前要掌握的东西
一、Android绘图三大API 1.Canvas类
(1)功能:Canvas代表了"依附"于指定View的画布,通过Canvas类的成员方法能够实现绘制各种图形。绘制一个图形由四部分组成:Bitmap、Canvas、Path/Rect/text等、Paint,其中Bitmap为绘制图形存放的像素位图,Canvas用于提供绘制图像方法、Paint为画笔、Path/Rect/text等分别为绘制图形的(轨迹/矩形/文本)。
(2)构造方法 Canvas() :构造空的canvas对象 Canvas(Bitmap bitmap) :构造一个Canvas对象,并指定其bitmap
(3)常用方法
boolean | clipRegion(Region region):剪切指定区域 |
void | drawBitmap(Bitmap bitmap, float left, float top, Paint paint):在指定点(x,y)使用指定的画笔paint绘制位图 |
void | drawBitmap(Bitmap bitmap, Rect src, Rect dst, Paint paint):在指定点(x,y)绘制从源位图中"挖取"的一块 |
void | drawCircle(float cx, float cy, float radius, Paint paint):绘制原点为(cx,cy),半径为radius的圆 |
void | drawLine(float startX, float startY, float stopX, float stopY, Paint paint):绘制一条起点为(startX,startY),终点为(stopX,stopY)直线 |
void | drawLines(float[] pts, int offset, int count, Paint paint):绘制多条直线,其中pts为一个浮点型数组提供绘制一条直接所需的数据(4个/条),count为绘制直线的条数 |
void | drawOval(RectF oval, Paint paint):绘制一个椭圆,oval为绘制椭圆的矩形边界 |
void | drawPath(Path path, Paint paint):沿着路径path绘制图形 |
void | drawPoint(float x, float y, Paint paint):绘制一个点(x,y) |
void | drawPoints(float[] pts, int offset, int count, Paint paint):绘制pts数组中的多个点(2个值/点) |
void | drawRect(float left, float top, float right, float bottom, Paint paint):绘制一个矩形,其参数为距离屏幕边界的距离(边界为0) |
void | drawRoundRect(RectF rect, float rx, float ry, Paint paint):使用指定的画笔绘制圆角矩形,其中rect为矩形边界、rx/ry分别为以矩形顶点为(0,0)相对位置圆的x半径、y半径 |
void | drawText(String text, float x, float y, Paint paint):以(x,y)为原点,使用指定画笔绘制文本 |
void | drawTextOnPath(String text, Path path, float x, float y, Paint paint):以(x,y)为原点,使用指定的画笔沿着指定路径绘制文本 |
int | getHeight():返回当前图层的高度 |
int | getWidth():返回当前绘图层的宽度 |
void | rotate(float degrees):对Canvas执行旋转变换; |
void | setBitmap(Bitmap bitmap):指定Canvas(画布)的位图Bitmap |
void | translate(float dx, float dy):相对于当前位置移动Canvas。向右移动dx距离(dx为负数即向左移动);向下移动dy距离(dy为负数即向上移动) |
void | skew(float sx,float sy):对Canvas执行倾斜变换 |
2.Paint类
(1)功能:Paint代表了Canvas上的画笔,Paint类主要用于设置绘制风格,包括画笔的颜色、画笔笔触粗细、填充风格等。
(2)构造方法 Paint() :使用默认设置构造一个Paint对象 Paint(int flags) :使用指定flags构造一个Paint对象 Paint(Paint paint) :使用已有画笔的设置构造一个新的Paint对象
(3)常用方法
void | reset():恢复画笔到默认配置 |
void | setARGB(int a, int r, int g, int b):设置画笔透明度和颜色,其参数分别代表透明度、红色、绿色、蓝色 |
void | setAlpha(int a):设置画笔的透明度 |
void | setAntiAlias(boolean aa):设置是否抗锯齿 |
void | setColor(int color):设置画笔的颜色 |
void | setFlags(int flags):设置画笔的flags(HINTING_OFF、HINTING_ON等) |
void | setHinting(int mode):设置画笔的提示模式 |
PathEffect | setPathEffect(PathEffect effect):设置绘制路径时的路径效果(ComposePathEffect, CornerPathEffect, DashPathEffect, DiscretePathEffect, PathDashPathEffect, SumPathEffect) |
Rasterizer | setRasterizer(Rasterizer rasterizer) |
Shader | setShader(Shader shader):设置画笔的填充效果(BitmapShader, ComposeShader, LinearGradient, RadialGradient, SweepGradient) |
void | setShadowLayer(float radius, float dx, float dy, int color):设置阴影效果 |
void | setStrokeJoin(Paint.Join join):设置画笔转弯处的连接风格(BEVEL-直线、MITER -锐角、ROUND-圆弧 ) |
void | setStrokeWidth(float width):设置画笔宽度 |
void | setStyle(Paint.Style style):设置Paint的填充风格(FILL-、FILL_AND_STROKE、STROKE ) |
void | setTextAlign(Paint.Align align):设置绘制文本时的文字对齐方式(CENTER -居中、LEFT-靠左、RIGHT -靠右:以(x,y)为中心) |
void | setTextSize(float textSize):设置绘制文本的文字大小 |
(1)功能:Android提供的Path类预先在View上将N个点连成一条"路径",然后调用Canvas的drawPath(path,paint)方法即可沿着路径绘制图形。另外,Android还提供了PathEffect来定义绘制路径图形效果,其包含ComposePathEffect、CornerPathEffect、DashPathEffect、DiscretePathEffect、PathDashPathEffect、SumPathEffect六种效果。
(2)构造方法 Path():构造一个Path对象 Path(Path src) :从另一个Path对象构造一个新的Path对象
(3)常用方法
boolean | isEmpty():判定Path对象是否为空(即不包含直线或曲线),如果为空返回true |
void | lineTo(float x, float y):增加一条从上一点到当前点(x,y)的直线 |
void | moveTo(float x, float y):设置下一个轮廓的开始点(x,y) |
void | rLineTo(float dx, float dy):以坐标为参照增加一条从上一点到当前点(x,y)的直线 |
void | rMoveTo(float dx, float dy):以坐标为参照设置下一个轮廓的开始点(x,y) |
void | reset():删除Path对象的所有直线和曲线 |
void | set(Path src):将当前Path对象的内容替换为对象src所包含的内容 |
void | setFillType(Path.FillType ft):设置路径的填充类型 |
void | setLastPoint(float dx, float dy):设置路径的最后一个点的坐标为(x,y) |
void | transform(Matrix matrix):通过matrix转换该路径中的点 |
void | close() :释放资源 |
1、自定义View的属性
2、在View的构造方法中获得我们自定义的属性
3、重写onMesure
4、重写onDraw
1、自定义View的属性,首先在res/values/ 下建立一个attrs.xml , 在里面定义我们的属性和声明我们的整个样式。
format是值该属性的取值类型:
reference : 资源id
color : 颜色值
boolean : 布尔值
dimension : 尺寸值
float : 浮点值
integer : 整形值
string : 字符串
fraction : 百分数
enum : 枚举值
flag : 位或运算
<?
xml version=
"1.0"
encoding=
"utf-8"
?>
<resources>
<!--圆-->
<attr name= "rotateBack" format= "color" />
<declare-styleable name= "RotateView" >
<attr name= "rotateBack" />
</declare-styleable>
</resources>
<resources>
<!--圆-->
<attr name= "rotateBack" format= "color" />
<declare-styleable name= "RotateView" >
<attr name= "rotateBack" />
</declare-styleable>
</resources>
//这是是获取值的
public RotateView(Context context
, AttributeSet attrs
, int defStyleAttr) {
super(context , attrs , defStyleAttr) ;
TypedArray a = context.getTheme().obtainStyledAttributes(attrs , R.styleable. RotateView ,defStyleAttr , 0) ;
int n = a.getIndexCount() ;
for ( int i = 0 ; i < n ; i++ )
{
int attr = a.getIndex(i) ;
switch (attr){
case R.styleable. RotateView_rotateBack:
rotateBack = a.getColor(attr ,Color. BLUE) ;
Log. d( TAG , "颜色值---------->"+ rotateBack) ;
break;
}
}
a.recycle() ;
init() ;
}
super(context , attrs , defStyleAttr) ;
TypedArray a = context.getTheme().obtainStyledAttributes(attrs , R.styleable. RotateView ,defStyleAttr , 0) ;
int n = a.getIndexCount() ;
for ( int i = 0 ; i < n ; i++ )
{
int attr = a.getIndex(i) ;
switch (attr){
case R.styleable. RotateView_rotateBack:
rotateBack = a.getColor(attr ,Color. BLUE) ;
Log. d( TAG , "颜色值---------->"+ rotateBack) ;
break;
}
}
a.recycle() ;
init() ;
}
初始PaInt
/**
* 初始化
*/
public void init(){
mPaint = new Paint() ;
//样式填充分3种 Paint.Style.FILL :填充内部 Paint.Style.FILL_AND_STROKE :填充内部和描边 Paint.Style.STROKE :仅描边
mPaint.setStyle(Paint.Style. FILL) ;
//颜色
mPaint.setColor( rotateBack) ;
//锯齿功能
mPaint.setAntiAlias( true) ;
//画笔宽度
mPaint.setStrokeWidth( 4) ;
//设置阴影
// mPaint.setShadowLayer(160,305,305,Color.GREEN);
mWidth = 200 ;
mHigth = 200 ;
rotate( true) ;
}
* 初始化
*/
public void init(){
mPaint = new Paint() ;
//样式填充分3种 Paint.Style.FILL :填充内部 Paint.Style.FILL_AND_STROKE :填充内部和描边 Paint.Style.STROKE :仅描边
mPaint.setStyle(Paint.Style. FILL) ;
//颜色
mPaint.setColor( rotateBack) ;
//锯齿功能
mPaint.setAntiAlias( true) ;
//画笔宽度
mPaint.setStrokeWidth( 4) ;
//设置阴影
// mPaint.setShadowLayer(160,305,305,Color.GREEN);
mWidth = 200 ;
mHigth = 200 ;
rotate( true) ;
}
mPaint.setStyle(Paint.Style.
FILL)
;
Paint.Style.FILL :填充内部
Paint.Style.FILL_AND_STROKE :填充内部和描边
Paint.Style.FILL_AND_STROKE :填充内部和描边
Paint.Style.STROKE :仅描边
一定要引入 xmlns:custom="http://schemas.android.com/apk/res/com.example.customview01"
<?
xml version=
"1.0"
encoding=
"utf-8"
?>
<LinearLayout xmlns: android = "http://schemas.android.com/apk/res/android"
android :layout_width= "match_parent"
android :gravity= "center"
android :layout_height= "match_parent"
xmlns: custom = "http://schemas.android.com/apk/res-auto"
android :weightSum= "1" >
<com.example.jiangtao.testevent.custom_view.CustomTitleView
android :layout_width= "wrap_content"
android :layout_height= "wrap_content"
custom :titleText = "2342"
android :layout_gravity= "center"
android :id= "@+id/custom_title_view"
android :padding= "20dp"
custom :mTitleTextColor= "#000000"
android :layout_centerInParent= "true"
custom :titleTextSize= "50sp"
/>
</LinearLayout>
<LinearLayout xmlns: android = "http://schemas.android.com/apk/res/android"
android :layout_width= "match_parent"
android :gravity= "center"
android :layout_height= "match_parent"
xmlns: custom = "http://schemas.android.com/apk/res-auto"
android :weightSum= "1" >
<com.example.jiangtao.testevent.custom_view.CustomTitleView
android :layout_width= "wrap_content"
android :layout_height= "wrap_content"
custom :titleText = "2342"
android :layout_gravity= "center"
android :id= "@+id/custom_title_view"
android :padding= "20dp"
custom :mTitleTextColor= "#000000"
android :layout_centerInParent= "true"
custom :titleTextSize= "50sp"
/>
</LinearLayout>
系统帮我们测量的高度和宽度都是MATCH_PARNET,当我们设置明确的宽度和高度时,系统帮我们测量的结果就是我们设置的结果,当我们设置为WRAP_CONTENT,或者MATCH_PARENT系统帮我们测量的结果就是MATCH_PARENT的长度。
所以,当设置了WRAP_CONTENT时,我们需要自己进行测量,即重写onMesure方法”:
重写之前先了解MeasureSpec的specMode,一共三种类型:
EXACTLY:一般是设置了明确的值或者是MATCH_PARENT
AT_MOST:表示子布局限制在一个最大值内,一般为WARP_CONTENT
UNSPECIFIED:表示子布局想要多大就多大,很少使用
@Override
protected void onMeasure( int widthMeasureSpec , int heightMeasureSpec) {
super.onMeasure(widthMeasureSpec , heightMeasureSpec) ;
// 重写onMeasure的目的是处理warp_content模式
// 获取宽度的模式
int widthSpecMode = MeasureSpec. getMode(widthMeasureSpec) ;
// 获取高度的模式
int heightSpecMode = MeasureSpec. getMode(heightMeasureSpec) ;
// 获取宽度的规格
int widthSpecSize = MeasureSpec. getSize(widthMeasureSpec) ;
// 获取高度的规格
int heightSpecSize = MeasureSpec. getSize(heightMeasureSpec) ;
// 如果宽高的模式都是warp_content,则使用默认的宽高值
if (widthSpecMode == MeasureSpec. AT_MOST && heightSpecMode == MeasureSpec. AT_MOST) {
setMeasuredDimension( mWidth , mHigth) ;
}
// 如果只有宽度模式是warp_content,则设置宽度为默认值,高度为测量出的值
else if (widthSpecMode == MeasureSpec. AT_MOST) {
setMeasuredDimension( mWidth , heightSpecSize) ;
}
// 如果只有高度模式是warp_content,则设置高度为默认值,宽度为测量出的值
else if (heightSpecMode == MeasureSpec. AT_MOST) {
setMeasuredDimension(widthSpecSize , mHigth) ;
}
}
protected void onMeasure( int widthMeasureSpec , int heightMeasureSpec) {
super.onMeasure(widthMeasureSpec , heightMeasureSpec) ;
// 重写onMeasure的目的是处理warp_content模式
// 获取宽度的模式
int widthSpecMode = MeasureSpec. getMode(widthMeasureSpec) ;
// 获取高度的模式
int heightSpecMode = MeasureSpec. getMode(heightMeasureSpec) ;
// 获取宽度的规格
int widthSpecSize = MeasureSpec. getSize(widthMeasureSpec) ;
// 获取高度的规格
int heightSpecSize = MeasureSpec. getSize(heightMeasureSpec) ;
// 如果宽高的模式都是warp_content,则使用默认的宽高值
if (widthSpecMode == MeasureSpec. AT_MOST && heightSpecMode == MeasureSpec. AT_MOST) {
setMeasuredDimension( mWidth , mHigth) ;
}
// 如果只有宽度模式是warp_content,则设置宽度为默认值,高度为测量出的值
else if (widthSpecMode == MeasureSpec. AT_MOST) {
setMeasuredDimension( mWidth , heightSpecSize) ;
}
// 如果只有高度模式是warp_content,则设置高度为默认值,宽度为测量出的值
else if (heightSpecMode == MeasureSpec. AT_MOST) {
setMeasuredDimension(widthSpecSize , mHigth) ;
}
}
从写onDraw()
@TargetApi(Build.VERSION_CODES.
LOLLIPOP)
@Override
protected void onDraw(Canvas canvas) {
super.onDraw(canvas) ;
int paddingLeft = getPaddingLeft() ;
int paddingRight = getPaddingRight() ;
int paddingTop = getPaddingTop() ;
int paddingBottom = getPaddingBottom() ;
int width = getWidth() - paddingLeft - paddingRight ;
int height = getHeight() - paddingBottom - paddingTop ;
mPaint.setColor( rotateBack) ;
//画布设置颜色
// canvas.drawColor(Color.RED);
//画圆(第一个参数是x点、 第二个是y点、 第三个半径 )
radius = Math. min(width ,height)/ 2 ;
canvas.drawCircle(paddingLeft+width/ 2 ,paddingTop+height/ 2 , radius , mPaint) ;
//画线startX:起始端点的X坐标。startY:起始端点的Y坐标。stopX:终止端点的X坐标。stopY:终止端点的Y坐标
// canvas.drawLine(0, 0, 100, 100,mPaint);
//画多条直线 前两个表示的是直线起点的横纵坐标,后两个表示的是直线终点的横纵坐标。(两两为一个点)
// float []pts={10,10,100,100,200,200,400,400};
// canvas.drawLines(pts,mPaint);
// 绘制圆角矩形
// RectF re1 = new RectF(30,30, 200, 200);
// canvas.drawRoundRect(re1, 30,30, mPaint);
// 绘制椭圆
// RectF re11 = new RectF(30,30,300, 200);
// canvas.drawOval(re11, mPaint);
//定义一个Path对象,封闭成一个三角形并根据Path对象绘制
// Path path1 = new Path();
// path1.moveTo(10, 340);
// path1.lineTo(70, 340);
// path1.lineTo(40, 290);
// path1.close();
// canvas.drawPath(path1, mPaint);
// 根据Path绘制五角形
// Path path2 = new Path();
// path2.moveTo(26, 360);
// path2.lineTo(54, 360);
// path2.lineTo(70, 392);
// path2.lineTo(40, 420);
// path2.lineTo(10, 392);
// path2.close();
// canvas.drawPath(path2, mPaint);
//c.绘制正方形
// canvas.drawRect(170,80,230,140,mPaint);
}
@Override
protected void onDraw(Canvas canvas) {
super.onDraw(canvas) ;
int paddingLeft = getPaddingLeft() ;
int paddingRight = getPaddingRight() ;
int paddingTop = getPaddingTop() ;
int paddingBottom = getPaddingBottom() ;
int width = getWidth() - paddingLeft - paddingRight ;
int height = getHeight() - paddingBottom - paddingTop ;
mPaint.setColor( rotateBack) ;
//画布设置颜色
// canvas.drawColor(Color.RED);
//画圆(第一个参数是x点、 第二个是y点、 第三个半径 )
radius = Math. min(width ,height)/ 2 ;
canvas.drawCircle(paddingLeft+width/ 2 ,paddingTop+height/ 2 , radius , mPaint) ;
//画线startX:起始端点的X坐标。startY:起始端点的Y坐标。stopX:终止端点的X坐标。stopY:终止端点的Y坐标
// canvas.drawLine(0, 0, 100, 100,mPaint);
//画多条直线 前两个表示的是直线起点的横纵坐标,后两个表示的是直线终点的横纵坐标。(两两为一个点)
// float []pts={10,10,100,100,200,200,400,400};
// canvas.drawLines(pts,mPaint);
// 绘制圆角矩形
// RectF re1 = new RectF(30,30, 200, 200);
// canvas.drawRoundRect(re1, 30,30, mPaint);
// 绘制椭圆
// RectF re11 = new RectF(30,30,300, 200);
// canvas.drawOval(re11, mPaint);
//定义一个Path对象,封闭成一个三角形并根据Path对象绘制
// Path path1 = new Path();
// path1.moveTo(10, 340);
// path1.lineTo(70, 340);
// path1.lineTo(40, 290);
// path1.close();
// canvas.drawPath(path1, mPaint);
// 根据Path绘制五角形
// Path path2 = new Path();
// path2.moveTo(26, 360);
// path2.lineTo(54, 360);
// path2.lineTo(70, 392);
// path2.lineTo(40, 420);
// path2.lineTo(10, 392);
// path2.close();
// canvas.drawPath(path2, mPaint);
//c.绘制正方形
// canvas.drawRect(170,80,230,140,mPaint);
}
滚动
/**
* 根据标签判断滚动
* @param flag
*/
public void rotate( boolean flag){
if (flag== true){
RotateAnimation ra = new RotateAnimation( 0 , 360 ,
Animation. RELATIVE_TO_SELF , 0.5F ,
Animation. RELATIVE_TO_SELF , 0.5F) ;
ra.setDuration( 1000) ;
ra.setRepeatCount(- 1) ;
this.startAnimation(ra) ;
}
}
* 根据标签判断滚动
* @param flag
*/
public void rotate( boolean flag){
if (flag== true){
RotateAnimation ra = new RotateAnimation( 0 , 360 ,
Animation. RELATIVE_TO_SELF , 0.5F ,
Animation. RELATIVE_TO_SELF , 0.5F) ;
ra.setDuration( 1000) ;
ra.setRepeatCount(- 1) ;
this.startAnimation(ra) ;
}
}
资料来源于网络希望对你有帮助,菜鸟一枚正在起飞中~~~~~~~~~