public class GuaGuaLeView extends View {
private Bitmap mDownBitmap,mUpBitmap;
private Paint mPaint;
private Path mPath;
private Canvas mCanvas;
public GuaGuaLeView(Context context) {
this(context,null);
}
public GuaGuaLeView(Context context, AttributeSet attrs) {
super(context, attrs);
init();
}
/**
* 对图片处理的一些初始化工作,在这里完成
*/
private void init(){
//设置画笔的一些属性
mPaint = new Paint();
mPaint.setAlpha(0);
mPaint.setXfermode(new PorterDuffXfermode(PorterDuff.Mode.DST_IN));
mPaint.setStyle(Paint.Style.STROKE);
mPaint.setStrokeJoin(Paint.Join.ROUND);
mPaint.setStrokeWidth(50);
mPaint.setStrokeCap(Paint.Cap.ROUND);
mPath = new Path();
//获取图片资源
mDownBitmap = BitmapFactory.decodeResource(getResources(), R.mipmap.image01);
//按照原图大小绘制一个遮罩层
mUpBitmap = Bitmap.createBitmap(mDownBitmap.getWidth(),mDownBitmap.getHeight(),
Bitmap.Config.ARGB_8888);
mCanvas = new Canvas(mUpBitmap);
mCanvas.drawColor(Color.GRAY);
}
/**
* 获取用户的触摸监听事件
* @param event
* @return
*/
@Override
public boolean onTouchEvent(MotionEvent event) {
switch (event.getAction()){
case MotionEvent.ACTION_DOWN:
mPath.reset();
mPath.moveTo(event.getX(),event.getY());
break;
case MotionEvent.ACTION_MOVE:
mPath.lineTo(event.getX(),event.getY());
break;
}
//开始绘制路径
mCanvas.drawPath(mPath,mPaint);
invalidate();
return true;
}
@Override
protected void onDraw(Canvas canvas) {
super.onDraw(canvas);
canvas.drawBitmap(mDownBitmap,0,0,null); //先绘制出下面的图片
canvas.drawBitmap(mUpBitmap,0,0,null);
}
}
布局文件中引入自定义View控件
.edu.com.canvasdemo.view.GuaGuaLeView
android:id="@+id/guaGuaLeImageView"
android:layout_width="300dp"
android:layout_height="300dp"
android:layout_centerHorizontal="true"/>
将图片改变成圆角的图片。
* 先用普通画笔画一个遮罩层,再用带PorterDuffXfermode的画笔将图像画在遮罩层上
自定义View代码的实现
public class RoundRectView extends ImageView {
private Bitmap mBitmap,outBitmap;
private Canvas mCanvas;
private Paint mPaint;
public RoundRectView(Context context, AttributeSet attrs) {
super(context, attrs);
init();
}
private void init(){
Log.i("执行顺序,","init()");
mBitmap = BitmapFactory.decodeResource(getResources(), R.mipmap.image01);
outBitmap = Bitmap.createBitmap(mBitmap.getWidth(),
mBitmap.getHeight(), Bitmap.Config.ARGB_8888);
mCanvas = new Canvas(outBitmap);
mPaint = new Paint();
mPaint.setAntiAlias(true);
RectF mRound = new RectF(0,0,mBitmap.getWidth(),mBitmap.getHeight());
// mCanvas.drawRoundRect(mRound,80,80,mPaint); //画圆角矩形
mCanvas.drawCircle(mBitmap.getWidth()/2,mBitmap.getHeight()/2,150,mPaint); //画圆形
mPaint.setXfermode(new PorterDuffXfermode(PorterDuff.Mode.SRC_IN));
mCanvas.drawBitmap(mBitmap,0,0,mPaint);
}
@Override
protected void onDraw(Canvas canvas) {
super.onDraw(canvas);
Log.i("执行顺序,","onDraw()");
canvas.drawBitmap(outBitmap,0,0,null);
}
}
在布局文件中引入自定义View
.edu.com.canvasdemo.view.RoundRectView
android:layout_below="@+id/guaGuaLeImageView"
android:layout_width="300dp"
android:layout_height="300dp" />
**SurfaceView与View类似,他们的不同之处在于
1、View主要使用于主动更新的情况下,而SurfaceView主要适用于被动更新,例如频繁的刷新。
2、View在主线程中对画面进行刷新,而SurfaceView通常会通过一个子线程来进行页面的刷新。
3、View在绘图时没有使用双缓冲机制,而SurfaceView在底层实现机制中就已经实现了双缓冲机制。
总之,当自定义View需要频繁的刷新,或者刷新时数据处理量很大时,就考虑用SurfaceView来替代View。**
使用步骤:
—| 创建一个类继承自SurfaceView并实现SurfaceHolder.Callback和Runnable接口。
—| 分别实现以下三个方法:
@Override
public void surfaceCreated(SurfaceHolder holder) {
Log.i("执行。。。","surfaceCreated()");
mIsDrawing = true;
new Thread(this).start();
}
@Override
public void surfaceChanged(SurfaceHolder holder, int format, int width, int height) {
Log.i("执行。。。","surfaceChanged()");
}
/**
* view销毁时结束多线程的执行
* @param holder
*/
@Override
public void surfaceDestroyed(SurfaceHolder holder) {
mIsDrawing = false;
Log.i("执行。。。","surfaceDestroyed()");
}
—| 在surfaceCreated方法中获取SurfaceHolder对象,开启子线程执行任务。
—| 在run()方法中使用lockCanvas()方法获得Canvas对象。可以进行绘图操作。并通过unlockCanvasAndPost()方法进行提交画布内容。
以下是代码的实现
public class DrawLineSurfaceView extends SurfaceView implements SurfaceHolder.Callback,Runnable {
//通过SurfaceHolder处理
private SurfaceHolder mHolder;
//用于绘图的Canvas
private Canvas mCanvas;
//子线程的标志位
private boolean mIsDrawing;
//绘制路径
private Path mPath;
//定义画笔
private Paint mPaint;
private int x = 0;
private int y =0;
public DrawLineSurfaceView(Context context) {
this(context,null);
}
public DrawLineSurfaceView(Context context, AttributeSet attrs) {
super(context, attrs);
initView();
}
public DrawLineSurfaceView(Context context, AttributeSet attrs, int defStyleAttr) {
this(context, attrs);
}
/**
* 初始化View
*/
private void initView(){
Log.i("执行。。。","initView()");
//初始化SurfaceHolder对象,并注册SurfaceHolder回调方法
mHolder = getHolder();
mHolder.addCallback(this);
//设置该View接收焦点
setFocusable(true);
setFocusableInTouchMode(true);
this.setKeepScreenOn(true);
mPath = new Path();
mPath.moveTo(x,y); //一定 要有一个开始点
mPaint = new Paint();
mPaint.setColor(Color.BLUE);
mPaint.setStyle(Paint.Style.STROKE);
mPaint.setStrokeWidth(12);
}
/**
* 在此方法中开启子线程进行绘制。
* @param holder
*/
@Override
public void surfaceCreated(SurfaceHolder holder) {
Log.i("执行。。。","surfaceCreated()");
mIsDrawing = true;
new Thread(this).start();
}
@Override
public void surfaceChanged(SurfaceHolder holder, int format, int width, int height) {
Log.i("执行。。。","surfaceChanged()");
}
/**
* view销毁时结束多线程的执行
* @param holder
*/
@Override
public void surfaceDestroyed(SurfaceHolder holder) {
mIsDrawing = false;
Log.i("执行。。。","surfaceDestroyed()");
}
@Override
public void run() {
while(mIsDrawing){
//执行绘制任务----这里绘制一个正弦的曲线
draw();
x +=1;
y = (int)(100*Math.sin(x*2*Math.PI/180)+400);
mPath.lineTo(x,y);
Log.i("----",getWidth()+"----");
if(x>getWidth())
mIsDrawing = false;
}
}
private void draw(){
try {
mCanvas = mHolder.lockCanvas();//获得Canvas对象![这里写图片描述](https://img-blog.csdn.net/20151128183623335)
mCanvas.drawColor(Color.WHITE);
mCanvas.drawPath(mPath,mPaint);
}catch (Exception e){
}finally {
if(mCanvas!=null)
mHolder.unlockCanvasAndPost(mCanvas); //将Canvas提交
}
}
}
在xml布局文件中引入自定义View
.edu.com.canvasdemo.view.DrawLineSurfaceView
android:layout_width="match_parent"
android:layout_height="wrap_content" />