我需要参加的行为是保留我根据缩放级别绘制的内容。我能够使用针对同一问题的另一种解决方案Canvas - zooming in, shifting, and scaling on Android来实现此行为。然而,我遇到了一个可能听起来很荒谬的问题,但是我无法解决这个问题。 当我在主活动中调用imageView.setImageBitmap(位图b)时,从不显示位图。它总是显示一个白页来绘制。
请问,如何在这里的自定义视图中显示我的位图?
以下是代码:
ScaleImageView.java
public class ScaleImageView extends View {
private Bitmap imgBitmap = null;
private int containerWidth;
private int containerHeight;
float[] mv = new float[9];
Paint background;
Matrix matrix = new Matrix();
Matrix savedMatrix = new Matrix();
PointF start = new PointF();
float currentScale;
float curX;
float curY;
//We can be in one of these 3 states
static final int NONE = 0;
static final int DRAG = 1;
static final int ZOOM = 2;
int mode = NONE;
float targetX;
float targetY;
float targetScale;
float targetScaleX;
float targetScaleY;
float scaleChange;
float targetRatio;
boolean isAnimating = false;
float oldDist = 1f;
PointF mid = new PointF();
private Handler mHandler = new Handler();
float minScale;
float maxScale = 8.0f;
float screenDensity;
private GestureDetector gestureDetector;
public static final int DEFAULT_SCALE_FIT_INSIDE = 0;
private int defaultScale;
private Path drawPath;
public Paint drawPaint;
private Canvas drawCanvas;
Rect clipBounds;
public ArrayList<Path> paths = new ArrayList<>();
public ArrayList<Paint> colors = new ArrayList<>();
// Creates Path and Paint for drawing
public void setUpDrawing() {
drawPath = new Path();
drawPaint = new Paint();
drawPaint.setColor(Color.RED);
drawPaint.setAntiAlias(true);
drawPaint.setStrokeWidth(8);
drawPaint.setStyle(Paint.Style.STROKE);
drawPaint.setStrokeJoin(Paint.Join.ROUND);
drawPaint.setStrokeCap(Paint.Cap.ROUND);
}
public ScaleImageView(Context context) {
super(context);
setFocusable(true);
setFocusableInTouchMode(true);
screenDensity = context.getResources().getDisplayMetrics().density;
initPaints();
gestureDetector = new GestureDetector(context, new MyGestureDetector());
setUpDrawing();
}
public ScaleImageView(Context context, AttributeSet attrs) {
super(context, attrs);
screenDensity = context.getResources().getDisplayMetrics().density;
initPaints();
gestureDetector = new GestureDetector(context,new MyGestureDetector());
defaultScale = ScaleImageView.DEFAULT_SCALE_FIT_INSIDE;
setUpDrawing();
}
private void initPaints() {
background = new Paint();
setUpDrawing();
}
@Override
protected void onSizeChanged(int width, int height, int oldWidth, int oldHeight) {
super.onSizeChanged(width, height, oldWidth, oldHeight);
containerWidth = width;
containerHeight = height;
if (imgBitmap != null) {
drawCanvas = new Canvas(imgBitmap);
int imgHeight = imgBitmap.getHeight();
int imgWidth = imgBitmap.getWidth();
float scale;
int initX = 0;
int initY = 0;
if (defaultScale == ScaleImageView.DEFAULT_SCALE_FIT_INSIDE) {
if (imgWidth > containerWidth) {
scale = (float) containerWidth / imgWidth;
float newHeight = imgHeight * scale;
initY = (containerHeight - (int) newHeight) / 2;
matrix.setScale(scale, scale);
matrix.postTranslate(0, initY);
} else {
scale = (float) containerHeight / imgHeight;
float newWidth = imgWidth * scale;
initX = (containerWidth - (int) newWidth) / 2;
matrix.setScale(scale, scale);
matrix.postTranslate(initX, 0);
}
curX = initX;
curY = initY;
currentScale = scale;
minScale = scale;
} else {
if (imgWidth > containerWidth) {
initY = (containerHeight - (int) imgHeight) / 2;
matrix.postTranslate(0, initY);
} else {
initX = (containerWidth - (int) imgWidth) / 2;
matrix.postTranslate(initX, 0);
}
curX = initX;
curY = initY;
currentScale = 1.0f;
minScale = 1.0f;
}
invalidate();
}
}
@Override
protected void onDraw(Canvas canvas) {
super.onDraw(canvas);
canvas.save();
if (imgBitmap != null && canvas != null) {
if (drawCanvas == null)
drawCanvas = new Canvas(imgBitmap);
clipBounds = canvas.getClipBounds();
canvas.drawBitmap(imgBitmap, matrix, background);
canvas.concat(matrix);
for (int i = 0; i < colors.size(); i++) {
canvas.drawPath(paths.get(i), colors.get(i));
}
canvas.drawPath(drawPath, drawPaint);
}
canvas.restore();
invalidate();
}
public void reDrawUndo() {
System.out.println("paths.size" + paths.size());
if (paths.size() > 0) {
paths.remove(paths.size() - 1);
colors.remove(colors.size() - 1);
invalidate();
}
}
//Checks and sets the target image x and y co-ordinates if out of bounds
private void checkImageConstraints() {
if (imgBitmap == null) {
return;
}
float[] mvals = new float[9];
matrix.getValues(mvals);
currentScale = mvals[0];
if (currentScale < minScale) {
float deltaScale = minScale / currentScale;
float px = containerWidth / 2;
float py = containerHeight / 2;
matrix.postScale(deltaScale, deltaScale, px, py);
invalidate();
}
matrix.getValues(mvals);
currentScale = mvals[0];
curX = mvals[2];
curY = mvals[5];
int rangeLimitX = containerWidth - (int) (imgBitmap.getWidth() * currentScale);
int rangeLimitY = containerHeight - (int) (imgBitmap.getHeight() * currentScale);
boolean toMoveX = false;
boolean toMoveY = false;
if (rangeLimitX < 0) {
if (curX > 0) {
targetX = 0;
toMoveX = true;
} else if (curX < rangeLimitX) {
targetX = rangeLimitX;
toMoveX = true;
}
} else {
targetX = rangeLimitX / 2;
toMoveX = true;
}
if (rangeLimitY < 0) {
if (curY > 0) {
targetY = 0;
toMoveY = true;
} else if (curY < rangeLimitY) {
targetY = rangeLimitY;
toMoveY = true;
}
} else {
targetY = rangeLimitY / 2;
toMoveY = true;
}
if (toMoveX == true || toMoveY == true) {
if (toMoveY == false) {
targetY = curY;
}
if (toMoveX == false) {
targetX = curX;
}
//Disable touch event actions
isAnimating = true;
//Initialize timer
mHandler.removeCallbacks(mUpdateImagePositionTask);
mHandler.postDelayed(mUpdateImagePositionTask, 100);
}
}
@Override
public boolean onTouchEvent(MotionEvent event) {
matrix.getValues(mv);
float touchX = (event.getX() * (1 / mv[4]) - (mv[2] / mv[4]));
float touchY = (event.getY() * (1 / mv[4]) - (mv[5] / mv[4]));
// Is drawing mode on?
if (ScaleImageActivity.flag) {
switch (event.getAction()) {
case MotionEvent.ACTION_DOWN:
drawPath.moveTo(touchX, touchY);
break;
case MotionEvent.ACTION_MOVE:
drawPath.lineTo(touchX, touchY);
break;
case MotionEvent.ACTION_UP:
Paint newPaint = new Paint();
newPaint.set(drawPaint);
colors.add(newPaint);
paths.add(drawPath);
drawPath = new Path();
drawPath.reset();
break;
case MotionEvent.ACTION_POINTER_DOWN:
System.out.println("bleh");
break;
default:
return false;
}
} else {
if (gestureDetector.onTouchEvent(event)) {
return true;
}
if (isAnimating == true) {
return true;
}
//Handle touch events here
float[] mvals = new float[9];
switch (event.getAction() & MotionEvent.ACTION_MASK) {
case MotionEvent.ACTION_DOWN:
if (isAnimating == false) {
savedMatrix.set(matrix);
start.set(event.getX(), event.getY());
mode = DRAG;
}
break;
case MotionEvent.ACTION_POINTER_DOWN:
oldDist = spacing(event);
if (oldDist > 10f) {
savedMatrix.set(matrix);
midPoint(mid, event);
mode = ZOOM;
}
break;
case MotionEvent.ACTION_UP:
case MotionEvent.ACTION_POINTER_UP:
mode = NONE;
matrix.getValues(mvals);
curX = mvals[2];
curY = mvals[5];
currentScale = mvals[0];
if (isAnimating == false) {
checkImageConstraints();
}
break;
case MotionEvent.ACTION_MOVE:
if (mode == DRAG && isAnimating == false) {
matrix.set(savedMatrix);
float diffX = event.getX() - start.x;
float diffY = event.getY() - start.y;
matrix.postTranslate(diffX, diffY);
matrix.getValues(mvals);
curX = mvals[2];
curY = mvals[5];
currentScale = mvals[0];
} else if (mode == ZOOM && isAnimating == false) {
float newDist = spacing(event);
if (newDist > 10f) {
matrix.set(savedMatrix);
float scale = newDist / oldDist;
matrix.getValues(mvals);
currentScale = mvals[0];
if (currentScale * scale <= minScale) {
matrix.postScale(minScale / currentScale, minScale / currentScale, mid.x, mid.y);
} else if (currentScale * scale >= maxScale) {
matrix.postScale(maxScale / currentScale, maxScale / currentScale, mid.x, mid.y);
} else {
matrix.postScale(scale, scale, mid.x, mid.y);
}
matrix.getValues(mvals);
curX = mvals[2];
curY = mvals[5];
currentScale = mvals[0];
}
}
break;
}
}
//Calculate the transformations and then invalidate
invalidate();
return true;
}
private float spacing(MotionEvent event) {
float x = event.getX(0) - event.getX(1);
float y = event.getY(0) - event.getY(1);
return (float) Math.sqrt(x * x + y * y);
}
private void midPoint(PointF point, MotionEvent event) {
float x = event.getX(0) + event.getX(1);
float y = event.getY(0) + event.getY(1);
point.set(x / 2, y / 2);
}
public void setImageBitmap(Bitmap b) {
if (b != null) {
imgBitmap = b;
containerWidth = getWidth();
containerHeight = getHeight();
int imgHeight = imgBitmap.getHeight();
int imgWidth = imgBitmap.getWidth();
float scale;
int initX = 0;
int initY = 0;
matrix.reset();
if (defaultScale == ScaleImageView.DEFAULT_SCALE_FIT_INSIDE) {
if (imgWidth > containerWidth) {
scale = (float) containerWidth / imgWidth;
float newHeight = imgHeight * scale;
initY = (containerHeight - (int) newHeight) / 2;
matrix.setScale(scale, scale);
matrix.postTranslate(0, initY);
} else {
scale = (float) containerHeight / imgHeight;
float newWidth = imgWidth * scale;
initX = (containerWidth - (int) newWidth) / 2;
matrix.setScale(scale, scale);
matrix.postTranslate(initX, 0);
}
curX = initX;
curY = initY;
currentScale = scale;
minScale = scale;
} else {
if (imgWidth > containerWidth) {
initX = 0;
if (imgHeight > containerHeight) {
initY = 0;
} else {
initY = (containerHeight - (int) imgHeight) / 2;
}
matrix.postTranslate(0, initY);
} else {
initX = (containerWidth - (int) imgWidth) / 2;
if (imgHeight > containerHeight) {
initY = 0;
} else {
initY = (containerHeight - (int) imgHeight) / 2;
}
matrix.postTranslate(initX, 0);
}
curX = initX;
curY = initY;
currentScale = 1.0f;
minScale = 1.0f;
}
}
invalidate();
}
private Runnable mUpdateImagePositionTask = new Runnable() {
public void run() {
float[] mvals;
if (Math.abs(targetX - curX) < 5 && Math.abs(targetY - curY) < 5) {
isAnimating = false;
mHandler.removeCallbacks(mUpdateImagePositionTask);
mvals = new float[9];
matrix.getValues(mvals);
currentScale = mvals[0];
curX = mvals[2];
curY = mvals[5];
//Set the image parameters and invalidate display
float diffX = (targetX - curX);
float diffY = (targetY - curY);
matrix.postTranslate(diffX, diffY);
} else {
isAnimating = true;
mvals = new float[9];
matrix.getValues(mvals);
currentScale = mvals[0];
curX = mvals[2];
curY = mvals[5];
//Set the image parameters and invalidate display
float diffX = (targetX - curX) * 0.3f;
float diffY = (targetY - curY) * 0.3f;
matrix.postTranslate(diffX, diffY);
mHandler.postDelayed(this, 25);
}
invalidate();
}
};
private Runnable mUpdateImageScale = new Runnable() {
public void run() {
float transitionalRatio = targetScale / currentScale;
float dx;
if (Math.abs(transitionalRatio - 1) > 0.05) {
isAnimating = true;
if (targetScale > currentScale) {
dx = transitionalRatio - 1;
scaleChange = 1 + dx * 0.2f;
currentScale *= scaleChange;
if (currentScale > targetScale) {
currentScale = currentScale / scaleChange;
scaleChange = 1;
}
} else {
dx = 1 - transitionalRatio;
scaleChange = 1 - dx * 0.5f;
currentScale *= scaleChange;
if (currentScale < targetScale) {
currentScale = currentScale / scaleChange;
scaleChange = 1;
}
}
if (scaleChange != 1) {
matrix.postScale(scaleChange, scaleChange, targetScaleX, targetScaleY);
mHandler.postDelayed(mUpdateImageScale, 15);
invalidate();
} else {
isAnimating = false;
scaleChange = 1;
matrix.postScale(targetScale / currentScale, targetScale / currentScale, targetScaleX, targetScaleY);
currentScale = targetScale;
mHandler.removeCallbacks(mUpdateImageScale);
invalidate();
checkImageConstraints();
}
} else {
isAnimating = false;
scaleChange = 1;
matrix.postScale(targetScale / currentScale, targetScale / currentScale, targetScaleX, targetScaleY);
currentScale = targetScale;
mHandler.removeCallbacks(mUpdateImageScale);
invalidate();
checkImageConstraints();
}
}
};
class MyGestureDetector extends GestureDetector.SimpleOnGestureListener {
@Override
public boolean onDoubleTap(MotionEvent event) {
if (isAnimating == true) {
return true;
}
scaleChange = 1;
isAnimating = true;
targetScaleX = event.getX();
targetScaleY = event.getY();
if (Math.abs(currentScale - maxScale) > 0.1) {
targetScale = maxScale;
} else {
targetScale = minScale;
}
targetRatio = targetScale / currentScale;
mHandler.removeCallbacks(mUpdateImageScale);
mHandler.post(mUpdateImageScale);
return true;
}
@Override
public boolean onFling(MotionEvent e1, MotionEvent e2, float velocityX, float velocityY) {
return super.onFling(e1, e2, velocityX, velocityY);
}
@Override
public boolean onDown(MotionEvent e) {
return false;
}
}
}
ScaleImageActivity.java
public class ScaleImageActivity extends Activity implements OnClickListener {
private Button btndraw, btnzoom;
private Bitmap bmp , alteredBitmap;
private ScaleImageView imageview;
public static boolean flag = true;
@Override
public void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
setContentView(R.layout.batata);
initwidget();
}
private void initwidget() {
imageview = (ScaleImageView) findViewById(R.id.image);
btndraw = (Button) findViewById(R.id.activity_main_zoom_draw);
btnzoom = (Button) findViewById(R.id.activity_main_zoom_zoom);
btndraw.setOnClickListener(this);
btnzoom.setOnClickListener(this);
Intent choosePictureIntent = new Intent(
Intent.ACTION_PICK,
android.provider.MediaStore.Images.Media.EXTERNAL_CONTENT_URI);
startActivityForResult(choosePictureIntent, 0);
}
@Override
public void onClick(View arg0) {
// TODO Auto-generated method stub
if (btndraw.equals(arg0))
flag = true;
else if (btnzoom.equals(arg0))
flag = false;
}
protected void onActivityResult(int requestCode, int resultCode,
Intent intent) {
super.onActivityResult(requestCode, resultCode, intent);
if (resultCode == RESULT_OK) {
Uri imageFileUri = intent.getData();
try {
BitmapFactory.Options bmpFactoryOptions = new BitmapFactory.Options();
bmpFactoryOptions.inJustDecodeBounds = true;
bmp = BitmapFactory
.decodeStream(
getContentResolver().openInputStream(
imageFileUri), null, bmpFactoryOptions);
bmpFactoryOptions.inJustDecodeBounds = false;
bmp = BitmapFactory
.decodeStream(
getContentResolver().openInputStream(
imageFileUri), null, bmpFactoryOptions);
alteredBitmap = Bitmap.createBitmap(bmp.getWidth(), bmp.getWidth(), bmp.getConfig());
imageview.setImageBitmap(alteredBitmap);
}
catch (Exception e) {
Log.v("ERROR", e.toString());
}
}
}
}
.XML布局文件:
<?xml version="1.0" encoding="utf-8"?>
<LinearLayout xmlns:android="http://schemas.android.com/apk/res/android"
android:layout_width="match_parent"
android:layout_height="match_parent"
android:orientation="vertical" >
<LinearLayout
android:layout_width="match_parent"
android:orientation="horizontal"
android:layout_height="wrap_content" >
<Button
android:id="@+id/activity_main_zoom_zoom"
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:text="Zoom" />
<Button
android:id="@+id/activity_main_zoom_draw"
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:text="Draw" />
</LinearLayout>
<julien.pc.drawing.ScaleImageView
android:id="@+id/image"
android:layout_width="wrap_content"
android:layout_height="wrap_content" />
</LinearLayout>