Android 选取 Bitmap 上点的控件布局

创建一个放大选点的布局

选点图片

在工作中,遇到了一个需求,需要选中图片上的某个位置,获得对应图像的坐标,如果直接用手去触摸,误差太大,我们想到的一个方式时,触摸图片后,用另外一个 ImageView 显示触摸点附近的一个范围的局部放大图像,随着手指的移动,局部放大图像也会跟着移动,为了防止局部图像移动太快,设定局部图像移动的距离是手指移动的十分之一,这样可以更好的控制移动距离。其中局部放大的的 ImageView 中心有一个指示 icon,即我们选中的点是恰好在局部放大 ImageView 中心位置的点。

public class ImageDotLayout extends FrameLayout {
	//放图片的 imageView
    private ImageView ivImage;
	/**放大镜作用的 imageView,放局部放大的图片 */
    private ImageView ivMagnifier;
	// 局部放大的图片
	private Bitmap bmMagnifier;
	// 瞄准镜指示图片,它的作用是,当移动的图片的位置
	// 跟瞄准镜指示图片重合时,表明当前选中的点
    private ImageView ivTarget;
	// 放大图片用到的 Matrix
	private Matrix matrix;
	 // 布局的宽度和高度
    private int mWidth, mHeight;
	// 瞄准镜指示图片宽高
    private int iconTargetW = 16, iconTargetH = 16;
	// 触摸点的坐标
    private float mX, mY;
	// 偏移坐标
    private float mOffsetX, mOffsetY;
	// 按下的点的中心坐标
    private float centerX, centerY;
    // 放大的倍数
    private float scaleX = 10f, scaleY = 10f;
    // 放大镜显示图片的宽高
    private int bmMagnifierW = 50, bmMagnifierH = 50;
    // 修改后的图片的宽度,高度
    private int resultBitmapWidth, resultBitmapHeight;
	// 要显示的图片
	private Bitmap bitmap;
	
