LayoutInflater:加载布局
基本用法:
mScrollView = (ScrollView) findViewById(R.id.scrollView_id);
//获取实例
LayoutInflater layoutInflater = LayoutInflater.from(this);
//加载布局
View buttonLayout = layoutInflater.inflate(R.layout.word_item, null);
mScrollView.addView(buttonLayout);
inflate()方法一般接收两个参数,第一个参数就是要加载的布局id,第二个参数是指给该布局的外部再嵌套一层父布局,如果不需要就直接传null。
先说一下,自己关于自定义控件Canvas,Paint的看法
Paint–画笔,你需要画什么样式的画,就需要什么样式的画笔
例:需要画一个红色的,10cm粗的矩形,那么你就要选择一个红色的,粗10cm的画笔
Canvas–可以将它理解为画布
那么,接下来,开始正文:
自定义view - - - view的绘制过程
有三个重要阶段onMeasure()、onLayout()和onDraw()
在layout的过程中需要用到measure过程中计算得到的每个View的测量大小,而draw过程需要layout确定每个view的位置才能进行绘制。
基本步骤:
1、自定义View的属性
2、在View的构造方法中获得我们自定义的属性
3、重写onMesure
4、重写onLayout(通常用于自定义viewGroup,自定义view很少用到)
5、重写onDraw
第一步:
自定义View的属性,首先在res/values/ 下建立一个attrs.xml , 在里面定义我们的属性和声明我们的整个样式。
demo:
<?xml version="1.0" encoding="utf-8"?>
<resources>
<declare-styleable name="ScratchView">
<!--蒙层的颜色-->
<attr name="maskColor" format="color|reference" />
<!--水印图片值-->
<attr name="watermark" format="reference" />
<!--擦除尺寸大小-->
<attr name="eraseSize" format="float" />
<!--最大比例-->
<attr name="maxPercent" format="integer" />
</declare-styleable>
</resources>
format是值该属性的取值类型
然后在布局中声明我们的自定义View,并设置属性值(不是必须)
第二步:在View的构造方法中获得我们自定义的属性
demo:
public CustomView(Context context, @Nullable AttributeSet attrs) {
super(context, attrs);
TypedArray typedArray = context.obtainStyledAttributes(attrs, R.styleable.ScratchView);
int maskColor = typedArray.getColor(R.styleable.ScratchView_maskColor, DEFAULT_MASKER_COLOR);
int watermarkResId = typedArray.getResourceId(R.styleable.ScratchView_watermark, -1);
float eraseSize = typedArray.getFloat(R.styleable.ScratchView_eraseSize, DEFAULT_ERASER_SIZE);
typedArray.recycle();
}
注意格式:typedArray.getFloat(R.styleable.ScratchView_***,defaultValue);
第三步:onMeasure()
onMeasure()方法,顾名思义就是用于测量视图的大小的。measure()方法接收两个参数,widthMeasureSpec和heightMeasureSpec,这两个值分别用于确定视图的宽度和高度的规格和大小。
MeasureSpec的值由specSize和specMode共同组成的,其中specSize记录的是大小,specMode记录的是规格。specMode一共有三种类型,如下所示:
MeasureSpec.EXACTLY:父视图希望子视图的大小是specSize中指定的大小,对应的也就是match_parent及固定尺寸
MeasureSpec.AT_MOST:子视图的大小最多是specSize中的大小,对应的也就是wrap_content
MeasureSpec.UNSPECIFIED:父视图不对子视图施加任何限制,这种情况比较少见,不太会用到。
获取测量模式、尺寸
int widthMode = MeasureSpec.getMode(widthMeasureSpec);
int widthSize = MeasureSpec.getSize(widthMeasureSpec);
如果你不想使用系统默认的测量方式,可以按照自己的意愿进行定制,重写onMeasure()方法。
如当我们需要绘制正方形,且android:layout_width
为match_parent
/ wrap_content
时,我们需要重写onMeasure( )
;
方式一:
@Override
protected void onMeasure(int widthMeasureSpec, int heightMeasureSpec) {
setMeasuredDimension(200, 200);
}
这样的话就把View默认的测量流程覆盖掉了,不管在布局文件中定义MyView这个视图的大小是多少,最终在界面上显示的大小都将会是200*200。
需要注意的是,在setMeasuredDimension()方法调用之后,我们才能使用getMeasuredWidth()和getMeasuredHeight()来获取视图测量出的宽高,以此之前调用这两个方法得到的值都会是0。
方式二:(我们这里给了一个默认值)
private int getMySize(int defaultSize, int measureSpec) {
int mySize = defaultSize;
int mode = MeasureSpec.getMode(measureSpec);
int size = MeasureSpec.getSize(measureSpec);
switch (mode) {
case MeasureSpec.UNSPECIFIED: {//如果没有指定大小,就设置为默认大小
mySize = defaultSize;
break;
}
case MeasureSpec.AT_MOST: {//如果测量模式是最大取值为size
//我们将大小取最大值,你也可以取其他值
mySize = size;
break;
}
case MeasureSpec.EXACTLY: {//如果是固定的大小,那就不要去改变它
mySize = size;
break;
}
}
return mySize;
}
@Override
protected void onMeasure(int widthMeasureSpec, int heightMeasureSpec) {
super.onMeasure(widthMeasureSpec, heightMeasureSpec);
int width = getMySize(100, widthMeasureSpec);
int height = getMySize(100, heightMeasureSpec);
if (width < height) {
height = width;
} else {
width = height;
}
setMeasuredDimension(width, height);
}
第四步:onLayout()
measure过程结束后,视图的大小就已经测量好了,接下来就是layout的过程了。正如其名字所描述的一样,这个方法是用于给视图进行布局的,也就是确定视图的位置。
host.layout(0, 0, host.mMeasuredWidth, host.mMeasuredHeight);
layout()方法接收四个参数,分别代表着左、上、右、下的坐标,当然这个坐标是相对于当前视图的父视图而言的。
在onLayout()过程结束后,我们就可以调用getWidth()方法和getHeight()方法来获取视图的宽高了。
getMeasureWidth()方法在measure()过程结束后就可以获取到了,而getWidth()方法要在layout()过程结束后才能获取到。
另外,getMeasureWidth()方法中的值是通过setMeasuredDimension()方法来进行设置的,而getWidth()方法中的值则是通过视图右边的坐标减去左边的坐标计算出来的。
两者在一般情况下都是相等的,除非用户在onlayout的时候childView.layout(0, 0, 200, 200);
,再次设置了具体值,而不是使用的getMeasureWidth()去计算,但此方式不推荐。
第五步:onDraw()
Paint,Canvas :http://www.cnblogs.com/yishujun/p/5559917.html
一、认识Paint:
Paint即画笔,在绘图过程中起到了极其重要的作用,画笔主要保存了颜色, 样式等绘制信息,指定了如何绘制文本和图形,画笔对象有很多设置方法,大体上可以分为两类,一类与图形绘制相关,一类与文本绘制相关。
以下是常用到的
图形绘制
- 设置绘制的颜色,a代表透明度,r,g,b代表颜色值。
setARGB(int a,int r,int g,int b);
类似:
//设置绘制图形的透明度
setAlpha(int a);
//设置绘制的颜色,使用颜色值来表示,该颜色值包括透明度和RGB颜色
setColor(int color);
- 设置画笔的样式,为FILL,FILL_OR_STROKE,或STROKE
Style.FILL: 实心 STROKE:空心 FILL_OR_STROKE:同时实心与空心
setStyle(Paint.Style style);
- 当画笔样式为STROKE或FILL_OR_STROKE时,设置笔刷的图形样式,如圆形样式 Cap.ROUND,或方形样式Cap.SQUARE
setStrokeCap(Paint.Cap cap);
- 当画笔样式为STROKE或FILL_OR_STROKE时,设置笔刷的粗细度
setStrokeWidth(float width);
- 设置是否使用抗锯齿功能,会消耗较大资源,绘制图形速度会变慢
setAntiAlias(boolean aa)
- 设定是否使用图像抖动处理,会使绘制出来的图片颜色更加平滑和饱满,图像更加清晰
setDither(boolean dither);
- 图像在动画进行中是否会滤掉对Bitmap图像的优化操作,本设置项依赖于dither和xfermode的设置
setFilterBitmap(boolean filter);
- 设置图像效果,使用Shader可以绘制出各种渐变效果
setShader(Shader shader);
- 设置图形重叠时的处理方式,如合并,取交集或并集,经常用来制作橡皮的擦除效果
setXfermode(Xfermode xfermode);
文本绘制
- 设置绘制文字的对齐方向
setTextAlign(Paint.Align align);
- 设置绘制文字x轴的缩放比例,可以实现文字的拉伸的效果
setTextScaleX(float scaleX);
- 设置绘制文字的字号大小
setTextSize(float textSize);
- 设置Typeface对象,即字体风格,包括粗体,斜体以及衬线体,非衬线体等
setTypeface(Typeface typeface);
- 设置带有下划线的文字效果
setUnderlineText(boolean underlineText);
- 设置带有删除线的效果
setStrikeThruText(boolean strikeThruText);
二、认识Canvas
Canvas类简单理解就是表示一块画布,可以在上面画我们想画的东西
Canvas中的方法很多,Canvas可以绘制的对象有:
- 弧线(arcs)
//基本语法
drawArc(RectF oval, float startAngle, float sweepAngle, boolean useCenter, Paint paint)
//参数说明
oval:RectF对象,定义的圆弧的形状和大小的范围。
startAngle:设置圆弧是从哪个角度来顺时针绘画的。
sweepAngle:设置圆弧扫过的角度。
useCenter:是否经过圆心
值得注意的是,这个参数在我们的 mPaint.setStyle(Paint.Style.STROKE); 设置为描边属性的时候,是看不出效果的。
paint:绘制时所使用的画笔。
填充颜色(argb和color)
Bitmap
// 第一种:矩阵变换
drawBitmap (Bitmap bitmap, Matrix matrix, Paint paint)
// 第二种:指定了图片左上角的坐标(距离坐标原点的距离)
drawBitmap (Bitmap bitmap, float left, float top, Paint paint)
// 第三种
drawBitmap (Bitmap bitmap, Rect src, Rect dst, Paint paint)
第三种 demo:
// 将画布坐标系移动到画布中央
canvas.translate(width/2,height/2);
// 指定图片绘制区域(左上角的四分之一)
Rect src = new Rect(0,0,bitmap.getWidth()/2,bitmap.getHeight()/2);
// 指定图片在屏幕上显示的区域
Rect dst = new Rect(0,0,200,200);
// 绘制图片
canvas.drawBitmap(bitmap,src,dst,null);
拓展:
//资源文件 (drawable/mipmap/ic_launcher):
Bitmap bitmap = BitmapFactory.decodeResource(context.getResources(),R.mipmap.ic_launcher);
//资源文件(assets):
Bitmap bitmap=null;
try {
InputStream is = mContext.getAssets().open("bitmap.png");
bitmap = BitmapFactory.decodeStream(is);
is.close();
} catch (IOException e) {
e.printStackTrace();
}
//内存卡文件:
Bitmap bitmap = BitmapFactory.decodeFile("/sdcard/bitmap.png");
//网络文件:
Bitmap bitmap = BitmapFactory.decodeStream(is);
is.close();
- 圆(circle和oval)
//基本语法
drawCircle(float cx, float cy, float radius,Paint paint)
//参数说明
cx:圆心X轴坐标
cy:圆心Y轴坐标
radius:圆半径
paint:绘制时所使用的画笔。
- 点(point)
//基本语法
drawPoint(float x, float y, Paint paint)
- 线(line)
//基本语法
drawLine(float startX, float startY, float stopX, float stopY, Paintpaint)
- 矩形(Rect)
//基本语法
drawRect(RectF rect, Paint paint)
- 图片(Picture)
drawPicture (Picture picture)
drawPicture (Picture picture, Rect dst)
drawPicture (Picture picture, RectF dst)
- 圆角矩形 (RoundRect)
//基本语法
drawRoundRect (RectF rect, float rx, float ry, Paint paint)
//参数说明
rect:RectF对象。
rx:x方向上的圆角半径。
ry:y方向上的圆角半径。
paint:绘制时所使用的画笔。
- 文本(text)
//基本语法
drawText (String text, float x, float y, Paint paint)
//参数说明
text:文本。
x:x默认是这个字符串的左边在屏幕的位置。
y:y是指定这个字符baseline在屏幕上的位置。
paint:绘制时所使用的画笔。
- 顶点(Vertices)
- 路径(path)
//基本语法
drawPath(Path path, Paint paint)
方法:
- 把当前的绘制的图像保存起来,让后续的操作相当于是在一个新的图层上的操作。
canvas.save();
- 把当前画布返回(调整)到上一个save()状态之前
canvas.restore();
- 把当前画布的原点移到(dx,dy),后面的操作都以(dx,dy)作为参照点,默认原点为(0,0)
canvas.translate(dx, dy);
- 扩大,x为水平方向的放大倍数,y为竖直方向的放大倍数
canvas.scale(x,y);
- 旋转,angle指旋转的角度,顺时针旋转。
canvas.rotate(angel);
RectF和Rect区别:精度的区别,一个float,一个int
RectF()构造一个无参的矩形
RectF(float left,float top,float right,float bottom)构造一个指定了4个参数的矩形
Rect和RecF的用法基本类似,只是参数为int类型,Rect(int left,int top,int right,int bottom)
常用Paint笔记:
private void initPaint() {
//画白色的圆画笔
mPaint = new Paint();
//抗锯齿
mPaint.setAntiAlias(true);
// 防抖动
mPaint.setDither(true);
// 开启图像过滤,对位图进行滤波处理。
mPaint.setFilterBitmap(true);
//画笔颜色
mPaint.setColor(Color.parseColor("#38B072"));
//空心圆
mPaint.setStyle(Paint.Style.STROKE);
//画笔宽度
mPaint.setStrokeWidth(mCircleR);
//设置笔刷样式为圆形
mPaint.setStrokeCap(Paint.Cap.ROUND);
}
demo:
链接下载地址:点这里,Github