Files
tubestation/mobile/android/base/widget/CropImageView.java

144 lines
5.1 KiB
Java

/* -*- Mode: Java; c-basic-offset: 4; tab-width: 20; indent-tabs-mode: nil; -*-
* This Source Code Form is subject to the terms of the Mozilla Public
* License, v. 2.0. If a copy of the MPL was not distributed with this
* file, You can obtain one at http://mozilla.org/MPL/2.0/. */
package org.mozilla.gecko.widget;
import android.content.Context;
import android.graphics.Bitmap;
import android.graphics.Matrix;
import android.graphics.drawable.Drawable;
import android.util.AttributeSet;
import android.widget.ImageView;
import com.nineoldandroids.view.ViewHelper;
import org.mozilla.gecko.widget.themed.ThemedImageView;
/**
* An ImageView which will always display at the given width and calculated height (based on the width and
* the supplied aspect ratio), drawn starting from the top left hand corner. A supplied drawable will be resized to fit
* the width of the view; if the resized drawable is too tall for the view then the drawable will be cropped at the
* bottom, however if the resized drawable is too short for the view to display whilst honouring it's given width and
* height then the drawable will be displayed at full height with the right hand side cropped.
*/
public abstract class CropImageView extends ThemedImageView {
public static final String LOGTAG = "Gecko" + CropImageView.class.getSimpleName();
private int viewWidth;
private int viewHeight;
private int drawableWidth;
private int drawableHeight;
private boolean resize = true;
private Matrix layoutCurrentMatrix = new Matrix();
private Matrix layoutNextMatrix = new Matrix();
public CropImageView(final Context context) {
this(context, null);
}
public CropImageView(final Context context, final AttributeSet attrs) {
this(context, attrs, 0);
}
public CropImageView(final Context context, final AttributeSet attrs, final int defStyleAttr) {
super(context, attrs, defStyleAttr);
init();
}
protected abstract float getAspectRatio();
protected void init() {
// Setting the pivots means that the image will be drawn from the top left hand corner. There are
// issues in Android 4.1 (16) which mean setting these values to 0 may not work.
// http://stackoverflow.com/questions/26658124/setpivotx-doesnt-work-on-android-4-1-1-nineoldandroids
ViewHelper.setPivotX(this, 1);
ViewHelper.setPivotY(this, 1);
}
/**
* Measure the view to determine the measured width and height.
* The height is constrained by the measured width.
*
* @param widthMeasureSpec horizontal space requirements as imposed by the parent.
* @param heightMeasureSpec vertical space requirements as imposed by the parent, but ignored.
*/
@Override
protected void onMeasure(final int widthMeasureSpec, final int heightMeasureSpec) {
// Default measuring.
super.onMeasure(widthMeasureSpec, heightMeasureSpec);
// Force the height based on the aspect ratio.
viewWidth = getMeasuredWidth();
viewHeight = (int) (viewWidth * getAspectRatio());
setMeasuredDimension(viewWidth, viewHeight);
updateImageMatrix();
}
protected void updateImageMatrix() {
if (!resize || getDrawable() == null) {
return;
}
setScaleType(ImageView.ScaleType.MATRIX);
getDrawable().setBounds(0, 0, viewWidth, viewHeight);
final float horizontalScaleValue = (float) viewWidth / (float) drawableWidth;
final float verticalScaleValue = (float) viewHeight / (float) drawableHeight;
final float scale = Math.max(verticalScaleValue, horizontalScaleValue);
layoutNextMatrix.setScale(scale, scale);
setImageMatrix(layoutNextMatrix);
// You can't modify the matrix in place and we want to avoid allocation, so let's keep two references to two
// different matrix objects that we can swap when the values need to change
final Matrix swapReferenceMatrix = layoutCurrentMatrix;
layoutCurrentMatrix = layoutNextMatrix;
layoutNextMatrix = swapReferenceMatrix;
}
public void setImageBitmap(final Bitmap bm, final boolean resize) {
super.setImageBitmap(bm);
this.resize = resize;
updateImageMatrix();
}
@Override
public void setImageResource(final int resId) {
super.setImageResource(resId);
setImageMatrix(null);
resize = false;
}
@Override
public void setImageDrawable(final Drawable drawable) {
this.setImageDrawable(drawable, false);
}
public void setImageDrawable(final Drawable drawable, final boolean resize) {
super.setImageDrawable(drawable);
if (drawable != null) {
// Reset the matrix to ensure that any previous changes aren't carried through.
setImageMatrix(null);
drawableWidth = drawable.getIntrinsicWidth();
drawableHeight = drawable.getIntrinsicHeight();
} else {
drawableWidth = -1;
drawableHeight = -1;
}
this.resize = resize;
updateImageMatrix();
}
}