本文来自 Android开发必知的50个诀窍 hack7
1.1 Canvas 介绍
可以把Canvas视为Surface的替身或者接口,图形便是绘制在Surface上的。
Canvas封装了所有绘图调用。
通过Canvas,绘制到Surface上的内容首先存储到与之关联的Bitmap中,Bitmap最终会呈现到窗口上。”Android框架规定,要绘制一些内容.需要四个基本要素:
A Bitmap to hold the pixels
A Canvas to host the draw calls (writing into the bitmap)
A drawing primitive (e.g. Rect, Path, text, Bitmap)
A paint (to describe the colors and styles for the drawing).
1.2 预期结果
如下,自定义View占据整个屏幕,在他的 Canvas 上动态的绘制矩形
1.3 首先我们创建一个 Activity 并把其 ContentView 设置为下面自定义的 MoveRectView
public class Hack5Activity extends Activity {
private MoveRectView mMoveView;
@Override
public void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
mMoveView = new MoveRectView(this);
setContentView(mMoveView);
}
}
1.4 完成 MoveRectView
创建 MoveRectView extends View
然后重写 onDraw() 方法
@Override
protected void onDraw(Canvas canvas) {
mDrawRect.set(rectLeft, rectTop, rectLeft + rectWidth, rectTop + rectHeight);
canvas.drawRoundRect(mDrawRect, 0, 0, mInnerPaint);
changePos();//改变位置
}
我们利用 canvas 来绘制矩形,然后通过改变矩形的位置来实现动画效果
//改变位置
protected void changePos() {
//x坐标
if (rectLeft > width - rectWidth) {
goRight = false;
}
if (rectLeft < 0) {
goRight = true;
}
if (goRight) {
rectLeft += xSpeed;
} else {
rectLeft -= xSpeed;
}
//y坐标
if (rectTop > height - rectHeight) {
goBottom = false;
}
if (rectTop < 0) {
goBottom = true;
}
if (goBottom) {
rectTop += ySpeed;
} else {
rectTop -= ySpeed;
}
//重新绘制,触发 onDraw()
postInvalidate();
}
位置的改变以屏幕的宽高做限.只需要改变 left 和 top 这两个值就可以. 最后的 postInvalidate(); 会再次出发 onDraw() 来绘制,从而形成循环.
1.5 MoveRectView 源码
public class MoveRectView extends View {
private static final int ALPHA = 255;
private int rectLeft = 0;
private int rectTop = 0;
private static final int rectWidth = 40;
private static final int rectHeight = 40;
private Paint mInnerPaint;
private RectF mDrawRect;
public int width;
public int height;
private boolean goRight = true;
private boolean goBottom = true;
private int xSpeed = 5;
private int ySpeed = 5;
public MoveRectView(Context context) {
super(context);
mInnerPaint = new Paint();
mDrawRect = new RectF();
mInnerPaint.setARGB(ALPHA, 255, 0, 0);
mInnerPaint.setAntiAlias(true);
System.out.println("绘图初始化");
}
@Override
protected void onMeasure(int widthMeasureSpec, int heightMeasureSpec) {
super.onMeasure(widthMeasureSpec, heightMeasureSpec);
width = getMeasuredWidth();
height = getMeasuredHeight();
}
@Override
protected void onDraw(Canvas canvas) {
mDrawRect.set(rectLeft, rectTop, rectLeft + rectWidth, rectTop + rectHeight);
canvas.drawRoundRect(mDrawRect, 0, 0, mInnerPaint);
changePos();
}
//改变位置
protected void changePos() {
//x坐标
if (rectLeft > width - rectWidth) {
goRight = false;
}
if (rectLeft < 0) {
goRight = true;
}
if (goRight) {
rectLeft += xSpeed;
} else {
rectLeft -= xSpeed;
}
//y坐标
if (rectTop > height - rectHeight) {
goBottom = false;
}
if (rectTop < 0) {
goBottom = true;
}
if (goBottom) {
rectTop += ySpeed;
} else {
rectTop -= ySpeed;
}
//重新绘制,触发 onDraw()
postInvalidate();
}
}
备注
关于控件高度 height 的值.
height 的取值是在构造方法中: height = getMeasuredHeight();
1 这个方法返回的高度是去除掉屏幕状态栏的
2 内置软件盘的手机,当软键盘的显示状态发生变化时,会触发构造方法来更新高度.
因此最初设计认为高度范围的限制比较麻烦的情况就不存在了.
高度去除了状态栏,下面才是 MoveRectView 的地盘
内置软键盘,红色矩形到底其顶部就会返回