ImageView无法在运行时调整大小

时间:2015-10-25 15:10:13

标签: java android

我正在寻找Cropper和Edmodo的图像crooper开源应用程序,它做得非常好,除了代替图像裁剪我想用它来缩放我的图像,我的逻辑每次都是裁剪窗口/视图大小的变化我会改变我的imageview的高度和宽度以匹配裁剪视图但每次我这样做都没有任何反应,但看着LogCat似乎我的高度和宽度确实发生了变化,除非imageview看起来仍然看起来相同是Class,我的更改在onSizeChanged()

中发表了评论
/*
 * Copyright 2013, Edmodo, Inc. 
 *
 * Licensed under the Apache License, Version 2.0 (the "License"); you may not use this work except in compliance with the License.
 * You may obtain a copy of the License in the LICENSE file, or at:
 *
 * http://www.apache.org/licenses/LICENSE-2.0
 *
 * Unless required by applicable law or agreed to in writing, software distributed under the License is distributed on an "AS IS" 
 * BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. See the License for the specific language 
 * governing permissions and limitations under the License. 
 */

package com.theartofdev.edmodo.cropper.cropwindow;

import android.content.Context;
import android.graphics.Canvas;
import android.graphics.Paint;
import android.graphics.Path;
import android.graphics.Rect;
import android.graphics.RectF;
import android.graphics.Region;
import android.util.AttributeSet;
import android.util.DisplayMetrics;
import android.util.Log;
import android.util.Pair;
import android.util.TypedValue;
import android.view.MotionEvent;
import android.view.View;
import android.widget.Toast;

import com.theartofdev.edmodo.cropper.CropImageView;
import com.theartofdev.edmodo.cropper.cropwindow.edge.Edge;
import com.theartofdev.edmodo.cropper.cropwindow.handle.Handle;
import com.theartofdev.edmodo.cropper.util.AspectRatioUtil;
import com.theartofdev.edmodo.cropper.util.HandleUtil;
import com.theartofdev.edmodo.cropper.util.PaintUtil;

