Make CropView handle images that aren't full-height

Compute the ImageView's extra top and bottom padding when it gets a
drawable or does layout, pass that information to CropView to adjust
its boundaries accordingly.

Also give MagnifierView some elevation so it doesn't get obscured by the
buttons.

Bug: 180967209
Test: Take a long screenshot at the top of the settings app, observe
    that the image isn't full height, ensure that crop handles properly
    honor image bounds and those bounds are honored on export as well.
Change-Id: Iac859995b362724a0db00b666a6ff970a0ccba1d
This commit is contained in:
Matt Casey
2021-02-24 15:30:47 -05:00
parent e4aa751de7
commit 37d6b6d53a
3 changed files with 56 additions and 7 deletions

View File

@@ -76,7 +76,6 @@
android:layout_height="wrap_content"
android:layout_marginBottom="42dp"
android:layout_marginHorizontal="48dp"
android:adjustViewBounds="true"
app:layout_constrainedHeight="true"
app:layout_constrainedWidth="true"
app:layout_constraintTop_toBottomOf="@id/guideline"
@@ -110,6 +109,7 @@
android:visibility="invisible"
android:layout_width="200dp"
android:layout_height="200dp"
android:elevation="2dp"
app:layout_constraintTop_toBottomOf="@id/guideline"
app:layout_constraintLeft_toLeftOf="parent"
app:handleThickness="@dimen/screenshot_crop_handle_thickness"

View File

@@ -65,6 +65,9 @@ public class CropView extends View {
private float mTopDelta = 0f;
private float mBottomDelta = 0f;
private int mExtraTopPadding;
private int mExtraBottomPadding;
private CropBoundary mCurrentDraggingBoundary = CropBoundary.NONE;
private float mStartingY; // y coordinate of ACTION_DOWN
private CropInteractionListener mCropInteractionListener;
@@ -117,12 +120,13 @@ public class CropView extends View {
if (mCurrentDraggingBoundary != CropBoundary.NONE) {
float delta = event.getY() - mStartingY;
if (mCurrentDraggingBoundary == CropBoundary.TOP) {
mTopDelta = pixelsToFraction((int) MathUtils.constrain(delta, -topPx,
mTopDelta = pixelDistanceToFraction((int) MathUtils.constrain(delta,
-topPx + mExtraTopPadding,
bottomPx - 2 * mCropTouchMargin - topPx));
} else { // Bottom
mBottomDelta = pixelsToFraction((int) MathUtils.constrain(delta,
mBottomDelta = pixelDistanceToFraction((int) MathUtils.constrain(delta,
topPx + 2 * mCropTouchMargin - bottomPx,
getHeight() - bottomPx));
getHeight() - bottomPx - mExtraBottomPadding));
}
updateListener(event);
invalidate();
@@ -194,6 +198,16 @@ public class CropView extends View {
animator.start();
}
/**
* Set additional top and bottom padding for the image being cropped (used when the
* corresponding ImageView doesn't take the full height).
*/
public void setExtraPadding(int top, int bottom) {
mExtraTopPadding = top;
mExtraBottomPadding = bottom;
invalidate();
}
/**
* @return value [0,1] representing the position of the top crop boundary. Does not reflect
* changes from any in-progress touch input.
@@ -244,12 +258,22 @@ public class CropView extends View {
true, mHandlePaint);
}
/**
* Convert the given fraction position to pixel position within the View.
*/
private int fractionToPixels(float frac) {
return (int) (frac * getHeight());
return (int) (mExtraTopPadding + frac * getImageHeight());
}
private float pixelsToFraction(int px) {
return px / (float) getHeight();
private int getImageHeight() {
return getHeight() - mExtraTopPadding - mExtraBottomPadding;
}
/**
* Convert the given pixel distance to fraction of the image.
*/
private float pixelDistanceToFraction(int px) {
return px / (float) getImageHeight();
}
private CropBoundary nearestBoundary(MotionEvent event, int topPx, int bottomPx) {

View File

@@ -157,6 +157,9 @@ public class LongScreenshotActivity extends Activity {
});
}
}
mPreview.addOnLayoutChangeListener(
(v, left, top, right, bottom, oldLeft, oldTop, oldRight, oldBottom) ->
updateCropLocation());
}
@Override
@@ -305,6 +308,27 @@ public class LongScreenshotActivity extends Activity {
}
}
private void updateCropLocation() {
Drawable drawable = mPreview.getDrawable();
if (drawable == null) {
return;
}
float imageRatio = drawable.getBounds().width() / (float) drawable.getBounds().height();
float viewRatio = mPreview.getWidth() / (float) mPreview.getHeight();
if (imageRatio > viewRatio) {
// Image is full width and height is constrained, compute extra padding to inform
// CropView
float imageHeight = mPreview.getHeight() * viewRatio / imageRatio;
int extraPadding = (int) (mPreview.getHeight() - imageHeight) / 2;
mCropView.setExtraPadding(extraPadding, extraPadding);
} else {
// Image is full height
mCropView.setExtraPadding(0, 0);
}
}
private void doCapture() {
mScrollCaptureController.start(mConnection,
new ScrollCaptureController.ScrollCaptureCallback() {
@@ -319,6 +343,7 @@ public class LongScreenshotActivity extends Activity {
Log.i(TAG, "Got tiles " + imageTileSet.getWidth() + " x "
+ imageTileSet.getHeight());
mPreview.setImageDrawable(imageTileSet.getDrawable());
updateCropLocation();
mMagnifierView.setDrawable(imageTileSet.getDrawable(),
imageTileSet.getWidth(), imageTileSet.getHeight());
mCropView.animateBoundaryTo(CropView.CropBoundary.BOTTOM, 0.5f);