显示指定位图到指定位置,最重要的就是参考物,以那个点为原点,往那个方向为正方向。有了参考物,画图还不是手到擒来?
android “横屏模式” 和 “竖屏模式” 的坐标系可以看成一样的,见下图:
总之一句话:***不管横屏竖屏,坐标原点在屏幕的左上角,往右为X正方向,往下为Y正方向!***有了坐标系,就相当于于有了参考物。至于你想把Bitmap怎么显示,是旋转,对称,位移…那就随便了。
首先:获取显示的位图。说一个坑:如果你把图片放在了res/drawable-xxhdpi之类的目录下,由于可以直接由 BitmapFactory的 : public static Bitmap decodeResource(Resources res, int id)
直接获取此类目录下位图,但这样获得的位图是经过本机像素密度参与转换计算而来的,所以由这个方法获得的位图与我们原始位图的像素宽度和高度不一样。见此方法源码便知:public static Bitmap decodeResource(Resources res, int id) { return decodeResource(res, id, null); }
跟进看一下主要的计算:
final TypedValue value = new TypedValue();
is = res.openRawResource(id, value);
bm = decodeResourceStream(res, value, is, null, opts);
就这样引入了与设备像素密度有关的TypeValue参与计算,
正确打开方式是直接打开位图的字节流或者去除与设备相关的参数,再用BitmapFactory的 public static Bitmap decodeStream(@Nullable InputStream is, @Nullable Rect outPadding, @Nullable Options opts)
解析位图,就可以直接获取原始位图。进而获取位图宽高,计算尺寸。
其次:获取显示位图的画布canvas。我分为两大情况:1.在主线程直接绘制的canvas 2.在子线程绘制的。第一种情况在自定义View绘制View常见,第二种在屏幕显示动态时常用。第二种情况在SurfaceView中通过其Holder可获得画布。得到画布后,又知道坐标系,显示位图不是轻而易举了吗?
然后:对想显示的位图进行调整(Matrix)。是截取一部分,还是全图全屏显示,旋转(rotate)或是对称,这就需要我们的Matrix矩阵变换类了,原理就不讲了,提供的很多变换方法,用法很简单,但是特别注意方法名的前缀prexxx,setxxx,postxxx:比如说缩放scale的方法:1.public void setScale(float sx, float sy)
2.public boolean preScale(float sx, float sy)
3.public boolean postScale(float sx, float sy)
。其中setxxx最为致命,直接清除以前对Matrix的操作(直接初始化),并对Matrix直接set此次操作,prexxx:可以理解在下次操作Matrix之前,叠加设置的效果并保存,达到连续操作Matrix的效果,postxxx:自己理解…设置完Matrix之后,调用public static Bitmap createBitmap(@NonNull Bitmap source, int x, int y, int width, int height, @Nullable Matrix m, boolean filter)
就可以获取变换后的位图了,注意位图的坐标系与屏幕一样,左上角为坐标原点
最后: 直接使用canvas的drawBitmap直接绘制就行了。特别注意理解canvas的各种draw方法:每调用drawBitmap时相当于***新建一个透明图层***,在图层上绘制位图后,把这个图层来覆盖在画布上,由此可以叠加绘制!
我提供一个方法:满足绝大部分使用情况
// 定义Android翻转参数的常量
public static final int TRANS_MIRROR=2;
public static final int TRANS_MIRROR_ROT180 = 1;
public static final int TRANS_MIRROR_ROT270 = 4;
public static final int TRANS_MIRROR_ROT90 = 7;
public static final int TRANS_NONE = 0;
public static final int TRANS_ROT180 = 3;
public static final int TRANS_ROT270 = 6;
public static final int TRANS_ROT90 = 5;
// 每次缩放的梯度
public static final float INTERVAL_SCALE=0.05f;
// 每次缩放的梯度是0.05,所以这里乘20以后转成整数
public static final int TIMES_SCALE=20;
private static final float[] pts=new float[8];
private static final Path path=new Path();
private static final RectF srcRect=new RectF();
// 用于从源位图中的srcX、srcY点开始、挖取宽width、高height的区域,并对该图片进行trans变换、
// 缩放scale(当scale为20时表示不缩放)、并旋转degree角度后绘制到Canvas的drawX、drawY处。
/**
*
* @param canvas 画布
* @param src 原始位图
* @param srcX 进行调整原始位图的X坐标
* @param srcY 进行调整原始位图的Y坐标
* @param width 进行调整原始位图的宽
* @param height 进行调整原始位图的高
* @param trans 进行的变化
* @param drawX 绘制在canvas的哪里X
* @param drawY 绘制在canvas的哪里Y
* @param degree 原始位图旋转的角度
* @param scale 原始位图缩放的比例
*/
public synchronized static void drawMatrixImage(Canvas canvas,Bitmap src,int srcX,int srcY,
int width,int height,int trans,int drawX,int drawY,int degree,int scale)
{
if (canvas == null)
{
return;
}
if (src == null || src.isRecycled())
{
return;
}
int srcWidth=src.getWidth();
int srcHeight=src.getHeight();
if (srcX+width>srcWidth){
width=srcWidth-srcX;
}
if (srcY+height>srcHeight){
height=srcHeight-srcY;
}
if (width<=0||height<+0)
{
return;
}
// 设置图片在横向、纵向上缩放因子
int scaleX=scale;
int scaleY=scale;
int rotate=0;
// 根据程序所要进行的图像变换来计算scaleX、scaleY以及rotate旋转角
switch (trans){
case TRANS_MIRROR_ROT180:
scaleX=-scaleX;
rotate=180;
break;
case TRANS_MIRROR:
scaleX=-scaleX;
break;
case TRANS_ROT180:
rotate=180;
break;
case TRANS_MIRROR_ROT270:
scaleX = -scale;
rotate = 270;
break;
case TRANS_ROT90:
rotate = 90;
break;
case TRANS_ROT270:
rotate = 270;
break;
case TRANS_MIRROR_ROT90:
scaleX = -scale;
rotate = 90;
break;
default:
break;
}
// 如果rotate、degree为0,表明不涉及旋转,
// 如果scaleX等于TIMES_SCALE,表明不涉及缩放
if (rotate==0&°ree==0&&scaleX==TIMES_SCALE){
drawImage(canvas,src,drawX,drawY,srcX,srcY,width,height);
}else {
Matrix matrix=new Matrix();
matrix.postScale(scaleX*INTERVAL_SCALE,scaleY*INTERVAL_SCALE);
matrix.postRotate(rotate);
matrix.postRotate(degree);
srcRect.set(srcX,srcY,srcX+width,srcY+height);
matrix.mapRect(srcRect);
matrix.postTranslate(drawX-srcRect.left,drawY-srcRect.top);
pts[0]=srcX;
pts[1]=srcY;
pts[2]=srcX+width;
pts[3] = srcY;
pts[4] = srcX + width;
pts[5] = srcY + height;
pts[6] = srcX;
pts[7] = srcY + height;
matrix.mapPoints(pts);
canvas.save();//保存当前图层进栈
path.reset();
path.moveTo(pts[0],pts[1]);
path.lineTo(pts[2], pts[3]);
path.lineTo(pts[4], pts[5]);
path.lineTo(pts[6], pts[7]);
path.close();
canvas.clipPath(path);
canvas.drawBitmap(src,matrix,null);
canvas.restore();//图层退栈
}
}
扬帆,启航!