先看下今天最终要实现的效果图:
这效果是不是很屌,要实现这个效果有2个重要的知识点必须要懂,现在就一一分析要使用到的知识点,然后才讨论这个效果怎么实现,
一:如何获取一个canvas对象
要想获取canvas对象有二种方法
第一种方法:自定义view或者viewGroup然后重写onDraw()或disPatchDraw()方法,这二个方法区别前者是没有子view时绘制使用onDraw(),当在view中药绘制子view时这时候要使用disPatchDraw(),这二个方法都有一个形参就是Canvas对象,而这个onDraw()或者disPathDraw()都是直接通过view调用的,所以直接通过canvas就绘制在view上了,
但是这种方法 除非绘制一些简单,单一的图形使用,复杂点的就不使用这个了,
二:第二种方法,通过创建Bitmap对象
我们知道canvas可以通过自定义view中onDraw()中参数给我们提供的,也可以自己创建一个Canvas,使用如下:
Canvas canvas = new Canvas(); Bitmap bitmap = BitmapFactory.decodeResource(getResources(),R.mipmap.headshow1); canvas.setBitmap(bitmap);
canvas设置的bitmap可以来自drawable目录下的资源文件,也可以自己创建一个空的Bitmap,Bitmap api给我们提供了很多种方法创建一个bitmap对象:
下面对createBitmap()几个重载的方法做一个简单的说明:
public static Bitmap createBitmap(Bitmap src) {} 从原位图src复制出一个新的位图,和原始位图相同
public static Bitmap createBitmap(Bitmap source, int x, int y, int width, int height) {}这个通常用在对原始图进行截取,
public static Bitmap createBitmap(Bitmap source, int x, int y, int width, int height,Matrix m, boolean filter) {}这和上面的用途差不多,只不过了多一个matrix矩阵,通过matirx可以对位图进行旋转等其他操作,
public static Bitmap createBitmap(int width, int height, Config config) {}这是创建一个空的设置了位图的宽和高并可以设置色彩模式,色彩模式一共有如下几种:这个Config类是Bitmap的内部类有四个值分别是:ALPHA_8 代表8位Alpha位图
ARGB_4444 代表16位ARGB位图
ARGB_8888 代表32位ARGB位图
RGB_565 代表8位RGB位图
位图位数越高代表其可以存储的颜色信息越多,当然图像也就越逼真,但是占内存也叫大
我们用bitmap构造了一个canvas,哪就相当于canvas这个图层上绘制的图形就保存在这个bitmap上,而不像我们直接使用onDraw()方法中自带的canvas绘制直接就绘制到view上了,但是我们自己创建的canvas如果想画在View上就必须使用OnDraw()函数中传进来的canvas画一遍bitmap才能画到view上,现在我们写个例子来说明下,光文字描述没有那么直观,
package com.example.customcircularavatar.view; import android.content.Context; import android.graphics.Bitmap; import android.graphics.Canvas; import android.graphics.Color; import android.graphics.Paint; import android.util.AttributeSet; import android.view.View; /** * Created by admin on 2016/5/11. */ public class CustomView extends View { private Paint mPaint; private Canvas mCanvas; public CustomView(Context context) { this(context,null); } public CustomView(Context context, AttributeSet attrs) { this(context, attrs,0); } public CustomView(Context context, AttributeSet attrs, int defStyleAttr) { super(context, attrs, defStyleAttr); init(context); } private void init(Context context) { mPaint = new Paint(); mPaint.setColor(Color.parseColor("#88000000")); mCanvas = new Canvas(); Bitmap bitmap = Bitmap.createBitmap(200,200, Bitmap.Config.ALPHA_8);//创建一个宽和高200的空的位图, mCanvas.setBitmap(bitmap);//把这个位图放在canvas这个图层上 } @Override protected void onDraw(Canvas canvas) { super.onDraw(canvas); mPaint.setTextSize(60); mCanvas.drawText("杭州准备开G20峰会",2000,200,mPaint); } }效果:
发现屏幕上什么都不显示,没有绘制出来任何东西,因为绘制就是在onDraw()方法中操作,现在再看下onDraw()方法都写了什么代码:
@Override protected void onDraw(Canvas canvas) { super.onDraw(canvas); mPaint.setTextSize(60); mCanvas.drawText("杭州准备开G20峰会",2000,200,mPaint); }你会发现调用drawText()方法的不是onDraw()自带的canvas对象,因为你要直接绘制到view上只有canvas跟它view有直接的关系,而使用我们自己创建的Canvas对象跟view毫无关系,所以这就是为什么在view上什么都看不见的原因,如果要在view上看见我们自己创建的canvas图层上所绘制的东西,是不是要把我们创建canvas对象通过onDraw()方法中提供的canvas对象给绘制上去呢?答案是错误的,你去查找发现canvas并没有一个方法把canvas对象当做形参给传递进去,而是通过canvas的drawBitmap()方法把创建的bitmap对象绘制上去,
package com.example.customcircularavatar.view; import android.content.Context; import android.graphics.Bitmap; import android.graphics.Canvas; import android.graphics.Color; import android.graphics.Paint; import android.util.AttributeSet; import android.view.View; /** * Created by admin on 2016/5/11. */ public class CustomView extends View { private Paint mPaint; private Canvas mCanvas; private Bitmap mBitmap; public CustomView(Context context) { this(context,null); } public CustomView(Context context, AttributeSet attrs) { this(context, attrs,0); } public CustomView(Context context, AttributeSet attrs, int defStyleAttr) { super(context, attrs, defStyleAttr); init(context); } private void init(Context context) { mPaint = new Paint(); mPaint.setColor(Color.parseColor("#88000000")); mCanvas = new Canvas(); mBitmap = Bitmap.createBitmap(900,900, Bitmap.Config.ALPHA_8);//创建一个宽和高600的空的位图, mCanvas.setBitmap(mBitmap);//把这个位图放在canvas这个图层上 } @Override protected void onDraw(Canvas canvas) { super.onDraw(canvas); mPaint.setTextSize(60); mPaint.setColor(Color.RED); mCanvas.drawText("杭州准备开G20峰会",60,100,mPaint);//在创建的canvas图层上绘制文字 canvas.drawBitmap(mBitmap,100,100,new Paint()); } }效果:
现在在屏幕上看到了我们绘制的文字信息了,为什么上面没有显示图片呢?那是因为我们创建的Bitmap是空的一个位图,现在我们在drawable资源中图片当做位图看看效果:
package com.example.customcircularavatar.view; import android.content.Context; import android.graphics.Bitmap; import android.graphics.BitmapFactory; import android.graphics.Canvas; import android.graphics.Color; import android.graphics.Paint; import android.util.AttributeSet; import android.util.Log; import android.view.View; import com.example.customcircularavatar.R; /** * Created by admin on 2016/5/11. */ public class CustomView extends View { private static final String TAG ="CustomView" ; private Paint mPaint; private Canvas mCanvas; private Bitmap mBitmap; public CustomView(Context context) { this(context,null); } public CustomView(Context context, AttributeSet attrs) { this(context, attrs,0); } public CustomView(Context context, AttributeSet attrs, int defStyleAttr) { super(context, attrs, defStyleAttr); init(context); } private void init(Context context) { mPaint = new Paint(); mPaint.setColor(Color.parseColor("#88000000")); mCanvas = new Canvas(); Bitmap srcBitmap = BitmapFactory.decodeResource(getResources(), R.mipmap.ic_launcher); mBitmap = Bitmap.createBitmap(srcBitmap); mCanvas.setBitmap(mBitmap);//把这个位图放在canvas这个图层上 } @Override protected void onDraw(Canvas canvas) { super.onDraw(canvas); mPaint.setTextSize(60); mPaint.setColor(Color.RED); mCanvas.drawText("杭州准备开G20峰会",60,100,mPaint);//在创建的canvas图层上绘制文字 canvas.drawBitmap(mBitmap,0,0,mPaint); } }发现一跑起来程序就挂了,日记如下:
刚开始以为是硬件加载引起的bug,后来发现不少硬件加速引起的,而是canvas.setBitmap(bitmap)这个bitmap对象要求是可变的,而我是通过BitmapFactry.decode...()这样获取的Bitmap对象是不可变的,源码解释:
/** * Specify a bitmap for the canvas to draw into. All canvas state such as * layers, filters, and the save/restore stack are reset with the exception * of the current matrix and clip stack. Additionally, as a side-effect * the canvas' target density is updated to match that of the bitmap. * * @param bitmap Specifies a mutable bitmap for the canvas to draw into. * @see #setDensity(int) * @see #getDensity() */ public void setBitmap(@Nullable Bitmap bitmap) { if (isHardwareAccelerated()) { throw new RuntimeException("Can't set a bitmap device on a HW accelerated canvas"); } if (bitmap == null) { native_setBitmap(mNativeCanvasWrapper, null); mDensity = Bitmap.DENSITY_NONE; } else { if (!bitmap.isMutable()) { throw new IllegalStateException(); } throwIfCannotDraw(bitmap); native_setBitmap(mNativeCanvasWrapper, bitmap); mDensity = bitmap.mDensity; } mBitmap = bitmap; }
bitmap Specifies a mutable bitmap for the canvas to draw into意思是说通过canvas draw上去的bitmap对象要是可变的,所以通过修改后代码如下:
package com.example.customcircularavatar.view; import android.content.Context; import android.graphics.Bitmap; import android.graphics.BitmapFactory; import android.graphics.Canvas; import android.graphics.Color; import android.graphics.Paint; import android.util.AttributeSet; import android.util.Log; import android.view.View; import com.example.customcircularavatar.R; /** * Created by admin on 2016/5/11. */ public class CustomView extends View { private static final String TAG ="CustomView" ; private Paint mPaint; private Canvas mCanvas; private Bitmap mBitmap; private Bitmap srcBitmap; public CustomView(Context context) { this(context,null); } public CustomView(Context context, AttributeSet attrs) { this(context, attrs,0); } public CustomView(Context context, AttributeSet attrs, int defStyleAttr) { super(context, attrs, defStyleAttr); init(context); } private void init(Context context) { mPaint = new Paint(); mCanvas = new Canvas(); mBitmap = Bitmap.createBitmap(900,900, Bitmap.Config.ALPHA_8); srcBitmap = BitmapFactory.decodeResource(getResources(), R.mipmap.ic_launcher); mCanvas.setBitmap(mBitmap); } @Override protected void onDraw(Canvas canvas) { super.onDraw(canvas); mPaint.setTextSize(60); mPaint.setColor(Color.RED); mCanvas.drawBitmap(srcBitmap,0,0,mPaint); mCanvas.drawText("杭州准备开G20峰会",60,100,mPaint); canvas.drawBitmap(mBitmap,0,0,mPaint); } }效果如下:
第二个知识点就是关于Xfermode
paint有个方法setXfermode(Xfermode xfermode),这个方法能起什么功能,就是实现两张图叠加时的混合效果,
这篇博客 周末把剩下的写完!