android - 如何像 Facebook 个人资料图片选择工具那样移动和缩放图片?

标签 android image crop

我想要像 Android 上的 Facebook 个人资料图像选择一样裁剪图像,用户可以在其中移动和缩放图像,从而调整图像大小和/或裁剪图像:

screenshot of the tool in question

我怎样才能做到这一点?

最佳答案

我有同样的要求。我结合 PhotoView 解决了它和 Cropper通过在 cropper 库中将 ImageView 替换为 PhotoView

我不得不修改 CropWindow 类以避免触摸事件没有被正确处理:

   public void setImageView(PhotoView pv){
        mPhotoView = pv;
    }
    @Override
    public boolean onTouchEvent(MotionEvent event) {

        // If this View is not enabled, don't allow for touch interactions.
        if (!isEnabled()) {
            return false;
        }

        switch (event.getAction()) {

            case MotionEvent.ACTION_DOWN:
                  boolean dispatch = onActionDown(event.getX(), event.getY());
                  if(!dispatch)
                    mPhotoView.dispatchTouchEvent(event);

                return dispatch;

            case MotionEvent.ACTION_UP:
            case MotionEvent.ACTION_CANCEL:
                getParent().requestDisallowInterceptTouchEvent(false);
                onActionUp();
                return true;

            case MotionEvent.ACTION_MOVE:
                onActionMove(event.getX(), event.getY());
                getParent().requestDisallowInterceptTouchEvent(true);
                return true;

            default:
                return false;
        }
    }

CropImageView 类中也做了一些改变:

private void init(Context context) {

    final LayoutInflater inflater = LayoutInflater.from(context);
    final View v = inflater.inflate(R.layout.crop_image_view, this, true);

    mImageView = (PhotoView) v.findViewById(R.id.ImageView_image2);

    setImageResource(mImageResource);
    mCropOverlayView = (CropOverlayView) v.findViewById(R.id.CropOverlayView);
    mCropOverlayView.setInitialAttributeValues(mGuidelines, mFixAspectRatio, mAspectRatioX, mAspectRatioY);
    mCropOverlayView.setImageView(mImageView);
}

您会注意到我已经将 Cropper 库中 R.layout.crop_image_view 中的 ImageView 替换为 PhotoView

Cropper 库支持固定尺寸,而 PhotoView 允许您移动和缩放照片,让您两全其美。 :)

希望对您有所帮助。

编辑,对于那些询问如何获取仅在裁剪区域内的图像的人:

