5

I want to have fixed size box 120x180 dp that contains a picture with correct aspect ratio and a border painted around it.

XML:

<android.support.constraint.ConstraintLayout
android:layout_width="120dp"
android:layout_height="180dp"
app:layout_gravity="center">

<ImageView
    android:id="@+id/picture"
    android:layout_width="0dp"
    android:layout_height="0dp"
    android:background="@drawable/game_border"
    app:srcCompat="@drawable/pic_lion"
    android:scaleType="centerInside" />

Game_border layout:

<layer-list xmlns:android="http://schemas.android.com/apk/res/android" >
<item>
    <shape android:shape="rectangle" >
        <solid android:color="#55111111" />
        <padding
            android:bottom="4dp"
            android:left="4dp"
            android:right="4dp"
            android:top="4dp" />

        <corners android:radius="6dp" />
    </shape>
</item>
</layer-list>

This scaleType setting works fine because it fill complete tile inner and background is not overriden. But to demonstrate incorrect aspect ratio I have increased top margin. See picture below. I tried remaining values but they either paint over the border or do not fill complete inner part.

How can I have the tile that has the border around a part of the picture with the right aspect ratio? The picture can be cut. I think that this technique is called center crop. I found it in the Picasso library.

enter image description here

FitXY deforms picture:

Bad aspect

Manually painted picture when I cropped picture while preserving aspect ratio. Sorry, it looks ugly but bounty ends very soon.

enter image description here

Bjorn's answer:

enter image description here

Rahul answer does not have bottom border

enter image description here

Leos Literak
  • 8,805
  • 19
  • 81
  • 156
  • 1
    did you test `android:adjustViewBounds` with true value? – Shayan Pourvatan Jan 02 '17 at 19:02
  • I set it to true but it did not help. – Leos Literak Jan 02 '17 at 21:22
  • please see http://stackoverflow.com/questions/2521959/how-to-scale-an-image-in-imageview-to-keep-the-aspect-ratio – Shayan Pourvatan Jan 03 '17 at 06:12
  • I think I am looking for center crop. This picasso description looks to fit my need: CenterCrop() is a cropping technique that scales the image so that it fills the requested bounds of the ImageView and then crops the extra. The ImageView will be filled completely, but the entire image might not be displayed. – Leos Literak Jan 03 '17 at 18:30
  • @Leos Literak you want to set an image to a view with the exact aspect ratio. as an example if there is an image view with 50dp in top padding ..you need to show your image in the remaining space with the aspect ratio without stretched.. is that you want or something else? – Charuක Jan 08 '17 at 04:27
  • @LeosLiterak Can you put up your expected output beneath the images with a separate heading ? – Sreehari Jan 09 '17 at 12:26
  • @Leos Literak return home quickly then :D – Charuක Jan 09 '17 at 15:42

6 Answers6

5
<ImageView
android:id="@id/img"
android:layout_width="match_parent"
android:layout_height="match_parent"
android:adjustViewBounds="true"
android:scaleType="fitCenter" />

scaleType="fitCenter" (default when omitted)

  • will make it as wide as the parent allows and up/down-scale as needed keeping aspect ratio.

    scaleType="centerInside"

  • if the intrinsic width of src is smaller than parent width will center the image horizontally

  • f the intrinsic width of src is larger than parent width will make it as wide as the parent allows and down-scale keeping aspect ratio.

It doesn't matter if you use android:src or ImageView.setImage*.key is android:adjustViewBounds

Or Using the CardView also you can make rounded corners for imageView.

 <android.support.v7.widget.CardView 
    android:layout_width="120dp"
    android:layout_height="180dp"
    android:layout_gravity="center"
    android:layout_marginLeft="6dp"
    android:layout_marginRight="6dp"
    android:layout_marginTop="6dp"
    app:cardCornerRadius="@dimen/_5dp"
    app:cardBackgroundColor="#D3D3D3"
    app:cardPreventCornerOverlap="false"
    card_view:cardPreventCornerOverlap="false">

    <ImageView
        android:layout_width="match_parent"
        android:layout_height="match_parent"
        android:layout_margin="3dp"
        android:background="@drawable/image"
        android:scaleType="fitXY" />

</android.support.v7.widget.CardView>
Rahul Devanavar
  • 3,917
  • 4
  • 32
  • 61
2

Having rounded corner ImageView can be a bit of a painful task. What you can do use a library that supports both rounded corners and borders. For example

https://github.com/vinc3m1/RoundedImageView

If you understand what it does then you can easily create your own ImageView. The trick is to override the onDraw method of the ImageView and clip using paths. You can find some articles related to this topic.

