Android Canvas 说明
来源:互联网 发布:sony vegas mac 编辑:程序博客网 时间:2024/06/06 09:27
Canvas 画布,用于在位图上进行绘制,内部关联一个mutable Bitmap, canvas在一系列操作后,展现在该Bitmap上。
什么时候有Canvas?
1. 自定义view时, onDraw、dispatchDraw
2. SurfaceHolder.lockCanvas(); 操作SurfaceView时需要用到Canvas
3. 自行创建。
Canvas c = new Canvas(bitmap);//要求参数bitmap为一个可变的Bitmap
或 Canvas c = new Canvas(); c.setBitmap(b);
API
canvas.drawPoint(100, 200, paint); //画像素点
canvas.drawPoints(new float[]{100,200, 100,220}, paint); //一组点 每两个元素表示点x,y
canvas.drawLine(50, 200, 80, 300, paint); //直线两点x,y x1,y1确定
canvas.drawLines(new float[]{50, 220, 100, 330, 115, 138, 459, 388}, paint); //一组直线
canvas.drawRect(rect, paint); //画矩形
canvas.drawRoundRect(new RectF(200, 10, 400, 80), 10, 80,paint); //圆角矩形 10:x方向圆角半径 80:y方向圆角半径
canvas.drawCircle(300, 700, 180, paint); //圆形 圆心x,y和半径值
canvas.drawArc(new RectF(100,700,400,1000), 180, 90,false,paint);//以矩形为边界,绘制弧形。顺时针绘制。0度在中心点到右水平线。true表示会连接到中心点,false不会连接,只会连接起始点和终点
canvas.drawOval(new RectF(100,700,200,900), p); //以矩形为边界,绘制椭圆。 如果矩形为正方形,那绘制的就是圆形
canvas.drawText(…) // 绘制文本
canvas.drawPath(path, p); //绘制出路径 路径内包含一些图形
canvas.drawTextOnPath(text, path, h, v, p); //沿着路径的图形绘制文本。h表示距离绘制的起点位置 v表示距离路径的位置。 当顺时针时v=0,文本紧贴图形外部;v<0离在图形外越来越远。逆时针时v=0,文本在图形内部;v>0文本离图形边越来越远
canvas.setDrawFilter(new PaintFlagsDrawFilter(0, Paint.ANTI_ALIAS_FLAG | Paint.FILTER_BITMAP_FLAG)); // 抗锯齿
canvas.drawBitmap(bmp, 0, 0, paint);
canvas.drawBitmap(bmp, matrix, paint);多边形绘制
Path path = new Path();
path.moveTo(x, y); //起始点path.lineTo(x, y); //到某点画直线
。。。
path.lineTo(x, y);
path.close();
canvas.drawPath(path, paint);
位移、旋转、缩放、扭曲(倾斜)
canvas.translate(dx, dy); 位移 即将(0,0)原点移到 (dx,dy)
canvas.rotate(float degrees); 默认以view的(0,0)原点 旋转
canvas.rotate(float degrees, float px, float py);
内部会先translate(px,py); 再rotate(degrees);再translate(-px,-py);
旋转后,x、y轴的指向也就改变了
canvas.scale(float sx, float sy); 以view的(0,0)为缩放中心
scale(float sx, float sy, float px, float py) ;
内部: translate(px, py);
scale(sx, sy);
translate(-px, -py); 这时平移的坐标相对于原来的坐标比例为: -px*sx, -py*sy
例
- paint.setColor(Color.BLACK);
- canvas.drawLine(0,0,100,500,paint);
- canvas.translate(50, 50);
- canvas.scale(0.5f,0.5f);
- paint.setColor(Color.BLUE);
- canvas.drawLine(0,0,100,500,paint);
- canvas.translate(-50, -50);
- // canvas.scale(0.5f, 0.5f, 50, 50);
- paint.setColor(Color.CYAN);
- canvas.drawLine(0,0,100,500,paint);
上例先绘制一条从(0,0)开始的 到 (100,500) 的 黑色线段;
平移(50,50),xy缩小0.5倍。 这时绘制的起始点(0,0) 即是平移后的(50,50)这个位置, 结束点(100,500)即变为(50,250),蓝色线段;
最后再平移(-50,-50),即只移动(-50*0.5,-50*0.5)=> (-25,-25), 以其为(0,0),绘制结束点为(50,250)的 青色线段
如下图:
canvas.skew(float sx, float sy);sx或sy为倾斜角度的tan值
save和restore
save就是保存当前的; restore 恢复、回退到上次save之前的状态。
可以多次save,再restoreToCount(int count);回退到某次save后。
int count = save(); 每save一次都返回一个count ; 或 int count = getSaveCount();
save(); Saves the current matrix and clip onto a private stack. 对应的flag:MATRIX_SAVE_FLAG | CLIP_SAVE_FLAG
saveLayer(); 不含alpha; 图层需要一个矩形的限定区和paint画笔; 可以指定其它flag
saveLayerAlpha(); 含alpha;图层需要一个矩形的限定区和paint画笔; 可以指定其它flag.(保存成一个透明度为a的,大小为矩形r的图层)
Canvas.MATRIX_SAVE_FLAG | Canvas.CLIP_SAVE_FLAG
| Canvas.HAS_ALPHA_LAYER_SAVE_FLAG | Canvas.FULL_COLOR_LAYER_SAVE_FLAG
| Canvas.CLIP_TO_LAYER_SAVE_FLAG; //Canvas.ALL_SAVE_FLAG 含所有5种flag
clip
clipRect(rect,...);
clipPath(path,...);
clipRegion(...); //已过时,类似操作推荐用 clipRect
canvas.save();Region region = new Region();region.set(new Rect(150, 0, 600, 700));region.op(new Rect(0,0, 200, 300), Region.Op.UNION);canvas.clipRegion(region); //裁剪范围canvas.drawColor(Color.RED);//将bitmap绘制到相应的regioncanvas.restore();
public enum Op {
DIFFERENCE(0), //区别上一个,即去掉上一个图形所占区域
INTERSECT(1), //交集
UNION(2), //并集
XOR(3), //去掉交集的部份
REVERSE_DIFFERENCE(4), //反转,即区别下一个,即去掉当前图形所占区域
REPLACE(5); //替换; 只保留当前图形
}
在执行了canvas的裁剪、平移、缩放、扭曲(skew)等操作,将影响其后执行的绘制draw的动作
所以一般在执行类似操作时 需要一对 save和restore
//----------------------------------------------------------------------------------------------------------------------------------------
这里学习hongyang(http://blog.csdn.net/lmj623565791/article/details/44098729)博客中的知识发现
public class ColorTrackView extends View {private int mTextStartX;private String mText = "编码编码";private Paint mPaint;private int mTextSize = 0;private int mTextOriginColor = 0xff000000;private int mTextChangeColor = 0xffff0000;private Rect mTextBound = new Rect();private int mTextWidth;private int mRealWidth;private float mProgress;public ColorTrackView(Context context) {super(context);init(context, null);}public ColorTrackView(Context context, AttributeSet attrs) {super(context, attrs);init(context, attrs);}public ColorTrackView(Context context, AttributeSet attrs, int defStyleAttr) {super(context, attrs, defStyleAttr);init(context, attrs);}private void init(Context context, AttributeSet attrs) {mTextSize = sp2px(getContext(), 30);mPaint = new Paint(Paint.ANTI_ALIAS_FLAG);TypedArray ta = context.obtainStyledAttributes(attrs,R.styleable.ColorTrackView);mText = ta.getString(R.styleable.ColorTrackView_text);mTextSize = ta.getDimensionPixelSize(R.styleable.ColorTrackView_text_size, mTextSize);mTextOriginColor = ta.getColor(R.styleable.ColorTrackView_text_origin_color, mTextOriginColor);mTextChangeColor = ta.getColor(R.styleable.ColorTrackView_text_change_color, mTextChangeColor);mProgress = ta.getFloat(R.styleable.ColorTrackView_progress, 0);ta.recycle();mPaint.setTextSize(mTextSize);measureText();}private void measureText() {mTextWidth = (int) mPaint.measureText(mText);mPaint.getTextBounds(mText, 0, mText.length(), mTextBound);}@Overrideprotected void onMeasure(int widthMeasureSpec, int heightMeasureSpec) {int width = measureWidth(widthMeasureSpec);int height = measureHeight(heightMeasureSpec);setMeasuredDimension(width, height);mRealWidth = getMeasuredWidth() - getPaddingLeft() - getPaddingRight();mTextStartX = mRealWidth / 2 - mTextWidth / 2;}private int measureHeight(int measureSpec) {int mode = MeasureSpec.getMode(measureSpec);int val = MeasureSpec.getSize(measureSpec);int result = 0;switch (mode) {case MeasureSpec.EXACTLY:result = val;break;case MeasureSpec.AT_MOST:case MeasureSpec.UNSPECIFIED:result = mTextBound.height();break;}result = mode == MeasureSpec.AT_MOST ? Math.min(result, val) : result;return result + getPaddingTop() + getPaddingBottom();}private int measureWidth(int measureSpec) {int mode = MeasureSpec.getMode(measureSpec);int val = MeasureSpec.getSize(measureSpec);int result = 0;switch (mode) {case MeasureSpec.EXACTLY:result = val;break;case MeasureSpec.AT_MOST:case MeasureSpec.UNSPECIFIED:// result = mTextBound.width();result = mTextWidth;break;}result = mode == MeasureSpec.AT_MOST ? Math.min(result, val) : result;return result + getPaddingLeft() + getPaddingRight();}@Overrideprotected void onDraw(Canvas canvas) {super.onDraw(canvas);drawText(canvas, mTextChangeColor, mTextStartX,(int) (mTextStartX + mProgress * mTextWidth));drawText(canvas, mTextOriginColor, (int) (mTextStartX + mProgress* mTextWidth), mTextStartX + mTextWidth);}private void drawText(Canvas canvas, int color, int startX, int endX) {mPaint.setColor(color);// canvas.save(Canvas.CLIP_SAVE_FLAG);canvas.clipRect(startX, 0, endX, getMeasuredHeight());canvas.drawText(mText, mTextStartX, getMeasuredHeight() / 2+ mTextBound.height() / 2, mPaint);// canvas.restore();}public static int sp2px(Context context, float spValue) {return (int) (spValue* context.getResources().getDisplayMetrics().scaledDensity + 0.5f);}public float getProgress() {return mProgress;}public void setProgress(float progress) {this.mProgress = progress;invalidate();}}
在执行了canvas的裁剪、平移、缩放、扭曲(skew)等操作,将影响其后执行的绘制draw的动作
所以一般在执行类似操作时 需要一对 save和restore
就明白了上面的含义了。public class ColorTrackActivity extends Activity {private MyHandler handler = new MyHandler();private ColorTrackView text;private int progress = 0;@Overrideprotected void onCreate(Bundle savedInstanceState) {super.onCreate(savedInstanceState);setContentView(R.layout.color_track_activity);text = (ColorTrackView) findViewById(R.id.text);}public void start(View v) {//ObjectAnimator.ofFloat(text, "progress", 0, 1).setDuration(2000) // .start(); handler.postDelayed(new Runnable() {@Overridepublic void run() {if (progress > 100) {return;}handler.sendEmptyMessage(0);}}, 20);}class MyHandler extends Handler {@Overridepublic void handleMessage(Message msg) {text.setProgress((progress++) / 100f);start(text);}}}可以看到这里hongyang使用的是属性动画,而我这里直接handler实现。
总结:快速的学习人家的博客的时候,需要注意几点。
(1)明白原理,去除代码中多余的部分,便于理解;
(2)看到不明白的知识点不要放过,比如这里,canvas的操作,使用注释的方法去掉就可以看到有啥影响了。
(3)自己想办法看看有啥其他的方法实现的,提高自己。
- Android Canvas 说明
- Android Canvas 说明
- Android中Canvas、Path 和 Paint 的方法说明
- Android 自定义View画圆和Canvas详细说明
- QML类型说明-Canvas
- QML类型说明-Canvas
- Android Canvas
- Android Canvas
- android canvas
- Android Canvas
- Android:Canvas
- Android Canvas
- android canvas
- Android Canvas
- android-Canvas
- Android Canvas
- android-Canvas
- Android Canvas
- android录制声音写入文件
- 祝兄弟们旗开得胜—兄弟连IT教育
- JBPM4 常用表结构详解,转自:http://blog.csdn.net/liulgcq/article/details/7205950
- emacs 基本操作
- 连续ping IP地址 shell脚本【来自《鸟哥linux的私房菜》】
- Android Canvas 说明
- JVM运行时是什么样子?
- [Leetcode]Search a 2D Matrix II
- Linux下进程间通信方式
- border-radius 圆角矩形
- retrofit2.0转换String 报错修复
- java.net.BindException: Cannot assign requested address解决之道
- Servlet:JSP理解
- linux非专业常用命令