/**
* A custom View representing the crop window and the shaded background outside the crop window.
*/
 public class CropOverlayView extends View {

//region: Fields and Consts

private static final int SNAP_RADIUS_DP = 6;

private static final float DEFAULT_SHOW_GUIDELINES_LIMIT = 100;

// Gets default values from PaintUtil, sets a bunch of values such that the
// corners will draw correctly
private static final float DEFAULT_CORNER_THICKNESS_DP = PaintUtil.getCornerThickness();

private static final float DEFAULT_LINE_THICKNESS_DP = PaintUtil.getLineThickness();

private static final float DEFAULT_CORNER_OFFSET_DP = (DEFAULT_CORNER_THICKNESS_DP / 2) - (DEFAULT_LINE_THICKNESS_DP / 2);

private static final float DEFAULT_CORNER_EXTENSION_DP = DEFAULT_CORNER_THICKNESS_DP / 2
        + DEFAULT_CORNER_OFFSET_DP;

private static final float DEFAULT_CORNER_LENGTH_DP = 20;

private static final int GUIDELINES_ON_TOUCH = 1;

private static final int GUIDELINES_ON = 2;

private static RectF mRectF = new RectF();

/**
 * The Paint used to draw the white rectangle around the crop area.
 */
private Paint mBorderPaint;

/**
 * The Paint used to draw the guidelines within the crop area when pressed.
 */
private Paint mGuidelinePaint;

/**
 * The Paint used to draw the corners of the Border
 */
private Paint mCornerPaint;

/**
 * The Paint used to darken the surrounding areas outside the crop area.
 */
private Paint mBackgroundPaint;

/**
 * The bounding box around the Bitmap that we are cropping.
 */
private Rect mBitmapRect;

// The radius of the touch zone (in pixels) around a given Handle.
private float mHandleRadius;

// An edge of the crop window will snap to the corresponding edge of a
// specified bounding box when the crop window edge is less than or equal to
// this distance (in pixels) away from the bounding box edge.
private float mSnapRadius;

// Holds the x and y offset between the exact touch location and the exact
// handle location that is activated. There may be an offset because we
// allow for some leeway (specified by mHandleRadius) in activating a
// handle. However, we want to maintain these offset values while the handle
// is being dragged so that the handle doesn't jump.
private Pair<Float, Float> mTouchOffset;

// The Handle that is currently pressed; null if no Handle is pressed.
private Handle mPressedHandle;

// Flag indicating if the crop area should always be a certain aspect ratio
// (indicated by mTargetAspectRatio).
private boolean mFixAspectRatio = CropImageView.DEFAULT_FIXED_ASPECT_RATIO;

// Floats to save the current aspect ratio of the image
private int mAspectRatioX = CropImageView.DEFAULT_ASPECT_RATIO_X;

private int mAspectRatioY = CropImageView.DEFAULT_ASPECT_RATIO_Y;

// The aspect ratio that the crop area should maintain; this variable is
// only used when mMaintainAspectRatio is true.
private float mTargetAspectRatio = ((float) mAspectRatioX) / mAspectRatioY;

/**
 * Instance variables for customizable attributes
 */
private int mGuidelines;

/**
 * The shape of the cropping area - rectangle/circular.
 */
private CropImageView.CropShape mCropShape;



// Whether the Crop View has been initialized for the first time
private boolean initializedCropWindow = false;

// Instance variables for the corner values
private float mCornerExtension;

private float mCornerOffset;

private float mCornerLength;
//endregion

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

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

/**
 * Informs the CropOverlayView of the image's position relative to the
 * ImageView. This is necessary to call in order to draw the crop window.
 *
 * @param bitmapRect the image's bounding box
 */
public void setBitmapRect(Rect bitmapRect) {
    mBitmapRect = bitmapRect;
    initCropWindow(mBitmapRect);
}

/**
 * Resets the crop overlay view.
 */
public void resetCropOverlayView() {

    if (initializedCropWindow) {
        initCropWindow(mBitmapRect);
        invalidate();
    }
}

/**
 * The shape of the cropping area - rectangle/circular.
 */
public void setCropShape(CropImageView.CropShape cropShape) {
    mCropShape = cropShape;
    invalidate();
}

/**
 * Sets the guidelines for the CropOverlayView to be either on, off, or to
 * show when resizing the application.
 *
 * @param guidelines Integer that signals whether the guidelines should be
 * on, off, or only showing when resizing.
 */
public void setGuidelines(int guidelines) {
    if (guidelines < 0 || guidelines > 2)
        throw new IllegalArgumentException("Guideline value must be set between 0 and 2. See documentation.");
    else {
        mGuidelines = guidelines;

        if (initializedCropWindow) {
            initCropWindow(mBitmapRect);
            invalidate();
        }
    }
}

/**
 * Sets whether the aspect ratio is fixed or not; true fixes the aspect
 * ratio, while false allows it to be changed.
 *
 * @param fixAspectRatio Boolean that signals whether the aspect ratio
 * should be maintained.
 */
public void setFixedAspectRatio(boolean fixAspectRatio) {
    mFixAspectRatio = fixAspectRatio;

    if (initializedCropWindow) {
        initCropWindow(mBitmapRect);
        invalidate();
    }
}

/**
 * Sets the X value of the aspect ratio; is defaulted to 1.
 *
 * @param aspectRatioX int that specifies the new X value of the aspect
 * ratio
 */
public void setAspectRatioX(int aspectRatioX) {
    if (aspectRatioX <= 0)
        throw new IllegalArgumentException("Cannot set aspect ratio value to a number less than or equal to 0.");
    else {
        mAspectRatioX = aspectRatioX;
        mTargetAspectRatio = ((float) mAspectRatioX) / mAspectRatioY;

        if (initializedCropWindow) {
            initCropWindow(mBitmapRect);
            invalidate();
        }
    }
}

/**
 * Sets the Y value of the aspect ratio; is defaulted to 1.
 *
 * @param aspectRatioY int that specifies the new Y value of the aspect
 * ratio
 */
public void setAspectRatioY(int aspectRatioY) {
    if (aspectRatioY <= 0)
        throw new IllegalArgumentException("Cannot set aspect ratio value to a number less than or equal to 0.");
    else {
        mAspectRatioY = aspectRatioY;
        mTargetAspectRatio = ((float) mAspectRatioX) / mAspectRatioY;

        if (initializedCropWindow) {
            initCropWindow(mBitmapRect);
            invalidate();
        }
    }
}

/**
 * Sets all initial values, but does not call initCropWindow to reset the
 * views. Used once at the very start to initialize the attributes.
 *
 * @param guidelines Integer that signals whether the guidelines should be
 * on, off, or only showing when resizing.
 * @param fixAspectRatio Boolean that signals whether the aspect ratio
 * should be maintained.
 * @param aspectRatioX float that specifies the new X value of the aspect
 * ratio
 * @param aspectRatioY float that specifies the new Y value of the aspect
 * ratio
 */
public void setInitialAttributeValues(int guidelines, boolean fixAspectRatio, int aspectRatioX, int aspectRatioY) {
    if (guidelines < 0 || guidelines > 2)
        throw new IllegalArgumentException("Guideline value must be set between 0 and 2. See documentation.");
    else
        mGuidelines = guidelines;

    mFixAspectRatio = fixAspectRatio;

    if (aspectRatioX <= 0)
        throw new IllegalArgumentException("Cannot set aspect ratio value to a number less than or equal to 0.");
    else {
        mAspectRatioX = aspectRatioX;
        mTargetAspectRatio = ((float) mAspectRatioX) / mAspectRatioY;
    }

    if (aspectRatioY <= 0)
        throw new IllegalArgumentException("Cannot set aspect ratio value to a number less than or equal to 0.");
    else {
        mAspectRatioY = aspectRatioY;
        mTargetAspectRatio = ((float) mAspectRatioX) / mAspectRatioY;
    }

}

//region: Private methods
@Override
protected void onSizeChanged(int w, int h, int oldw, int oldh) {
    super.onSizeChanged(w, h, oldw, oldh);
    // Initialize the crop window here because we need the size of the view
    // to have been determined.

    //my changes to update imageview height and width
    CropImageView.mImageView.getLayoutParams().height = h;
    CropImageView.mImageView.getLayoutParams().width = w;
    CropImageView.mImageView.requestLayout();
    CropImageView.mImageView.invalidate();


    initCropWindow(mBitmapRect);

   // CropImageView.mImageView.invalidate();
}

@Override
protected void onDraw(Canvas canvas) {

    super.onDraw(canvas);

    // Draw translucent background for the cropped area.
    drawBackground(canvas, mBitmapRect);


    if (showGuidelines()) {
        // Determines whether guidelines should be drawn or not
        if (mGuidelines == GUIDELINES_ON) {
            drawRuleOfThirdsGuidelines(canvas);
        } else if (mGuidelines == GUIDELINES_ON_TOUCH) {
            // Draw only when resizing
            if (mPressedHandle != null)
                drawRuleOfThirdsGuidelines(canvas);
        }
    }

    float w = mBorderPaint.getStrokeWidth();
    float l = Edge.LEFT.getCoordinate() + w;
    float t = Edge.TOP.getCoordinate() + w;
    float r = Edge.RIGHT.getCoordinate() - w;
    float b = Edge.BOTTOM.getCoordinate() - w;
    if (mCropShape == CropImageView.CropShape.RECTANGLE) {
        // Draw rectangle crop window border.
        canvas.drawRect(l, t, r, b, mBorderPaint);
        drawCorners(canvas);
    } else {
        // Draw circular crop window border
        mRectF.set(l, t, r, b);
        canvas.drawOval(mRectF, mBorderPaint);
    }
}

@Override
public boolean onTouchEvent(@SuppressWarnings("NullableProblems") 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:
            onActionDown(event.getX(), event.getY());
            return true;

        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;
    }
}

