先说下我要解决的问题,如图,界面上的小图片能够随意拖动,背景的大图片可以放大(超过屏幕)也可以随意拖动,我现在要做的是将小图片的位置记录下来,放大大图片里形成一张新的图片而且要保证两张图片的相对位置和大小保持不变,花点时间实现这个效果:

1.背景图片的放大可拖动我使用的是Google提供的PhototView开源包,就在再这里展示了;
2.小图片的随意拖动,这个相信对大家来说都不是大问题,我附上自己写的,参考下:
package com.example.androidhtmldemo;
import android.app.Activity;
import android.util.DisplayMetrics;
import android.view.MotionEvent;
import android.view.View;
import android.view.View.OnTouchListener;
/**
* View随手势在屏幕上移动
* @author Administrator
*
*/
public class OnViewMoveTouchListener implements OnTouchListener {
private View imgView;
private int lastX,lastY;
private int left,right,top,bottom;
private DisplayMetrics dm;
public OnViewMoveTouchListener(View v,Activity context) {
this.imgView = v;
dm = context.getResources().getDisplayMetrics();;
}
@Override
public boolean onTouch(View v, MotionEvent event) {
switch (event.getAction()) {
case MotionEvent.ACTION_DOWN:
lastX = (int) event.getRawX();
lastY = (int) event.getRawY();
break;
case MotionEvent.ACTION_MOVE:
int dx = (int) (event.getRawX() - lastX);
int dy = (int) (event.getRawY() - lastY);
left = v.getLeft() + dx;
right = v.getRight() + dx;
top = v.getTop() + dy;
bottom = v.getBottom() + dy;
if (left < 0) {
left = 0;
right = left + v.getWidth();
}
if (right > dm.widthPixels) {
right = dm.widthPixels;
left = dm.widthPixels - v.getWidth();
}
if (top < 0) {
top = 0;
bottom = dm.heightPixels + v.getHeight();
}
if (bottom > dm.heightPixels) {
bottom = dm.heightPixels;
top = dm.heightPixels - v.getHeight();
}
imgView.layout(left, top, right, bottom);
lastX = (int) event.getRawX();
lastY = (int) event.getRawY();
break;
case MotionEvent.ACTION_UP:
break;
}
return true;
}
}
3.相关方法:
①RectF mRect = mPhotoView.getDisplayRect(); 这里获取的是图片占据的矩形,可以获取矩形四个角的坐标,当然获取的值是相对于我们应用在屏幕上占据的空间如果超出屏幕会获取负值
②mCanvas.drawBitmap(bitmap, left, top, paint); bitmap:要在画布上绘制的图片,left:在画布上绘制图片X起点;Top:在画布上绘制图片的Y起点;paint画笔,可以为null;
③ mCanvas.drawBitmap(bitmap, src, dst, paint);bitmap:在要画布上绘制的Bitmap,src:bitmap在画布上占据的矩形,dst:这个是Bitmap在画布上占据的矩形和位置,我解释的可能不太清楚(简单的说:src就是说明这个Bitmap需要多大的空间,当然如果这个空间小于位图的尺寸,位图只会显示一部分,具体显示哪一部分可以调整这个Rect来获取;dst:这个标示要把Bitmap绘制在画布上的哪个位置),可以参考下下面代码:
Rect mSrcRect = new Rect(0, 0, dpDrawable.getWidth(), dpDrawable.getHeight()); Rect mDstRect = new Rect((int)x, (int)y, (int)(x + width), (int)(y + height));
4.相关代码:
package com.example.androidhtmldemo;
import android.content.Context;
import android.graphics.Bitmap;
import android.graphics.Bitmap.Config;
import android.graphics.BitmapFactory;
import android.graphics.Canvas;
import android.graphics.Rect;
import android.util.Log;
public class DrawBpOnBpUtils {
private Context context;
private Bitmap bgDrawable, dpDrawable;
private int bgDrawableId,dpDrawableId;
/**
*
* @param context 上下文环境
* @param bgDrawableId 背景图片
* @param dpDrawableId 印章
*/
public DrawBpOnBpUtils(Context context, int bgDrawableId, int dpDrawableId) {
this.context = context;
this.bgDrawableId = bgDrawableId;
this.dpDrawableId = dpDrawableId;
}
/** *画布上能分配给Bitmap的空间是有限的,为了让图片全部显示就对图片做适当的压缩
* @param drawableId
* @param scale 图片相对比例
* @return
*/
private Bitmap getBitmapByBitmap(int drawableId,float width,float height) {
int simpleSize = 1 ;
BitmapFactory.Options options = new BitmapFactory.Options();
options.inJustDecodeBounds = true;
BitmapFactory.decodeResource(context.getResources(), drawableId,options);
while ((options.outWidth / simpleSize > width) || (options.outHeight / simpleSize > height)) {
simpleSize *= 2;
}
options.inJustDecodeBounds = false;
options.inSampleSize = simpleSize;
return BitmapFactory.decodeResource(context.getResources(), drawableId);
}
/**
* 绘制图片
* @param scale 两张Bitmap相对比例
* @param x dpDrawable在canvas的 left
* @param y dpDrawable在canvase的 top
* @return
*/
public Bitmap onDrawBitmap(float width,float height,float x,float y){
bgDrawable = BitmapFactory.decodeResource(context.getResources(), bgDrawableId);
dpDrawable = getBitmapByBitmap(dpDrawableId, width,height);
Bitmap result = Bitmap.createBitmap(bgDrawable.getWidth(), bgDrawable.getHeight(), Config.ARGB_8888);
Rect mSrcRect = new Rect(0, 0, dpDrawable.getWidth(), dpDrawable.getHeight());
Rect mDesRect = new Rect((int)x, (int)y, (int)(x + width), (int)(y + height));
Canvas mCanvas = new Canvas(result);
mCanvas.drawBitmap(bgDrawable, 0, 0, null);
mCanvas.drawBitmap(dpDrawable, mSrcRect, mDesRect, null);
Log.e(getClass().getName(), "x:" + x + ";y:" + y + ";top:" + (x + dpDrawable.getWidth()) + "right:" + (y + dpDrawable.getHeight()));
bgDrawable.recycle();
dpDrawable.recycle();
bgDrawable = null;
dpDrawable = null;
return result;
}
}
package com.example.androidhtmldemo;
import uk.co.senab.photoview.PhotoView;
import android.app.Activity;
import android.graphics.Bitmap;
import android.graphics.BitmapFactory;
import android.graphics.RectF;
import android.os.Bundle;
import android.util.Log;
import android.view.View;
import android.view.View.OnClickListener;
import android.view.Window;
import android.widget.Button;
import com.example.androidhtmldemo.OnViewMoveTouchListener.OnViewMoveRsultCallback;
public class ShowPhotoActivity extends Activity{
private PhotoView mPhotoView;
private PhotoView imgSeal;
private Button btnTakePhoto;
private Bitmap newBitmap;
private float newLeft = 0;
private float newTop = 0;
@Override
protected void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
requestWindowFeature(Window.FEATURE_NO_TITLE);
setContentView(R.layout.activity_showphoto);
mPhotoView = (PhotoView) findViewById(R.id.photoView1);
imgSeal = (PhotoView) findViewById(R.id.imgPutSeal);
btnTakePhoto = (Button) findViewById(R.id.btnTakePhoto);
OnViewMoveTouchListener onTouchListener = new OnViewMoveTouchListener(imgSeal, this); //imgSeal是可以随意拖动的,尝试获取他的坐标结果都不太满意,只好做一个回调让结果返回到这里(汗颜)
onTouchListener.setOnViewMoveRsultCallback(new OnViewMoveRsultCallback() {
@Override
public void onViewMoveResultCallback(float left, float top, float right,
float bottom) {
newLeft = left;
newTop = top;
}
});
imgSeal.setOnTouchListener(onTouchListener);
imgSeal.setDrawingCacheEnabled(true);
btnTakePhoto.setOnClickListener(new OnClickListener() {
@Override
public void onClick(View arg0) {
drawBitmap(newLeft,newTop);
}
});
}
/**
*
* @param left 印章 left
* @param top 印章 Top
*/
private void drawBitmap(float left,float top){
if(newBitmap != null){
newBitmap.recycle();
newBitmap = null;
}
Log.e(getPackageName(), "newLeft:" + newLeft + ";newTop:" + newTop);
RectF mRect = mPhotoView.getDisplayRect();
float x = left;
float y = top;
if(mRect.left < 0){
x += Math.abs(mRect.left);
}
if(mRect.top < 0){
y += Math.abs(mRect.top);
}
if(mRect.left > 0){
x -= mRect.left;
}
if(mRect.top > 0){
y -= mRect.top;
}
BitmapFactory.Options options = new BitmapFactory.Options();
options.inJustDecodeBounds = false;
Bitmap bp = BitmapFactory.decodeResource(getResources(), R.drawable.img_test,options);
float scale = bp.getWidth() / mRect.width(); //原图的宽与有效区域宽的比值
bp.recycle();
bp = null;
newBitmap = new DrawBpOnBpUtils(this, R.drawable.img_test, R.drawable.images)
.onDrawBitmap(imgSeal.getWidth() * scale,imgSeal.getHeight() * scale, x * scale,y * scale);
mPhotoView.setImageBitmap(newBitmap);
}
}
附上布局:
<?xml version="1.0" encoding="utf-8"?>
<RelativeLayout xmlns:android="http://schemas.android.com/apk/res/android"
android:layout_width="match_parent"
android:layout_height="match_parent"
android:orientation="vertical" >
<uk.co.senab.photoview.PhotoView
android:id="@+id/photoView1"
android:layout_width="fill_parent"
android:layout_height="fill_parent"
android:layout_gravity="center_horizontal"
android:adjustViewBounds="true"
android:src="@drawable/img_test" />
<uk.co.senab.photoview.PhotoView
android:id="@+id/imgPutSeal"
android:layout_width="48dp"
android:layout_height="48dp"
android:adjustViewBounds="true"
android:src="@drawable/images" />
<Button
android:id="@+id/btnTakePhoto"
android:layout_width="96dp"
android:layout_height="48dp"
android:layout_alignParentBottom="true"
android:layout_centerHorizontal="true"
android:text="快照" />
</RelativeLayout>
还要需要改进的地方:①imgSeal的大小可以随着mPhotoView的大小和位置而改变②之后生成新图片应该根据背景图片的大小和位置来显示,欢迎大家交流
来源:https://www.cnblogs.com/ZhangXiangQian/p/4942189.html