   void initView(Context context) {
		ivImage = new ImageView(context);
        LayoutParams layoutParams =
                new LayoutParams(ViewGroup.LayoutParams.MATCH_PARENT, ViewGroup.LayoutParams.MATCH_PARENT);
        addView(ivImage, layoutParams);
		
// 获取 ivImage 的宽高,暂时在这里实现
        ivImage.post(new Runnable() {
            @Override
            public void run() {
                mWidth = ivImage.getWidth();
                mHeight = ivImage.getHeight();
                ivMagnifier = new ImageView(mContext);
                // 修改宽高,改成正方形
                int width;
                if (mWidth < mHeight) {
                    width = mWidth / 2;
                } else {
                    width = mHeight / 2;
                }
                LayoutParams lpMagnifier =
                        new LayoutParams(width, width);
                addView(ivMagnifier, lpMagnifier);
                ivMagnifier.setVisibility(GONE);

   ivTarget = new ImageView(mContext);
                LayoutParams lpTarget =
                        new LayoutParams(iconTargetW, iconTargetH);
                ivTarget.setImageDrawable(getResources().getDrawable(R.drawable.icon_target));
                addView(ivTarget, lpTarget);
                ivTarget.setVisibility(GONE);
            }
        });
		
matrix = new Matrix();
        matrix.postScale(scaleX, scaleY);
		
ivImage.setOnTouchListener(new OnTouchListener() {
            @Override
            public boolean onTouch(View v, MotionEvent event) {

   if (bitmap == null) {
                    return true;
                }
                // x y 值做一个处理
                // 放大的图加一个中心标准点
                switch (event.getAction()) {
                    case MotionEvent.ACTION_DOWN:
                        mX = event.getX();
                        mY = event.getY();
                        centerX = mX;
                        centerY = mY;
                        // 对 x 和 y 进行一个判断,来设置放大的 imageView 在哪里显示
                        if (mX < mWidth / 2 && mY < mHeight / 2) {
                            // 调整位置
                            LayoutParams lpMagnifier = (LayoutParams) ivMagnifier.getLayoutParams();
                            if (mWidth < mHeight) {
                                lpMagnifier.leftMargin = mWidth / 2;
                                lpMagnifier.topMargin = mHeight / 2 + ((mHeight - mWidth) / 4);
                            } else {
                                lpMagnifier.leftMargin = mWidth / 2 + ((mWidth - mHeight) / 4);
                                lpMagnifier.topMargin = mHeight / 2;
                            }
                            ivMagnifier.setLayoutParams(lpMagnifier);

   LayoutParams lpTarget = (LayoutParams) ivTarget.getLayoutParams();
                            lpTarget.leftMargin = mWidth / 4 * 3 - iconTargetW / 2;
                            lpTarget.topMargin = mHeight / 4 * 3 - iconTargetH / 2;
                            ivTarget.setLayoutParams(lpTarget);
                        } else if (mX > mWidth / 2 && mY < mHeight / 2) {
                            LayoutParams lpMagnifier = (LayoutParams) ivMagnifier.getLayoutParams();
                            if (mWidth < mHeight) {
                                lpMagnifier.leftMargin = 0;
                                lpMagnifier.topMargin = mHeight / 2 + ((mHeight - mWidth) / 4);
                            } else {
                                lpMagnifier.leftMargin = 0 + ((mWidth - mHeight) / 4);
                                lpMagnifier.topMargin = mHeight / 2;
                            }
                            ivMagnifier.setLayoutParams(lpMagnifier);

   LayoutParams lpTarget = (LayoutParams) ivTarget.getLayoutParams();
                            lpTarget.leftMargin = mWidth / 4 - iconTargetW / 2;
                            lpTarget.topMargin = mHeight / 4 * 3 - iconTargetH / 2;
                            ivTarget.setLayoutParams(lpTarget);
                        } else if (mX < mWidth / 2 && mY > mHeight / 2) {
                            LayoutParams lpMagnifier = (LayoutParams) ivMagnifier.getLayoutParams();
                            if (mWidth < mHeight) {
                                lpMagnifier.leftMargin = mWidth / 2;
                                lpMagnifier.topMargin = 0 + ((mHeight - mWidth) / 4);
                            } else {
                                lpMagnifier.leftMargin = mWidth / 2 + ((mWidth - mHeight) / 4);
                                lpMagnifier.topMargin = 0;
                            }
                            ivMagnifier.setLayoutParams(lpMagnifier);

   LayoutParams lpTarget = (LayoutParams) ivTarget.getLayoutParams();
                            lpTarget.leftMargin = mWidth / 4 * 3 - iconTargetW / 2;
                            lpTarget.topMargin = mHeight / 4 - iconTargetH / 2;
                            ivTarget.setLayoutParams(lpTarget);
                        } else {
                            LayoutParams lpMagnifier = (LayoutParams) ivMagnifier.getLayoutParams();
                            if (mWidth < mHeight) {
                                lpMagnifier.leftMargin = 0;
                                lpMagnifier.topMargin = 0 + ((mHeight - mWidth) / 4);
                            } else {
                                lpMagnifier.leftMargin = 0 + ((mWidth - mHeight) / 4);
                                lpMagnifier.topMargin = 0;
                            }
                            ivMagnifier.setLayoutParams(lpMagnifier);

   LayoutParams lpTarget = (LayoutParams) ivTarget.getLayoutParams();
                            lpTarget.leftMargin = mWidth / 4 - iconTargetW / 2;
                            lpTarget.topMargin = mHeight / 4 - iconTargetH / 2;
                            ivTarget.setLayoutParams(lpTarget);
                        }
                        // 放大的 imageView 显示
                        ivMagnifier.setVisibility(VISIBLE);
                        ivMagnifier.bringToFront();
                        ivTarget.setVisibility(VISIBLE);
                        ivTarget.bringToFront();
                        showMagnifierImage();
                        break;
                    case MotionEvent.ACTION_MOVE:
                        // 将要放大的图片位置显示到 imageView 中
                        float dx = event.getX() - centerX;
                        float dy = event.getY() - centerY;
                        mX =  centerX + dx / 10;
                        mY =  centerY + dy / 10;
                        showMagnifierImage();
                        break;
                    case MotionEvent.ACTION_UP:
                        // 放大的 imageView 隐藏
                        ivMagnifier.setVisibility(GONE);
                        ivTarget.setVisibility(GONE);
                       // 保存当前位置的点
                        if (bmMagnifier != null) {
                            Log.e("WillWolf", "mX:" + mX + ", mY" + mY + ", mOffsetX" + mOffsetX + ", mOffsetY" + mOffsetY);
                            
   }
                        break;
                }
                return true;
            }
        });
	}
	
private void showMagnifierImage() {
        int width = bmMagnifierW;
        int height = bmMagnifierH;
        // 目标点的坐标
        float dst[] = convertPosition(mX, mY);

   float dstX = dst[0];
        float dstY = dst[1];

   // 这里是表示最右边
        if (dstX + bmMagnifierW / 2 >= bitmap.getWidth()) {
            width = (int) (bmMagnifierW - (dstX + bmMagnifierW / 2 - bitmap.getWidth()));
            if (width <= 0) {
                width = 1;
            }
        } else {
            width = bmMagnifierW;
        }
        // 这里是最下边
        if (dstY + bmMagnifierH / 2 >= bitmap.getHeight()) {
            height = (int) (bmMagnifierH - (dstY + bmMagnifierH / 2 - bitmap.getHeight()));
            if (height <= 0) {
                height = 1;
            }
        } else {
            height = bmMagnifierH;
        }
        // 如果从屏幕边缘处下滑,会出现值 < 0 的情况
        if (dstX - bmMagnifierW / 2 >= 0 && dstY - bmMagnifierH / 2 >= 0) {
            // 做了边界处理,有可能会导致左边的位置 + 显示的宽度 > 图片的宽度而崩溃。
            int x = (int) dstX - bmMagnifierW / 2;
            if (x + width >= bitmap.getWidth()) {
                x = bitmap.getWidth() - width;
            }
            int y = (int) dstY - bmMagnifierH / 2;
            if (y + height >= bitmap.getHeight()) {
                y = bitmap.getHeight() - height;
            }
            bmMagnifier = Bitmap.createBitmap(bitmap, x, y, width, height, matrix, true);
            ivMagnifier.setImageBitmap(bmMagnifier);
        } else {
            // 如果 dstX 大于 0, 表示是在最左边
            if (dstX > 0 && dstY - bmMagnifierH / 2 >= 0) {
                bmMagnifier = Bitmap.createBitmap(bitmap, (int) dstX, (int) dstY - bmMagnifierH / 2, (int) (dstX * 2), height, matrix, true);
                ivMagnifier.setImageBitmap(bmMagnifier);
            } else if (dstX - bmMagnifierW / 2 >= 0 && dstY > 0) {
                // 如果 dstY 大于 0,表示是在最上边
                bmMagnifier = Bitmap.createBitmap(bitmap, (int) dstX - bmMagnifierW / 2, (int) dstY, width, (int) (dstY * 2), matrix, true);
                ivMagnifier.setImageBitmap(bmMagnifier);
            } else {

   }
        }
    }
	
	
	
	
/**
     * 设置图像并显示
     * 
     */
    public void setBitmap(int direction, Bitmap bitmap) {
		// 为了解决边界问题,对 bitmap 进行一个扩大操作
        resultBitmapWidth = bitmap.getWidth() + 50;
        resultBitmapHeight = bitmap.getHeight() + 50;
        Bitmap result = Bitmap.createBitmap(resultBitmapWidth,
                resultBitmapHeight, Bitmap.Config.RGB_565);
        Canvas canvas = new Canvas(result);
        canvas.drawBitmap(bitmap, 25, 25, null);
        this.bitmap = result;
        ivImage.setImageBitmap(result);
    }
	
private int mOffsetX;
	private int mOffsetY;
	public float[] convertPosition(float x, float y) {
        // 使用系统提供的 api 进行坐标点的转换,即 ImageView 的坐标点
		// 转换成 Bitmap 上的坐标点
		// 目标点的坐标,必须要有图片设置到 ImageView 中
        float dst[] = new float[2];
        // 获取到ImageView的matrix
        Matrix imageMatrix = photoView.getImageMatrix();
        // 创建一个逆矩阵
        Matrix inverseMatrix = new Matrix();
        // 求逆,逆矩阵被赋值
        imageMatrix.invert(inverseMatrix);
        // 通过逆矩阵映射得到目标点 dst 的值
        inverseMatrix.mapPoints(dst, new float[]{x, y});

// 进行一个比例换算,获取到 Bitmap 上的坐标点
		// 比如 Bitmap 尺寸是 1280 * 720,ImageView 
		// 的尺寸是 200 * 100,那么 ImageView 的一半位置
		// 肯定也对应 Bitmap 一半的位置。
        float[] realPoint = new float[2];
        realPoint[0] = resultBitmapWidth * x / mWidth;
        realPoint[1] = resultBitmapHeight * y / mHeight;

   // 上述两种计算方式会有一点偏差。
        mOffsetX = (realPoint[0] - dst[0]) * mWidth / resultBitmapWidth;
        mOffsetY = (realPoint[1] - dst[1]) * mHeight / resultBitmapHeight;
        Log.e("WillWolf", "mOffset-->" + mOffsetX + ", " + mOffsetY);
        return realPoint;
    }


public void release() {
        if (bitmap != null) {
            bitmap.recycle();
        }
        if (bmMagnifier != null) {
            bmMagnifier.recycle();
        }
    }
}
  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值