private void init(Context context) {

    DisplayMetrics displayMetrics = context.getResources().getDisplayMetrics();

    mHandleRadius = HandleUtil.getTargetRadius(context);

    mSnapRadius = TypedValue.applyDimension(TypedValue.COMPLEX_UNIT_DIP,
            SNAP_RADIUS_DP,
            displayMetrics);

    mBorderPaint = PaintUtil.newBorderPaint(context);
    mGuidelinePaint = PaintUtil.newGuidelinePaint();
    mBackgroundPaint = PaintUtil.newBackgroundPaint(context);
    mCornerPaint = PaintUtil.newCornerPaint(context);

    // Sets the values for the corner sizes
    mCornerOffset = TypedValue.applyDimension(TypedValue.COMPLEX_UNIT_DIP,
            DEFAULT_CORNER_OFFSET_DP,
            displayMetrics);
    mCornerExtension = TypedValue.applyDimension(TypedValue.COMPLEX_UNIT_DIP,
            DEFAULT_CORNER_EXTENSION_DP,
            displayMetrics);
    mCornerLength = TypedValue.applyDimension(TypedValue.COMPLEX_UNIT_DIP,
            DEFAULT_CORNER_LENGTH_DP,
            displayMetrics);

    // Sets guidelines to default until specified otherwise
    mGuidelines = CropImageView.DEFAULT_GUIDELINES;
}

