Reputation: 21237
I'm trying to expand an ImageView
that sits inside a RelativeLayout
. I want the width to fill the parent while still maintaining the aspect ratio of the image. This sounds an awful lot like I could just use centerCrop in the XML layout file. The difference is that I do not want the image center-aligned. What I want is the image to be aligned to the top of the parent, with any excess on the bottom of the image to be cropped.
Here is the XML:
<RelativeLayout
android:background="#f00"
android:id="@+id/skyline_header"
android:layout_width="match_parent"
android:layout_height="0dp"
android:layout_weight="25">
<ImageView
android:id="@+id/bg_image"
android:layout_width="match_parent"
android:layout_height="match_parent"
android:src="@drawable/bg_img"/>
</RelativeLayout>
And here is my code:
final RelativeLayout headerContainer = (RelativeLayout) view.findViewById(R.id.skyline_header);
final ImageView iv = (ImageView) view.findViewById(R.id.bg_image);
ViewTreeObserver vto = headerContainer.getViewTreeObserver();
vto.addOnGlobalLayoutListener(new ViewTreeObserver.OnGlobalLayoutListener() {
@Override
public void onGlobalLayout() {
headerContainer.getViewTreeObserver().removeOnGlobalLayoutListener(this);
double imgAspectRatio = (double)iv.getMeasuredWidth() / (double)iv.getMeasuredHeight();
int screenWidth = getActivity().getResources().getDisplayMetrics().widthPixels;
Log.d("tag", Integer.toString(iv.getMeasuredWidth()));
Log.d("tag", Integer.toString(iv.getMeasuredHeight()));
Log.d("tag", Double.toString(imgAspectRatio));
Log.d("tag", Integer.toString(screenWidth));
int newHeight = (int) ((double)screenWidth * imgAspectRatio);
img.setLayoutParams(new RelativeLayout.Layout(screenWidth, newHeight));
img.requestLayout();
}
});
This code results in exactly what you would see if you just set scaleType="fitCenter"
. It fills the height of the container, centers the image, and leaves margins on the left and right.
The output is strange. It shows that the image view has the same width as the screen:
1440
562
2.5622775800711746
1440
Hopefully this will communicate conceptually what I have right now:
I want the picture to stretch to fill the entire horizontal space (no visible red remaining) without making the swimmer look really freakishly wide (i.e. keep the aspect ratio intact). The water underneath the swimmer can be cropped as needed to maintain the first two requirements.
Upvotes: 3
Views: 1585
Reputation: 3140
Well, fortunately android API provides another scaleType
: matrix
, So you are free to show parts of image you want, add these lines of code to onCreate
method of the Activity
:
final ImageView iv = (ImageView) findViewById(R.id.iv);
iv.getViewTreeObserver().addOnGlobalLayoutListener(new ViewTreeObserver.OnGlobalLayoutListener() {
@Override
public void onGlobalLayout() {
int viewWidth = iv.getMeasuredWidth();
int viewHeight = iv.getMeasuredHeight();
Drawable src = iv.getDrawable();
if (src != null) {
int srcWidth = src.getIntrinsicWidth();
int srcHeight = src.getIntrinsicHeight();
float wRatio = (float) viewWidth / srcWidth;
float hRatio = (float) viewHeight / srcHeight;
float scaleFactor = Math.max(wRatio, hRatio);
float hTranslate = (viewWidth - scaleFactor * srcWidth) / 2;
Matrix matrix = new Matrix();
matrix.setScale(scaleFactor, scaleFactor);
matrix.postTranslate(hTranslate, 0);
iv.setScaleType(ImageView.ScaleType.MATRIX);
iv.setImageMatrix(matrix);
Log.i("test", "srcWidth: " + srcWidth);
Log.i("test", "srcHeight: " + srcHeight);
Log.i("test", "viewWidth: " + viewWidth);
Log.i("test", "viewHeight: " + viewHeight);
Log.i("test", "wRatio: " + wRatio);
Log.i("test", "hRatio: " + hRatio);
Log.i("test", "scaleFactor: " + scaleFactor);
Log.i("test", "hTranslate: " + hTranslate);
}
iv.getViewTreeObserver().removeOnGlobalLayoutListener(this);
}
});
first you register an OnGlobalLayoutListener
so you will access the dimension of the view in the right time (I believe you already know it), then you compute wRatio
(width ratio) and hRatio
(height ratio) using provided parameters and choose the bigger one as the scaleFactor
(so you make sure that drawable
covers whole of the view), Also you need to align drawable
center horizontally (that's the role hTranslate
plays), finally create the matrix and we're there!
Original image :
centerCrop result:
topCrop result (what we did by code)
Upvotes: 3