MapUnit单元格源代码

package cjz.project.maptry4;

import android.content.Context;
import android.graphics.Bitmap;
import android.graphics.Canvas;
import android.graphics.Color;
import android.graphics.Matrix;
import android.graphics.Paint;
import android.graphics.Rect;
import android.graphics.RectF;
import android.util.AttributeSet;
import android.util.Log;
import android.view.ViewGroup;
import android.widget.FrameLayout;
import android.widget.ImageView;

import java.io.File;
import java.io.FileInputStream;
import java.io.FileNotFoundException;
import java.io.FileOutputStream;
import java.io.IOException;
import java.nio.ByteBuffer;
import java.util.Random;

/**
* Created by cjz on 2019/4/30.
*/

public class MapUnit extends ImageView {

private int beforeTag[] = new int[]{Integer.MIN_VALUE, Integer.MIN_VALUE};

/**状态位:判断是否需要刷新**/
public boolean isNeedRefresh = false;

private Bitmap tempBitmap = null;
private Bitmap bm = null;

/**默认保存缓存图的路径**/
private String cachePath = "";

public Bitmap cacheBitmap;
private Bitmap newBitmap;

/**开启debug界面**/
private boolean isDebug = true;
private byte[] readPixels;
private int mWidth, mHeight;

/**
* 是否初始化完成
**/
private boolean isInitFinished = false;

public MapUnit(Context context) {
super(context);
init();
}

public MapUnit(Context context, AttributeSet attrs) {
super(context, attrs);
init();
}

public MapUnit(Context context, AttributeSet attrs, int defStyleAttr) {
super(context, attrs, defStyleAttr);
init();
}

private void init(){
cachePath = getContext().getFilesDir().getAbsolutePath() /*+ File.separator + pos[0] + File.separator + pos[1]*/;
//Log.i("缓存路径", cachePath);
}

@Override
protected void onMeasure(int widthMeasureSpec, int heightMeasureSpec) {
super.onMeasure(widthMeasureSpec, heightMeasureSpec);
int width = MeasureSpec.getSize(widthMeasureSpec);
int height = MeasureSpec.getSize(heightMeasureSpec);
// if(width > 0 && height > 0){
mWidth = width;
mHeight = height;
// }
// if(getWidth() > 0 && getHeight() > 0){
// isInitFinished = true;
// Log.i("初始化完成","asdasdasd");
// }
}

@Override
public void setLayoutParams(ViewGroup.LayoutParams params) {
if(mWidth == 0 && mHeight == 0){
mWidth = params.width;
mHeight = params.height;
}
//Log.i("长度宽度setLayoutParams", String.format("mWidth : %d, mHeight : %d", mWidth, mHeight));
super.setLayoutParams(params);
}

@Override
protected void onLayout(boolean changed, int left, int top, int right, int bottom) {
super.onLayout(changed, left, top, right, bottom);
}

/**读取该单元格对应的Bitmap**/
private Bitmap readUnitBitmap(){
File file = new File(cachePath);
if(file.exists()){
try {
FileInputStream fileInputStream = new FileInputStream(file);
// if(!isInitFinished){
// if (mWidth == 0 || mHeight == 0) {
// Log.i("长度宽度异常", "");
// return null;
// } else {
// isInitFinished = true;
// }
// } else {
if (mWidth <= 0 || mHeight <= 0) {
Log.i("长度宽度异常", "");
return null;
}
// }
Bitmap unitPixelBitmap = Bitmap.createBitmap(mWidth, mHeight, Bitmap.Config.ARGB_8888);
if(readPixels == null){
readPixels = new byte[fileInputStream.available()];
} else if(readPixels.length < fileInputStream.available()){
readPixels = new byte[fileInputStream.available()];
}
fileInputStream.read(readPixels);
unitPixelBitmap.copyPixelsFromBuffer(ByteBuffer.wrap(readPixels));
fileInputStream.close();
//Log.i("正常返回图片", "");
return unitPixelBitmap;
} catch (FileNotFoundException e) {
Log.i("读图出错了", "读图出错了0");
e.printStackTrace();
} catch (IOException e) {
Log.i("读图出错了", "读图出错了1");
e.printStackTrace();
}
}
return null;
}

// /**读取该单元格对应的Bitmap**/
// private Bitmap readUnitBitmap2(){
// File file = new File(cachePath);
// if(file.exists()){
// try {
// FileInputStream fileInputStream = new FileInputStream(file);
// if (getWidth() == 0 || getHeight() == 0) {
// Log.i("长度宽度异常", "");
// return null;
// }
// Bitmap bitmap = Bitmap.createBitmap(getWidth(), getHeight(), Bitmap.Config.ARGB_8888);
// if(readPixels == null){
// readPixels = new byte[fileInputStream.available()];
// } else if(readPixels.length < fileInputStream.available()){
// readPixels = new byte[fileInputStream.available()];
// }
// fileInputStream.read(readPixels);
// bitmap.copyPixelsFromBuffer(ByteBuffer.wrap(readPixels));
// fileInputStream.close();
// //Log.i("正常返回图片", "");
// return bitmap;
// } catch (FileNotFoundException e) {
// e.printStackTrace();
// } catch (IOException e) {
// e.printStackTrace();
// }
// }
// return null;
// }

/**换坐标之前保存该单元格对应的Bitmap**/
private void saveUnitBitmap(){
File file = new File(cachePath);
try {
if (!file.exists()) {
file.createNewFile();
}
FileOutputStream fileOutputStream = new FileOutputStream(file);
Bitmap cacheBitmap = this.cacheBitmap;
if(cacheBitmap == null){
buildDrawingCache();
cacheBitmap = getDrawingCache();
}
byte pixels[] = new byte[cacheBitmap.getWidth() * cacheBitmap.getHeight() * 4];
cacheBitmap.copyPixelsToBuffer(ByteBuffer.wrap(pixels));
fileOutputStream.write(pixels);
fileOutputStream.close();
} catch (FileNotFoundException e) {
e.printStackTrace();
} catch (IOException e) {
e.printStackTrace();
}
}


public void setCachePath(String cachePath){
this.cachePath = cachePath;
}

@Override
public void setTag(Object tag) {
super.setTag(tag);
//设置标签的同时创建缓存文件夹和缓存文件
int pos[] = (int[]) tag;
File file = new File(getContext().getFilesDir().getAbsolutePath() + File.separator + pos[0]);
if(!file.exists()){
file.mkdir();
}
file = new File(getContext().getFilesDir().getAbsolutePath() + File.separator + pos[0] + File.separator + pos[1]);
if(!file.exists()){
file.mkdir();
}
cachePath = getContext().getFilesDir().getAbsolutePath() + File.separator + pos[0] + File.separator + pos[1] + File.separator + "unit.dat";
// Log.i("缓存路径", cachePath);
//用Tag对应图片刷新Unit
if(pos[0] != beforeTag[0] || pos[1] != beforeTag[1]){
Bitmap bitmap = readUnitBitmap();
if(bitmap != null){
//Log.i("刷新图片", "refreshBitmap:" + cachePath);
setImageBitmap(bitmap);
} else {
Log.i("刷新图片", "refreshNull:" + cachePath);
setImageBitmap(null);
}
}
beforeTag[0] = pos[0];
beforeTag[1] = pos[1];
}

@Override
public void setImageBitmap(Bitmap bm) {
super.setImageBitmap(bm);
if(this.bm != null){
this.bm.recycle();
this.bm = null;
}
this.bm = bm;
}

/**绘制图片**/
public void drawBitmap(Bitmap bitmap){
//先读取本Unit对应的Tag对应的文件夹是否有图片,有的话需要现在的图叠加起来
// if(cacheBitmap != null && !cacheBitmap.isRecycled()){
// cacheBitmap.recycle();
// cacheBitmap = null;
// }
// if(newBitmap != null && !newBitmap.isRecycled()){
// newBitmap.recycle();
// newBitmap = null;
// }
// System.gc();
cacheBitmap = readUnitBitmap();
if(cacheBitmap == null){
cacheBitmap = Bitmap.createBitmap(getWidth(), getHeight(), Bitmap.Config.ARGB_8888);
}
Canvas canvas = new Canvas(cacheBitmap);
if(bitmap != null && !bitmap.isRecycled()){
FrameLayout parent = (FrameLayout) getParent();
//获取本控件在屏幕可见区域对应的位图像素,并制作成Bitmap显示
Rect targetRect = new Rect(0, 0, 0, 0);
//计算本Unit需要截取父控件固定画布Bitmap的范围Start:
if (getX() + (1 - getScaleX()) / 2 * getWidth() < parent.getLeft()) { //左边缘小于0
targetRect.left = parent.getLeft();
} else {
targetRect.left = (int)(getX() + (1 - getScaleX()) / 2 * getWidth());
}

if (getX() + (1 - getScaleX()) / 2 * getWidth() + getWidth() * getScaleX() > parent.getRight()) { //单元的右边缘大于父控件右边缘
targetRect.right = parent.getRight();
} else {
targetRect.right = (int)(getX() + (1 - getScaleX()) / 2 * getWidth() + getWidth() * getScaleX());
}

if (getY() + (1 - getScaleY()) / 2 * getHeight() < parent.getTop()) {
targetRect.top = parent.getTop();
} else {
targetRect.top = (int)(getY() + (1 - getScaleY()) / 2 * getHeight());
}

if (getY() + (1 - getScaleY()) / 2 * getHeight() + getHeight() * getScaleY() > parent.getBottom()) {
targetRect.bottom = parent.getBottom();
} else {
targetRect.bottom = (int)(getY() + (1 - getScaleY()) / 2 * getHeight() + getHeight() * getScaleY());
}

if(targetRect.width() <= 0 || targetRect.height() <= 0){
return;
}
//计算本Unit需要截取父控件固定画布Bitmap的范围End;
//生成位图
int pixels[] = new int[targetRect.width() * targetRect.height()];
if(targetRect.right > bitmap.getWidth()){
targetRect.right = bitmap.getWidth();
}
if(targetRect.bottom > bitmap.getHeight()){
targetRect.bottom = bitmap.getHeight();
}
bitmap.getPixels(pixels, 0, targetRect.width(), targetRect.left, targetRect.top, targetRect.width(), targetRect.height());
newBitmap = Bitmap.createBitmap(pixels, targetRect.width(), targetRect.height(), Bitmap.Config.ARGB_8888);
Log.i("显示范围", targetRect.toString());
//由于Unit无论缩放之后视觉大小多大,初始大小依然是满屏的,所以切出来的屏幕画布一部分的像素块,无法铺满Unit,需要对像素块拉伸:
setScaleType(ScaleType.MATRIX);
Matrix matrix = new Matrix();
//如果Unit的做边框在父控件左侧外面,则需要把像素块移动到Unit可见区域的骑士位置再拉伸。所以这里计算左边框要偏移多少
float dx = 0;
float dy = 0;
if(getX() + (1 - getScaleX()) / 2 * getWidth() < 0){
dx = -(getX() + (1 - getScaleX()) / 2 * getWidth()) / getScaleX(); //左偏了多少,图片就要右偏多少,而且即使格子缩小了也只是视觉上缩少了,格子的像素量不变,所以截出来的图的坐标还要反向放大进行偏移
}
if(getY() + (1 - getScaleY()) / 2 * getHeight() < 0){
dy = -(getY() + (1 - getScaleY()) / 2 * getHeight()) / getScaleY();
}
matrix.postTranslate(dx, dy);
//之前的步骤计算了图片覆盖的左起点和顶起点,现在计算图片覆盖的右终点和底终点
float parentWidth = ((FrameLayout) getParent()).getRight(); //父控件右边终点
float parentHeight = ((FrameLayout) getParent()).getBottom();

float unitRightBoarder = (getX() + (1 - getScaleX()) / 2 * getWidth() + getWidth() * getScaleX()); //本Unit在屏幕实际的右边界位置
/**如果Unit右边界位置超出父控件右边界,则“Unit可见区域右边界 = 父控件右边界 - Unit实际可见左边界”并反向放大至和图片等效比例尺。
/否则直接用Unit真实右边界**/
float rightBoarder = unitRightBoarder > parentWidth ?
(parentWidth - (getX() + (1 - getScaleX()) / 2 * getWidth())) / getScaleX() :
getWidth() ;//右边框
//原理同上
float unitBottomBoarder = (getY() + (1 - getScaleY()) / 2 * getHeight() + getHeight() * getScaleY());
float bottomBoarder = unitBottomBoarder > parentHeight ?
(parentHeight - (getY() + (1 - getScaleY()) / 2 * getHeight())) / getScaleY(): //(屏幕边界 - View实际起始边界) / 缩放率 反向放大
getHeight() ;
//图片在Unit中实际应显示范围
RectF visibleRect = new RectF(dx, dy, rightBoarder, bottomBoarder);
//以实际应显示范围的左上角作为缩放中心,长、宽分别除以像素块的长、宽,得到像素块应该拉伸或者收缩的比例:
matrix.postScale(visibleRect.width() / newBitmap.getWidth(), visibleRect.height() / newBitmap.getHeight(), dx, dy);
canvas.drawBitmap(newBitmap, matrix, null);
setImageBitmap(cacheBitmap);
// setImageMatrix(matrix);
//保存本次绘图
saveUnitBitmap();
} else {
setImageBitmap(cacheBitmap);
}
}

//todo x作为一级文件夹,y作为二级文件夹,然后分别放对应(x,y)的bitmap文件
@Override
protected void onDraw(Canvas canvas) {
//传入的是空白的canvas,因此绘制过的内容并不能不断叠加
super.onDraw(canvas);
if(isDebug){
drawTest(canvas);
}
}

private void drawTest(Canvas canvas){
Random random = new Random();
//Log.i("onDraw", hashCode() + "");
Paint paint = new Paint();
paint.setStrokeWidth(8f);
// paint.setColor((0xFF000000 | (random.nextInt(255) & 0xFF) << 16 | (random.nextInt(255) & 0xFF) << 8 | (random.nextInt(255) & 0xFF)));
paint.setColor(Color.GRAY);
paint.setStyle(Paint.Style.STROKE);
//绘制背景
canvas.drawRect(0, 0, getWidth(), getHeight(), paint);
Paint paintPen = new Paint();
paintPen.setStrokeWidth(4f);
paintPen.setStyle(Paint.Style.FILL);
paintPen.setColor(Color.RED);
paintPen.setTextSize(32f);
paintPen.setAntiAlias(true);
//绘制自己是第几列第几行的单元
if(getTag() != null) {
int position[] = (int[]) getTag();
canvas.drawText(String.format("UnitX: %d, \nUnitY: %d", position[0], position[1]), getWidth() / 2 - 100, getHeight() / 2, paintPen);
}

//绘制边界点
paint.setColor(Color.BLUE);
canvas.drawPoint(0, 0, paint);
canvas.drawPoint(0, getHeight(), paint);
canvas.drawPoint(getWidth(), 0, paint);
canvas.drawPoint(getWidth(), getHeight(http://www.amjmh.com/v/BIBRGZ_558768/), paint);

// paint.setColor(Color.WHITE);
// Path path = new Path();
// path.moveTo(0, 0);
// path.lineTo(getWidth(), getHeight());
// canvas.drawPath(path, paint);
}
}

posted @ 2019-08-18 17:33  水至清明  阅读(185)  评论(0编辑  收藏  举报