/**
 * Set the initial crop window size and position. This is dependent on the
 * size and position of the image being cropped.
 *
 * @param bitmapRect the bounding box around the image being cropped
 */
private void initCropWindow(Rect bitmapRect) {

    if (bitmapRect.width() == 0 || bitmapRect.height() == 0) {
        return;
    }

    // Tells the attribute functions the crop window has already been
    // initialized
    if (!initializedCropWindow) {
        initializedCropWindow = true;
    }

    if (mFixAspectRatio
            && (bitmapRect.left != 0 || bitmapRect.right != 0
            || bitmapRect.top != 0 || bitmapRect.bottom != 0)) {

        // If the image aspect ratio is wider than the crop aspect ratio,
        // then the image height is the determining initial length. Else,
        // vice-versa.
        if (AspectRatioUtil.calculateAspectRatio(bitmapRect) > mTargetAspectRatio) {

            Edge.TOP.setCoordinate(bitmapRect.top);
            Edge.BOTTOM.setCoordinate(bitmapRect.bottom);

            final float centerX = getWidth() / 2f;

            //dirty fix for wrong crop overlay aspect ratio when using fixed aspect ratio
            mTargetAspectRatio = (float) mAspectRatioX / mAspectRatioY;

            // Limits the aspect ratio to no less than 40 wide or 40 tall
            final float cropWidth = Math.max(Edge.MIN_CROP_LENGTH_PX,
                    AspectRatioUtil.calculateWidth(Edge.TOP.getCoordinate(),
                            Edge.BOTTOM.getCoordinate(),
                            mTargetAspectRatio));

            // Create new TargetAspectRatio if the original one does not fit
            // the screen
            if (cropWidth == Edge.MIN_CROP_LENGTH_PX) {
                mTargetAspectRatio = (Edge.MIN_CROP_LENGTH_PX) / (Edge.BOTTOM.getCoordinate() - Edge.TOP.getCoordinate());
            }

            final float halfCropWidth = cropWidth / 2f;
            Edge.LEFT.setCoordinate(centerX - halfCropWidth);
            Edge.RIGHT.setCoordinate(centerX + halfCropWidth);

        } else {

            Edge.LEFT.setCoordinate(bitmapRect.left);
            Edge.RIGHT.setCoordinate(bitmapRect.right);

            final float centerY = getHeight() / 2f;

            // Limits the aspect ratio to no less than 40 wide or 40 tall
            final float cropHeight = Math.max(Edge.MIN_CROP_LENGTH_PX,
                    AspectRatioUtil.calculateHeight(Edge.LEFT.getCoordinate(),
                            Edge.RIGHT.getCoordinate(),
                            mTargetAspectRatio));

            // Create new TargetAspectRatio if the original one does not fit
            // the screen
            if (cropHeight == Edge.MIN_CROP_LENGTH_PX) {
                mTargetAspectRatio = (Edge.RIGHT.getCoordinate() - Edge.LEFT.getCoordinate()) / Edge.MIN_CROP_LENGTH_PX;
            }

            final float halfCropHeight = cropHeight / 2f;
            Edge.TOP.setCoordinate(centerY - halfCropHeight);
            Edge.BOTTOM.setCoordinate(centerY + halfCropHeight);
        }

    } else { // ... do not fix aspect ratio...

        // Initialize crop window to have 10% padding w/ respect to image.
        final float horizontalPadding = 0.1f * bitmapRect.width();
        final float verticalPadding = 0.1f * bitmapRect.height();

        Edge.LEFT.setCoordinate(bitmapRect.left + horizontalPadding);
        Edge.TOP.setCoordinate(bitmapRect.top + verticalPadding);
        Edge.RIGHT.setCoordinate(bitmapRect.right - horizontalPadding);
        Edge.BOTTOM.setCoordinate(bitmapRect.bottom - verticalPadding);
    }
}