private Bitmap getCurrentDisplayedImage(){
        Bitmap result = Bitmap.createBitmap(mImageView.getWidth(), mImageView.getHeight(), Bitmap.Config.RGB_565);
        Canvas c = new Canvas(result);
        mImageView.draw(c);
        return result;
    }
    public Bitmap getCroppedImage() {

        Bitmap mCurrentDisplayedBitmap = getCurrentDisplayedImage();
        final Rect displayedImageRect = ImageViewUtil2.getBitmapRectCenterInside(mCurrentDisplayedBitmap, mImageView);

        // Get the scale factor between the actual Bitmap dimensions and the
        // displayed dimensions for width.
        final float actualImageWidth =mCurrentDisplayedBitmap.getWidth();
        final float displayedImageWidth = displayedImageRect.width();
        final float scaleFactorWidth = actualImageWidth / displayedImageWidth;

        // Get the scale factor between the actual Bitmap dimensions and the
        // displayed dimensions for height.
        final float actualImageHeight = mCurrentDisplayedBitmap.getHeight();
        final float displayedImageHeight = displayedImageRect.height();
        final float scaleFactorHeight = actualImageHeight / displayedImageHeight;

        // Get crop window position relative to the displayed image.
        final float cropWindowX = Edge.LEFT.getCoordinate() - displayedImageRect.left;
        final float cropWindowY = Edge.TOP.getCoordinate() - displayedImageRect.top;
        final float cropWindowWidth = Edge.getWidth();
        final float cropWindowHeight = Edge.getHeight();

        // Scale the crop window position to the actual size of the Bitmap.
        final float actualCropX = cropWindowX * scaleFactorWidth;
        final float actualCropY = cropWindowY * scaleFactorHeight;
        final float actualCropWidth = cropWindowWidth * scaleFactorWidth;
        final float actualCropHeight = cropWindowHeight * scaleFactorHeight;

        // Crop the subset from the original Bitmap.
        final Bitmap croppedBitmap = Bitmap.createBitmap(mCurrentDisplayedBitmap,
                                                         (int) actualCropX,
                                                         (int) actualCropY,
                                                         (int) actualCropWidth,
                                                         (int) actualCropHeight);

        return croppedBitmap;
    }

    public RectF getActualCropRect() {

        final Rect displayedImageRect = ImageViewUtil.getBitmapRectCenterInside(mBitmap, mImageView);

        final float actualImageWidth = mBitmap.getWidth();
        final float displayedImageWidth = displayedImageRect.width();
        final float scaleFactorWidth = actualImageWidth / displayedImageWidth;

        // Get the scale factor between the actual Bitmap dimensions and the displayed
        // dimensions for height.
        final float actualImageHeight = mBitmap.getHeight();
        final float displayedImageHeight = displayedImageRect.height();
        final float scaleFactorHeight = actualImageHeight / displayedImageHeight;

        // Get crop window position relative to the displayed image.
        final float displayedCropLeft = Edge.LEFT.getCoordinate() - displayedImageRect.left;
        final float displayedCropTop = Edge.TOP.getCoordinate() - displayedImageRect.top;
        final float displayedCropWidth = Edge.getWidth();
        final float displayedCropHeight = Edge.getHeight();

        // Scale the crop window position to the actual size of the Bitmap.
        float actualCropLeft = displayedCropLeft * scaleFactorWidth;
        float actualCropTop = displayedCropTop * scaleFactorHeight;
        float actualCropRight = actualCropLeft + displayedCropWidth * scaleFactorWidth;
        float actualCropBottom = actualCropTop + displayedCropHeight * scaleFactorHeight;

        // Correct for floating point errors. Crop rect boundaries should not exceed the
        // source Bitmap bounds.
        actualCropLeft = Math.max(0f, actualCropLeft);
        actualCropTop = Math.max(0f, actualCropTop);
        actualCropRight = Math.min(mBitmap.getWidth(), actualCropRight);
        actualCropBottom = Math.min(mBitmap.getHeight(), actualCropBottom);

        final RectF actualCropRect = new RectF(actualCropLeft,
                                               actualCropTop,
                                               actualCropRight,
                                               actualCropBottom);

        return actualCropRect;
    }




private boolean onActionDown(float x, float y) {    
        final float left = Edge.LEFT.getCoordinate();
        final float top = Edge.TOP.getCoordinate();
        final float right = Edge.RIGHT.getCoordinate();
        final float bottom = Edge.BOTTOM.getCoordinate();    
        mPressedHandle = HandleUtil.getPressedHandle(x, y, left, top, right, bottom, mHandleRadius);    
        if (mPressedHandle == null)
            return false;
        mTouchOffset = HandleUtil2.getOffset(mPressedHandle, x, y, left, top, right, bottom);

        invalidate();
        return true;
    }

关于android - 如何像 Facebook 个人资料图片选择工具那样移动和缩放图片?,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/22683887/

相关文章:

android - Google Play 服务在虚拟机上已过时

javascript - 使用带有自定义 header 的 Ajax 加载图像

java - 图像不会显示在 JLabel 中

android - 上传前从相机裁剪图像(Phonegap)

android - Android 2.1 的浏览器是否支持 HTML 5 以及它播放什么视频格式?

android - 从 Android 菜单项图标获取可绘制对象

javascript - Fabric.js "reverse"和 "layered"剪裁/剪裁

javascript - 使用 JavaScript 裁剪图像在 IE 中有效,但在 Firefox 中无效

java - 快速 Activity 切换导致应用程序崩溃

Jquery图像加载顺序