Rishabh876
  • 3,010
  • 2
  • 20
  • 37
  • Cool. I worried that I cannot fix it in XML and I will have to implement it myself. So this would save me lots of work. Bu I am still waiting if somebody knows root source of this issue. – Leos Literak Jan 02 '17 at 21:08
2

You can use two separate ImageViews: one for the frame, and another one for the picture. That way you can use the ScaleType "centerCrop" on the picture ImageView, and resultant picture will always be in the desired aspect-ratio with a border around it.

Just make sure that the constraints on both ImageViews are set so that both ImageViews span the parent.

Code:

<android.support.constraint.ConstraintLayout
xmlns:android="http://schemas.android.com/apk/res/android"
xmlns:app="http://schemas.android.com/apk/res-auto"
xmlns:tools="http://schemas.android.com/tools"
android:layout_width="120dp"
android:layout_height="180dp">

<ImageView
    android:layout_width="0dp"
    android:layout_height="0dp"
    app:srcCompat="@drawable/game_border"
    android:id="@+id/frame"
    app:layout_constraintTop_toTopOf="parent"
    app:layout_constraintRight_toRightOf="parent"
    app:layout_constraintLeft_toLeftOf="parent"
    app:layout_constraintBottom_toBottomOf="parent"/>

<ImageView
    android:layout_width="0dp"
    android:layout_height="0dp"
    app:srcCompat="@drawable/lion"
    android:id="@+id/picture"
    android:scaleType="centerCrop"
    app:layout_constraintTop_toTopOf="parent"
    app:layout_constraintRight_toRightOf="parent"
    app:layout_constraintLeft_toLeftOf="parent"
    app:layout_constraintBottom_toBottomOf="parent"
    android:layout_marginTop="4dp"
    android:layout_marginStart="4dp"
    android:layout_marginLeft="4dp"
    android:layout_marginEnd="4dp"
    android:layout_marginRight="4dp"
    android:layout_marginBottom="4dp" />

Result: Picture_with_border

Jawad Hassan
  • 501
  • 3
  • 5
1

Since you are already using ConstraintLayout, there's this handy attribute app:layout_constraintDimensionRatio that let you specify aspect ratio dimensions. Here's layout code for the picture below.

<?xml version="1.0" encoding="utf-8"?>
<android.support.constraint.ConstraintLayout
    xmlns:android="http://schemas.android.com/apk/res/android"
    xmlns:app="http://schemas.android.com/apk/res-auto"
    android:layout_width="match_parent"
    android:layout_height="match_parent"
    >

  <ImageView
      android:id="@+id/picture"
      android:layout_width="120dp"
      android:layout_height="0dp"
      android:background="@drawable/game_border"
      android:scaleType="centerInside"
      app:layout_constraintBottom_toBottomOf="parent"
      app:layout_constraintDimensionRatio="h, 2:3"
      app:layout_constraintLeft_toLeftOf="parent"
      app:layout_constraintRight_toRightOf="parent"
      app:layout_constraintTop_toTopOf="parent"
      app:srcCompat="@drawable/vertical_deploy"
      />

</android.support.constraint.ConstraintLayout>

example

Alexander Perfilyev
  • 6,739
  • 2
  • 17
  • 30
1

Try this:

<LinearLayout
        android:layout_width="120dp"
        android:layout_height="180dp"
        android:background="@drawable/game_border">

        <ImageView
            android:id="@+id/picture"
            android:layout_width="match_parent"
            android:layout_height="match_parent"
            app:srcCompat="@drawable/pic_lion"
            android:scaleType="centerCrop" />

    </LinearLayout>

Hope will help you!

Jagruttam Panchal
  • 3,152
  • 2
  • 15
  • 21
1

Use a simple Framelayout for the background and use centerCrop for the ImageView:

<FrameLayout
    android:layout_width="120dp"
    android:layout_height="180dp"
    android:background="@drawable/background_with_rounded_corners"
    android:padding="4dp">

    <ImageView
        android:layout_width="match_parent"
        android:layout_height="match_parent"
        android:scaleType="centerCrop"/>
</FrameLayout>

And move the padding into the FrameLayout, so for your background resource file you only need color and corners:

<layer-list xmlns:android="http://schemas.android.com/apk/res/android">
    <item>
        <shape android:shape="rectangle">
            <solid android:color="#55111111" />
            <corners android:radius="6dp" />
        </shape>
    </item>
</layer-list>
Björn Kechel
  • 7,933
  • 3
  • 54
  • 57