/**
 * Indicates whether the crop window is small enough that the guidelines
 * should be shown. Public because this function is also used to determine
 * if the center handle should be focused.
 *
 * @return boolean Whether the guidelines should be shown or not
 */
public static boolean showGuidelines() {
    if ((Math.abs(Edge.LEFT.getCoordinate() - Edge.RIGHT.getCoordinate()) < DEFAULT_SHOW_GUIDELINES_LIMIT)
            || (Math.abs(Edge.TOP.getCoordinate() - Edge.BOTTOM.getCoordinate()) < DEFAULT_SHOW_GUIDELINES_LIMIT)) {
        return false;
    } else {
        return true;
    }
}

private void drawRuleOfThirdsGuidelines(Canvas canvas) {

    float w = mBorderPaint.getStrokeWidth();
    float l = Edge.LEFT.getCoordinate() + w;
    float t = Edge.TOP.getCoordinate() + w;
    float r = Edge.RIGHT.getCoordinate() - w;
    float b = Edge.BOTTOM.getCoordinate() - w;

    if (mCropShape == CropImageView.CropShape.OVAL) {
        l += 15 * mGuidelinePaint.getStrokeWidth();
        t += 15 * mGuidelinePaint.getStrokeWidth();
        r -= 15 * mGuidelinePaint.getStrokeWidth();
        b -= 15 * mGuidelinePaint.getStrokeWidth();
    }

    // Draw vertical guidelines.
    final float oneThirdCropWidth = Edge.getWidth() / 3;

    final float x1 = l + oneThirdCropWidth;
    canvas.drawLine(x1, t, x1, b, mGuidelinePaint);
    final float x2 = r - oneThirdCropWidth;
    canvas.drawLine(x2, t, x2, b, mGuidelinePaint);

    // Draw horizontal guidelines.
    final float oneThirdCropHeight = Edge.getHeight() / 3;

    final float y1 = t + oneThirdCropHeight;
    canvas.drawLine(l, y1, r, y1, mGuidelinePaint);
    final float y2 = b - oneThirdCropHeight;
    canvas.drawLine(l, y2, r, y2, mGuidelinePaint);
}

private void drawBackground(Canvas canvas, Rect bitmapRect) {

    final float l = Edge.LEFT.getCoordinate();
    final float t = Edge.TOP.getCoordinate();
    final float r = Edge.RIGHT.getCoordinate();
    final float b = Edge.BOTTOM.getCoordinate();

    if (mCropShape == CropImageView.CropShape.RECTANGLE) {
        canvas.drawRect(bitmapRect.left, bitmapRect.top, bitmapRect.right, t, mBackgroundPaint);
        canvas.drawRect(bitmapRect.left, b, bitmapRect.right, bitmapRect.bottom, mBackgroundPaint);
        canvas.drawRect(bitmapRect.left, t, l, b, mBackgroundPaint);
        canvas.drawRect(r, t, bitmapRect.right, b, mBackgroundPaint);
    } else {
        Path circleSelectionPath = new Path();
        mRectF.set(l, t, r, b);
        circleSelectionPath.addOval(mRectF, Path.Direction.CW);
        canvas.clipPath(circleSelectionPath, Region.Op.XOR);
        canvas.drawRect(bitmapRect.left, bitmapRect.top, bitmapRect.right, bitmapRect.bottom, mBackgroundPaint);
        canvas.restore();
    }
}

