1

I'm building an Android application and am now designing the user profile activity.

It is supposed to display the profile picture at the top in a rectangle container that looks like a banner.

<ImageView
android:id="@+id/user_pic"
android:layout_width="match_parent"
android:layout_height="match_parent"
android:scaleType="fitCenter"
android:adjustViewBounds="true"
android:background="@android:color/transparent"
android:layout_centerHorizontal="true"
android:elevation="2dp"/>

This XML code works well if the image is a 1x1 ratio or if the height is bigger than the width. (I display a blurry and stretched version of the same image in background so it's not completely ugly).

The problem I hit is when the WIDTH is bigger than the HEIGHT. It tries to scale the height (in my case to 300dp) but then the width hits the borders of the layout and it stops resizing, leaving me with an empty space under the image.

I know that the scaleType="centerCrop" does pretty much what I'm looking for, but if the ratio of the image is 1x1 it's cropping the top part of the image (most of the time the hairs) of the person, which I don't want.

So basically, is there a way in XML, or in JAVA, to resize the height of an image to fill my container while keeping the width ratio and ignoring the max width of the parent layout ? (I imagine it's supposed to crop what would overflow just like "centerCrop" would).

Here is an image of what I'm currently acheiving and the problem occuring. The grey part is a blurry and resized version of the same Image, so it doesn't look too ugly when the image can't fill the width (for example, in a 1x1 ratio picture). https://i.stack.imgur.com/FUDcP.png

Beerbossa
  • 110
  • 1
  • 8
  • I would like the width to be cropped a little if necessary to make sure that the height is always matching the container's height, but I'm pretty sure it cannot be done in XML only since only centerCrop seems to give me this feature. CenterCropWidth would be an amazing scaleType ! – Beerbossa Nov 09 '16 at 05:21
  • https://developer.android.com/reference/android/widget/ImageView.ScaleType.html there are 8 scale types mentioned in this link, try all, if none worked, then you have to crop the image programatically and set to `ImageView` – Mohammed Atif Nov 09 '16 at 05:23

3 Answers3

0

I am not getting you properly, but you want keep the aspect ratio of Image, you should match_parent to android:height and try to wrap_content the width of ImageView. Try to fitCenter as android:scaleType.

Try the code bellow -

<ImageView
        android:id="@+id/user_pic"
        android:layout_width="wrap_content"
        android:layout_height="match_parent"
        android:scaleType="fitCenter"
        android:adjustViewBounds="true"
        android:background="@android:color/transparent"/>
Akshay
  • 1,702
  • 1
  • 9
  • 16
  • Yeah this is basically the best that I could accomplish in pure XML, but the problem with this solution occurs if your image has a larger width and a smaller height. It's going to try to match the parent's height, but won't be able to once the width of the image hits the left and right borders of the parent layout. If you look at the image I posted in my original post, this is pretty much the result it gives. – Beerbossa Nov 09 '16 at 05:55
  • Then you should create a Custom view and extend with ImageView, and change onMeasure method according to your need. Please also make a try to set android:layout_width to "wrap_content". – Akshay Nov 09 '16 at 06:00
0

The answer was found at this link.

Basically, the trick used is to make a custom ImageView class in Java, then use it. It will calculate the correct area to crop, if necessary, depending of the situation.

If anyone finds a pure XML solution, feel free to tell me !

Without any further wait, here is the code I used.

JAVA CLASS

public class FitYCropXImageView extends ImageView {
    boolean done = false;

    @SuppressWarnings("UnusedDeclaration")
    public FitYCropXImageView(Context context) {
        super(context);
        setScaleType(ScaleType.MATRIX);
    }

    @SuppressWarnings("UnusedDeclaration")
    public FitYCropXImageView(Context context, AttributeSet attrs) {
        super(context, attrs);
        setScaleType(ScaleType.MATRIX);
    }

    @SuppressWarnings("UnusedDeclaration")
    public FitYCropXImageView(Context context, AttributeSet attrs, int defStyle) {
        super(context, attrs, defStyle);
        setScaleType(ScaleType.MATRIX);
    }

    private final RectF drawableRect = new RectF(0, 0, 0,0);
    private final RectF viewRect = new RectF(0, 0, 0,0);
    private final Matrix m = new Matrix();
    @Override
    protected void onMeasure(int widthMeasureSpec, int heightMeasureSpec) {
        super.onMeasure(widthMeasureSpec, heightMeasureSpec);
        if (done) {
            return;//Already fixed drawable scale
        }
        final Drawable d = getDrawable();
        if (d == null) {
            return;//No drawable to correct for
        }
        int viewHeight = getMeasuredHeight();
        int viewWidth = getMeasuredWidth();
        int drawableWidth = d.getIntrinsicWidth();
        int drawableHeight = d.getIntrinsicHeight();
        drawableRect.set(0, 0, drawableWidth, drawableHeight);//Represents the original image
        //Compute the left and right bounds for the scaled image
        float viewHalfWidth = viewWidth / 2;
        float scale = (float) viewHeight / (float) drawableHeight;
        float scaledWidth = drawableWidth * scale;
        float scaledHalfWidth = scaledWidth / 2;
        viewRect.set(viewHalfWidth - scaledHalfWidth, 0, viewHalfWidth + scaledHalfWidth, viewHeight);

        m.setRectToRect(drawableRect, viewRect, Matrix.ScaleToFit.CENTER /* This constant doesn't matter? */);
        setImageMatrix(m);

        done = true;

        requestLayout();
    }
}

XML

<com.app.YourAppName.YourAppName.CustomViews.FitYCropXImageView
                        android:id="@+id/user_pic"
                        android:layout_width="match_parent"
                        android:layout_height="match_parent"
                        android:background="@android:color/transparent"
                        android:elevation="2dp"
                        />

JAVA ACTIVITY IF NECESSARY

import com.app.YourAppName.YourAppName.CustomViews.FitYCropXImageView;

FitYCropXImageView profilePic = (FitYCropXImageView) findViewById(R.id.user_pic);
Community
  • 1
  • 1
Beerbossa
  • 110
  • 1
  • 8
0

If your ImageView width is match_parent and Your Original Image size is 300x400

and also assume that Deice's WIDTH_PIXEL 1080 and HEIGHT_PIXEL 1920

Your ImageView need to be 1080x1440(3:4)

You can use like below.

public static final int WIDTH_PIXEL = Resources.getSystem().getDisplayMetrics().widthPixels;
public static final int HEIGHT_PIXEL = Resources.getSystem().getDisplayMetrics().heightPixels;

//ratioX : ratioY = givenX : X
public static int getRatio(int ratioX, int ratioY, int givenX) {
    int result = (int) ((((float) ratioY * (float) givenX) / (float) ratioX) + 0.5f);
    //Log.v(TAG, "Request -> " + ratioX + " : " + ratioY + " = " + givenX + " : " + result);
    return result;
}


{//Usage
   int width = 300;
   int height = 400;

   int resultHeight = getRatio(width, height , WIDTH_PIXEL);
   myImageVIew.getLayoutParams().height = resultHeight ;
}


<ImageView  
    android:layout_width="match_parent"
    android:layout_height="wrap_content"/>    

I hope it can be a hint for you.

Soo Chun Jung
  • 595
  • 3
  • 14