private void drawCorners(Canvas canvas) {

    float w = mBorderPaint.getStrokeWidth();
    final float l = Edge.LEFT.getCoordinate() + w;
    final float t = Edge.TOP.getCoordinate() + w;
    final float r = Edge.RIGHT.getCoordinate() - w;
    final float b = Edge.BOTTOM.getCoordinate() - w;

    // Top left
    canvas.drawLine(l - mCornerOffset, t - mCornerExtension, l - mCornerOffset, t + mCornerLength, mCornerPaint);
    canvas.drawLine(l, t - mCornerOffset, l + mCornerLength, t - mCornerOffset, mCornerPaint);

    // Top right
    canvas.drawLine(r + mCornerOffset, t - mCornerExtension, r + mCornerOffset, t + mCornerLength, mCornerPaint);
    canvas.drawLine(r, t - mCornerOffset, r - mCornerLength, t - mCornerOffset, mCornerPaint);

    // Bottom left
    canvas.drawLine(l - mCornerOffset, b + mCornerExtension, l - mCornerOffset, b - mCornerLength, mCornerPaint);
    canvas.drawLine(l, b + mCornerOffset, l + mCornerLength, b + mCornerOffset, mCornerPaint);

    // Bottom left
    canvas.drawLine(r + mCornerOffset, b + mCornerExtension, r + mCornerOffset, b - mCornerLength, mCornerPaint);
    canvas.drawLine(r, b + mCornerOffset, r - mCornerLength, b + mCornerOffset, mCornerPaint);
}

/**
 * Handles a {@link android.view.MotionEvent#ACTION_DOWN} event.
 *
 * @param x the x-coordinate of the down action
 * @param y the y-coordinate of the down action
 */
private void 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;
    }

    // Calculate the offset of the touch point from the precise location
    // of the handle. Save these values in a member variable since we want
    // to maintain this offset as we drag the handle.
    mTouchOffset = HandleUtil.getOffset(mPressedHandle, x, y, left, top, right, bottom);

    invalidate();
}

/**
 * Handles a {@link android.view.MotionEvent#ACTION_UP} or
 * {@link android.view.MotionEvent#ACTION_CANCEL} event.
 */
private void onActionUp() {

    if (mPressedHandle == null) {
        return;
    }

    mPressedHandle = null;

    invalidate();
}

/**
 * Handles a {@link android.view.MotionEvent#ACTION_MOVE} event.
 *
 * @param x the x-coordinate of the move event
 * @param y the y-coordinate of the move event
 */
private void onActionMove(float x, float y) {

    if (mPressedHandle == null) {
        return;
    }

    // Adjust the coordinates for the finger position's offset (i.e. the
    // distance from the initial touch to the precise handle location).
    // We want to maintain the initial touch's distance to the pressed
    // handle so that the crop window size does not "jump".
    x += mTouchOffset.first;
    y += mTouchOffset.second;

    // Calculate the new crop window size/position.
    if (mFixAspectRatio) {
        mPressedHandle.updateCropWindow(x, y, mTargetAspectRatio, mBitmapRect, mSnapRadius);
    } else {
        mPressedHandle.updateCropWindow(x, y, mBitmapRect, mSnapRadius);
    }
    invalidate();
}
//endregion
}

1 个答案:

答案 0 :(得分:0)

你可以尝试使用毕加索。将它放入Gradle构建后,它会在后台为您完成所有缩放。 Picasso