Crop image to square - Android - android

How can I cut rectangular image (600 x 300) from left and right to fit in square ImageView ? I don't want to resize image, I just want to crop it, to be 300 x 300.
[SOLUTION]
As #blackbelt said
Bitmap cropImg = Bitmap.createBitmap(src, startX, startY, dstWidth, dstHeight);
is great for cropping images. So how can you automatically crop images with different sizes. I create this simple code for that:
// From drawable
Bitmap src= BitmapFactory.decodeResource(context.getResources(), R.drawable.image);
// From URL
Bitmap src = null;
try {
String URL = "http://www.example.com/image.jpg";
InputStream in = new java.net.URL(URL).openStream();
src = BitmapFactory.decodeStream(in);
} catch (Exception e) {
e.printStackTrace();
}
int width = src.getWidth();
int height = src.getHeight();
int crop = (width - height) / 2;
Bitmap cropImg = Bitmap.createBitmap(src, crop, 0, height, height);
ImageView.setImageBitmap(cropImg);

Expanding a little on the answer above
Since in some situations you can end up with an exception or not the expected result, just by using the Bitmap.createBitmap(), like the fallowing:
java.lang.IllegalArgumentException: x + width must be <=
bitmap.width()
Heres is a small function that does the crop and handle some of the commons cases.
Edit: updated accordantly to droidster's claim.
public static Bitmap cropToSquare(Bitmap bitmap){
int width = bitmap.getWidth();
int height = bitmap.getHeight();
int newWidth = (height > width) ? width : height;
int newHeight = (height > width)? height - ( height - width) : height;
int cropW = (width - height) / 2;
cropW = (cropW < 0)? 0: cropW;
int cropH = (height - width) / 2;
cropH = (cropH < 0)? 0: cropH;
Bitmap cropImg = Bitmap.createBitmap(bitmap, cropW, cropH, newWidth, newHeight);
return cropImg;
}
I did several testing with some images of different resolutions and sizes and it work as expected.
It can also be used in other situations, for example when you are trying to make a "perfectly" round image and need to pass a squarish bitmap, etc.

set fixed image view height, width, and set two properties to image view
android:adjustViewBounds="true"
android:scaleType="centerCrop"
done

You can use
Bitmap dst = Bitmap.createBitmap(src, startX, startY, dstWidth, dstHeight);
from the documentation:
Returns an immutable bitmap from the specified subset of the source
bitmap. The new bitmap may be the same object as source, or a copy may
have been made. It is initialized with the same density as the
original bitmap.
Here you can find the documentation

Now xml is having properties like
custom:cropAspectRatioX="2"
custom:cropAspectRatioY="1"
Make both 1 if u want square cropping. now it is of rectangle
Add activity CropActivity
package agropost.post.agro.com.agropost.Activity;
import android.content.Intent;
import android.graphics.Bitmap;
import android.graphics.BitmapFactory;
import android.os.Bundle;
import android.support.v7.app.AppCompatActivity;
import android.util.DisplayMetrics;
import android.widget.Button;
import com.theartofdev.edmodo.cropper.CropImageView;
import agropost.post.agro.com.agropost.R;
import agropost.post.agro.com.agropost.Utility.Constants;
import butterknife.BindView;
import butterknife.ButterKnife;
import butterknife.OnClick;
public class CropActivity extends AppCompatActivity {
public static boolean isCrop = false;
#BindView(R.id.img_crop)
CropImageView imgCrop;
#BindView(R.id.btn_done)
Button btnDone;
#BindView(R.id.btn_cancel)
Button btnCancel;
#Override
protected void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
setContentView(R.layout.activity_crop);
ButterKnife.bind(this);
DisplayMetrics displayMetrics = new DisplayMetrics();
getWindowManager().getDefaultDisplay().getMetrics(displayMetrics);
int width = displayMetrics.widthPixels;
width = width - 80;
imgCrop.getLayoutParams().height = width;
imgCrop.getLayoutParams().width = width;
imgCrop.setBackground(null);
imgCrop.setScaleType(CropImageView.ScaleType.FIT_CENTER);
imgCrop.setImageBitmap(Constants.mDashboardActivity.thumbnail_r);
}
#OnClick(R.id.btn_done)
public void onViewClicked() {
isCrop = true;
Intent returnIntent = new Intent();
Constants.mDashboardActivity.thumbnail_r = imgCrop.getCroppedImage();
setResult(3, returnIntent);
finish();
}
#OnClick(R.id.btn_cancel)
public void onViewClickedCancel() {
byte[] byteArray = getIntent().getByteArrayExtra("default");
Bitmap bmp = BitmapFactory.decodeByteArray(byteArray, 0, byteArray.length);
Constants.mDashboardActivity.thumbnail_r = bmp;
isCrop = true;
Intent returnIntent = new Intent();
setResult(3, returnIntent);
finish();
}
#Override
public void onBackPressed() {
// super.onBackPressed();
}
}
xml of activity..............
<?xml version="1.0" encoding="utf-8"?>
<LinearLayout 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="match_parent"
android:layout_height="match_parent"
android:background="#color/transparent"
android:gravity="center"
android:orientation="vertical"
tools:context=".Activity.CropActivity">
<com.theartofdev.edmodo.cropper.CropImageView xmlns:custom="http://schemas.android.com/apk/res-auto"
android:id="#+id/img_crop"
android:layout_width="100dp"
android:layout_height="100dp"
android:background="#drawable/drawer_bg"
android:scaleType="centerInside"
custom:cropAspectRatioX="2"
custom:cropAspectRatioY="1"
custom:cropFixAspectRatio="true"
custom:cropShape="rectangle" />
<LinearLayout
android:layout_width="match_parent"
android:layout_height="wrap_content"
android:orientation="horizontal">
<Button
android:id="#+id/btn_done"
android:layout_width="match_parent"
android:layout_height="60dp"
android:layout_marginLeft="#dimen/margin_40"
android:layout_marginRight="#dimen/margin_20"
android:layout_marginTop="#dimen/margin_20"
android:layout_weight="1"
android:background="#drawable/btn_bg_green_rounded"
android:text="Done"
android:textColor="#color/colorWhite"
android:textSize="#dimen/fontsize_normal" />
<Button
android:id="#+id/btn_cancel"
android:layout_width="match_parent"
android:layout_height="60dp"
android:layout_marginLeft="#dimen/margin_20"
android:layout_marginRight="#dimen/margin_40"
android:layout_marginTop="#dimen/margin_20"
android:layout_weight="1"
android:background="#drawable/btn_bg_green_rounded"
android:text="Cancel"
android:textColor="#color/colorWhite"
android:textSize="#dimen/fontsize_normal"
android:visibility="gone" />
</LinearLayout>
</LinearLayout>
add dependecy
implementation 'com.theartofdev.edmodo:android-image-cropper:2.4.+'

Related

How to create circular facebook profile picture

I'm having trouble using this library to make one of my images into a circle dynamically. Here is my attempt:
private void drawerSetup() {
Profile profile = Profile.getCurrentProfile();
ProfilePictureView profilePictureView = (ProfilePictureView) findViewById(R.id.profile_image);
CircularImageView circularProfilePicture = (CircularImageView) findViewById(R.id.profile_image_circle);
if(profilePictureView != null) {
profilePictureView.setProfileId(profile.getId());
ImageView imageView = ((ImageView)profilePictureView.getChildAt(0));
Bitmap bitmap = ((BitmapDrawable)imageView.getDrawable()).getBitmap();
circularProfilePicture.setImageBitmap(bitmap);
}
}
Layout:
<?xml version="1.0" encoding="utf-8"?>
<RelativeLayout xmlns:android="http://schemas.android.com/apk/res/android"
android:layout_width="match_parent"
android:layout_height="200dp"
xmlns:facebook="http://schemas.android.com/apk/res-auto"
xmlns:app="http://schemas.android.com/tools"
android:background="#drawable/side_nav_bar"
android:paddingLeft="#dimen/activity_horizontal_margin"
android:paddingRight="#dimen/activity_horizontal_margin"
android:paddingBottom="#dimen/activity_vertical_margin"
android:paddingTop="#dimen/activity_vertical_margin"
android:theme="#style/ThemeOverlay.AppCompat.Dark"
android:orientation="vertical"
android:gravity="bottom"
app:showIn="#layout/activity_news_feed">
<com.facebook.login.widget.ProfilePictureView
android:id="#+id/profile_image"
android:layout_width="wrap_content"
android:layout_height="wrap_content"
facebook:com_facebook_preset_size="normal"
android:layout_centerHorizontal="true"
android:layout_centerVertical="true"
android:paddingBottom="8dp"
android:layout_centerInParent="true" />
<com.mikhaellopez.circularimageview.CircularImageView
android:layout_width="100dp"
android:layout_height="100dp"
app:border_color="#EEEEEE"
app:border_width="2dp"
app:shadow="true"
app:shadow_radius="10"
android:id="#+id/profile_image_circle"
app:shadow_color="#000000"
android:layout_alignBottom="#+id/profile_image"
android:layout_toLeftOf="#+id/profile_image"
android:layout_toStartOf="#+id/profile_image" />
I know that my profilePictureView is displaying correctly when i call profilePictureView.setProfileId(profile.getId()); On my layout, it displays correctly. However, when I try to call the circularProfilePicture, I simply get an "empty" photo. It doesn't seem like the bitmap for the image isn't being recognized/set correctly. The image doesn't display as the profilePictureView does. Any ideas why this might happen?
After using different image library (including Picasso), I finished to use Facebook one named Fresco. It's much faster with less code, everyting works as it should.
Fresco support:
streaming of progressive JPEGs
display of animated GIFs and WebPs
extensive customization of image loading and display
The doc says too that
In Android 4.x and lower, Fresco puts images in a special region of Android memory. This lets your application run faster - and suffer the dreaded OutOfMemoryError much less often.
It also support rounded corner as you are searching, see here.
Layout example:
<com.facebook.drawee.view.SimpleDraweeView
android:id="#+id/avatarImageView"
android:layout_width="50dp"
android:layout_height="50dp"
fresco:placeholderImageScaleType="centerCrop"
fresco:placeholderImage="#drawable/photo_placeholder"
fresco:roundAsCircle="true"/>
Note: don't forget to call Fresco.initialize(this); somewhere (normally in your Application class).
I should also notice that Fresco currently add 2.6Mb to your application using ProGuard. You may choose to use another library such as Glide if you want less functionality.
I can't help but notice most answers asking you to use 2 libraries, 1 for loading the Image and 2nd for displaying it. Your goal as a developer should always be to get your task done with the minimum number of libraries and here is a solution that only needs 1 library. I will use Glide here since it caches the images exactly for the size you need. I haven't used Fresco so cannot comment on it but HERE's something on Picasso vs. Glide
Step 1
Create your layout
<?xml version="1.0" encoding="utf-8"?>
<RelativeLayout xmlns:android="http://schemas.android.com/apk/res/android"
android:layout_width="match_parent"
android:layout_height="#dimen/nav_header_height"
android:paddingBottom="#dimen/activity_vertical_margin"
android:paddingLeft="#dimen/activity_horizontal_margin"
android:paddingRight="#dimen/activity_horizontal_margin"
android:paddingTop="#dimen/activity_vertical_margin"
android:theme="#style/ThemeOverlay.AppCompat.Dark">
<LinearLayout
android:layout_width="match_parent"
android:layout_height="wrap_content"
android:layout_centerInParent="true"
android:gravity="center"
android:orientation="vertical">
<ImageView
android:id="#+id/image_profile"
android:layout_width="#dimen/profile_picture_size"
android:layout_height="#dimen/profile_picture_size"
android:background="#drawable/image_circle"
android:paddingTop="#dimen/nav_header_vertical_spacing"
android:src="#drawable/com_facebook_profile_picture_blank_square" />
<TextView
android:id="#+id/text_username"
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:paddingTop="#dimen/nav_header_vertical_spacing"
android:text="#string/placeholder_name"
android:textAppearance="#style/TextAppearance.AppCompat.Body1"
android:textColor="#color/colorTextPrimary" />
</LinearLayout>
</RelativeLayout>
This is what my Layout looks like, notice I used a plain simple ImageView instead of a fancy library. Feel free to adjust it to match your needs.
Step 2
Write a custom transform to convert a square image into a Circle Image. Glide uses something called Transformations to let you manipulate images according to what you need. Read THIS post for what transformations are and read THIS post to play with some custom transformations. In our case our transformation class looks like this.
import android.content.Context;
import android.graphics.Bitmap;
import android.graphics.BitmapShader;
import android.graphics.Canvas;
import android.graphics.Matrix;
import android.graphics.Paint;
import com.bumptech.glide.Glide;
import com.bumptech.glide.load.Transformation;
import com.bumptech.glide.load.engine.Resource;
import com.bumptech.glide.load.engine.bitmap_recycle.BitmapPool;
import com.bumptech.glide.load.resource.bitmap.BitmapResource;
public class CropCircleTransform implements Transformation<Bitmap> {
private BitmapPool mBitmapPool;
public CropCircleTransform(Context context) {
this(Glide.get(context).getBitmapPool());
}
public CropCircleTransform(BitmapPool pool) {
this.mBitmapPool = pool;
}
#Override
public Resource<Bitmap> transform(Resource<Bitmap> resource, int outWidth, int outHeight) {
Bitmap source = resource.get();
int size = Math.min(source.getWidth(), source.getHeight());
int width = (source.getWidth() - size) / 2;
int height = (source.getHeight() - size) / 2;
Bitmap bitmap = mBitmapPool.get(size, size, Bitmap.Config.ARGB_8888);
if (bitmap == null) {
bitmap = Bitmap.createBitmap(size, size, Bitmap.Config.ARGB_8888);
}
Canvas canvas = new Canvas(bitmap);
Paint paint = new Paint();
BitmapShader shader =
new BitmapShader(source, BitmapShader.TileMode.CLAMP, BitmapShader.TileMode.CLAMP);
if (width != 0 || height != 0) {
// source isn't square, move viewport to center
Matrix matrix = new Matrix();
matrix.setTranslate(-width, -height);
shader.setLocalMatrix(matrix);
}
paint.setShader(shader);
paint.setAntiAlias(true);
float r = size / 2f;
canvas.drawCircle(r, r, r, paint);
return BitmapResource.obtain(bitmap, mBitmapPool);
}
#Override public String getId() {
return "CropCircleTransform()";
}
}
Step 3
Load the picture into this layout using Glide. Admin is an object that contains details such as name, email, profile picture url etc, mDrawer is a reference to the NavigationView. Notice how Glide uses the transformation defined in step 2 to achieve the circular image effect.
public void addHeaderToDrawer(#NonNull Admin admin) {
View headerView = mDrawer.inflateHeaderView(R.layout.nav_header_main);
TextView textUserName = (TextView) headerView.findViewById(R.id.text_username);
ImageView imageProfile = (ImageView) headerView.findViewById(R.id.image_profile);
textUserName.setText(admin.getName());
Glide.with(mContext)
.load(admin.getUrl())
.asBitmap()
.transform(new CropCircleTransform(mContext))
.into(imageProfile);
}
Step 4
Sit back and enjoy the show. I am also loading the data from Facebook, let me know if you are still facing any issues :)
I achieve this through using PICASSO library.
No need to use CircularImageView
Here is my code:
Target target = new Target() {
#Override
public void onPrepareLoad(Drawable arg0) {
// Toast.makeText(FragmentChatView.this, "message",
// Toast.LENGTH_LONG).show();
}
#Override
public void onBitmapLoaded(Bitmap bitmap, Picasso.LoadedFrom arg1) {
bitmap = Bitmap.createScaledBitmap(bitmap, 40, 40, false);
final Drawable drawImage = new BitmapDrawable(BaseActivity.this
.getBaseContext().getResources(), bitmap);
// ((MaterialNavigationDrawer<Fragment>)
// FragmentChatView.this).getToolbar().setLogo(drawImage);
if (iv_logo != null)
iv_logo.setImageDrawable(drawImage);
}
#Override
public void onBitmapFailed(Drawable arg0) {
}
};
public class CircleTransform implements Transformation {
#Override
public Bitmap transform(Bitmap source) {
int size = Math.min(source.getWidth(), source.getHeight());
int x = (source.getWidth() - size) / 2;
int y = (source.getHeight() - size) / 2;
Bitmap squaredBitmap = Bitmap
.createBitmap(source, x, y, size, size);
if (squaredBitmap != source) {
source.recycle();
}
Bitmap bitmap = Bitmap.createBitmap(size, size, source.getConfig());
Canvas canvas = new Canvas(bitmap);
Paint paint = new Paint();
BitmapShader shader = new BitmapShader(squaredBitmap,
BitmapShader.TileMode.CLAMP, BitmapShader.TileMode.CLAMP);
paint.setShader(shader);
paint.setAntiAlias(true);
float r = size / 2f;
canvas.drawCircle(r, r, r, paint);
squaredBitmap.recycle();
return bitmap;
}
#Override
public String key() {
return "circle";
}
}
Hope it will work for you.
Try this library: https://github.com/hdodenhof/CircleImageView. I've tried several alternatives, and this one was the lucky winner.
try this
<ImageView
android:layout_width="150dp"
android:layout_height="150dp"
android:background="#drawable/shape"
android:src="#drawable/User"
android:id="#+id/imageView2" />
shape.xml
<?xml version="1.0" encoding="utf-8"?>
<shape xmlns:android="http://schemas.android.com/apk/res/android"
android:shape="oval">
<gradient
android:angle="0"
android:centerColor="#ffffff"
android:centerX="35%"
android:endColor="#ffffff"
android:startColor="#ffffff"
android:type="linear" />
<padding
android:bottom="20dp"
android:left="20dp"
android:right="20dp"
android:top="20dp" />
<size
android:width="150dp"
android:height="150dp" />
<stroke
android:width="5dp"
android:color="#color/allThemeBlue" />
</shape>
out put

Get width of CardView in Adapter.onBindViewHolder

I have a list of posts and most of them are pictures (simply put it is posts just like G+ or FB apps). Each post entry has an image aspect ratio, so I can set image height based on it's width even before image was loaded from server, so card layout wouldn't change on load.
The problem is layout_width="match_parent" set for both card and post image. When I get width of cardview it is zero. So i can't calculate height.
For now the only solution I see is to take width of parent container (RecyclerView) and deduct all paddings, but it doesn't look like a good solution.
Is there any other way to do it?
Here is an example of adapter code
#Override
public void onBindViewHolder(ViewHolder holder, int position) {
....
int width = holder.itemView.getWidth();
....
//do some calculations
}
Layouts (without irrelevant parts)
<?xml version="1.0" encoding="utf-8"?>
<android.support.v7.widget.CardView xmlns:android="http://schemas.android.com/apk/res/android"
xmlns:card_view="http://schemas.android.com/apk/res-auto"
android:id="#+id/card"
android:layout_width="match_parent"
android:layout_height="match_parent"
android:descendantFocusability="blocksDescendants"
android:foreground="?android:attr/selectableItemBackground"
card_view:cardBackgroundColor="#ffffff"
card_view:cardCornerRadius="3dp">
<RelativeLayout xmlns:android="http://schemas.android.com/apk/res/android"
android:layout_width="match_parent"
android:layout_height="wrap_content">
<include
android:id="#+id/includedPost"
layout="#layout/post_details" />
</RelativeLayout>
</android.support.v7.widget.CardView>
includedPost:
<?xml version="1.0" encoding="utf-8"?>
<RelativeLayout 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="wrap_content">
<ImageView
android:id="#+id/postImage"
android:layout_width="match_parent"
android:layout_height="wrap_content"
android:layout_below="#+id/commenterImage"
android:minHeight="120dp"
android:scaleType="centerCrop" />
</RelativeLayout>
when onBind or onViewAttachedToWindow is called, the child is not measured yet so you cannot get the width. Even if these calls were made after child is measured, what you are trying to do would not be a good practice because changing height will require a new measurement.
If you are using LinearLayoutManager, it will give the full width to the child (expect RecyclerView padding and child's margins). It is not great but OK to derive your height from there.
Another (more flexible) approach here is to create a custom ImageView that keeps your aspect ratio. When onBind is called, you'll set the desired aspect ratio of your custom ImageView.
When on measure is called, it will measure depending on your aspect ratio.
class MyImageView extends ImageVIew {
....
private float mScale = 1f;
public void setScale(int scale) {
mScale = scale;
}
#Override
protected void onMeasure(int widthMeasureSpec, int heightMeasureSpec) {
super.onMeasure(widthMeasureSpec, heightMeasureSpec);
int width = getMeasuredWidth();
setMeasuredDimension(width, width * mScale);
}
}
So in your onBind method, you call setScale on the ImageView depending on your w/h ratio.
I have not tested but this approach should work as desired.
You can use Picasso Transformation to achieve this.
FitToTargetViewTransformation class:
import android.graphics.Bitmap;
import android.view.View;
import com.squareup.picasso.Transformation;
/**
* Picasso Transformation class to fit image to target View size
*/
public class FitToTargetViewTransformation implements Transformation {
private View view;
public FitToTargetViewTransformation(View view) {
this.view = view;
}
#Override
public Bitmap transform(Bitmap source) {
int targetWidth = view.getWidth();
double aspectRatio = (double) source.getHeight() / (double) source.getWidth();
int targetHeight = (int) (targetWidth * aspectRatio);
if (source.getHeight() >= source.getWidth()) {
return source;
}
Bitmap result = Bitmap.createScaledBitmap(source, targetWidth, targetHeight, false);
if (result != source) {
// Same bitmap is returned if sizes are the same
source.recycle();
}
return result;
}
#Override
public String key() {
return "transformation" + " desiredWidth";
}
}
And somewhere in onBindViewHolder you do something like this:
Picasso.with(context)
.load(AVATAR_ENDPOINT)
.transform(new FitToTargetViewTransformation(feedViewHolder.icAvatar))
.into(feedViewHolder.icAvatar);

how can i reduce the row height in a custom listview android

I created a custom listview with rowlayout.xml and custom adapter. heach row has a pair of textveiws and background, the problem is i can't reduce the height if i set the background image for the row. if quit it the height is so small.
I need create a custom row with background and reduce the height how i cant, i tried change re row.xml height, but it doesn't work. in the android's ui visor it seems is going to work, but when I run it the row never changes his size.
this is the code for the row
<?xml version="1.0" encoding="utf-8"?>
<RelativeLayout xmlns:android="http://schemas.android.com/apk/res/android"
android:layout_width="fill_parent"
android:layout_height="80dp"
android:orientation="horizontal"
android:paddingLeft="#dimen/lateral_margin"
android:paddingRight="#dimen/lateral_margin"
android:background="#drawable/list_detail"
>
<TextView
android:id="#+id/textItemOnList"
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:text="TextView"
android:layout_alignParentLeft="true"
android:layout_centerVertical="true" />
<TextView
android:id="#+id/textMoneyOnList"
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:text="TextView"
android:layout_alignParentRight="true"
android:layout_centerVertical="true" />
</RelativeLayout>
You will have to resize your background image same the size of your listview row.
` public static Bitmap resizeBitmap(Bitmap photo, float x, float y) {
try {
// get current bitmap width and height
int width = photo.getWidth();
int height = photo.getHeight();
// determine how much to scale
float scaleWidth = x / width;
float scaleHeight = y / height;
// create the matrix for the manipulation
Matrix matrix = new Matrix();
// resize the bitmap
matrix.postScale(scaleWidth, scaleHeight);
// recreate the new bitmap
Bitmap resizebitmap = Bitmap.createBitmap(photo, 0, 0, width,
height, matrix, false);
return resizebitmap;
} catch (NullPointerException e) {
e.printStackTrace();
} catch (OutOfMemoryError e) {
e.printStackTrace();
System.gc();
}
return null;
}
`

Android ImageView: Fit Width

I download image and set it as a screen background dynamically using Imageview. I have tried ScaleType, to scale the image.
If image height is larger than width then ScaleTypes fitStart, fitEnd and fitCenter don't work. Android scale down the photo and fit it based on the height, but I see some extra blank space as part of the width.
I want to scale down the photo based on the width so that it fits the width and I don't care if there's some extra blank space as part of the height or if height is too long it is fine if it's going out of the view(if that's possible?).
ScaleType.XY scale the photo and fit everything in the ImageView and doesn't care about image height/weight ratio.
<ImageView
android:id="#+id/background"
android:layout_width="match_parent"
android:layout_height="match_parent"
android:adjustViewBounds="true"
android:scaleType="fitStart"
/>
I ended up using this code:
<ImageView
android:id="#+id/background"
android:layout_width="match_parent"
android:layout_height="match_parent"
android:adjustViewBounds="true"
android:scaleType="centerCrop"
android:src="#drawable/name"
/>
Make sure you set the image using src instead of background.
android:adjustViewBounds="true" does the job!
This elegant solution found here will work like a charm for you.
Basically you just have to create a small class that extends ImageView and simply override the onMeasure method to adjust the width and height as you want. Here it scales to fit width by using:
#Override
protected void onMeasure(int widthMeasureSpec, int heightMeasureSpec) {
int width = MeasureSpec.getSize(widthMeasureSpec);
int height = width * getDrawable().getIntrinsicHeight() / getDrawable().getIntrinsicWidth();
setMeasuredDimension(width, height);
}
You would use this special ImageView like this:
<your.activity.package.AspectRatioImageView
android:layout_width="fill_parent"
android:layout_height="fill_parent"
android:layout_gravity="center_vertical"
android:src="#drawable/test" />
There is a simple method if you simply want to fill the width of screen and have height proportional (and know the ratio of the image) you can do this in OnCreate():
setContentView(R.layout.truppview_activity);
trupImage = (ImageView) findViewById(R.id.trupImage);
Display display = getWindowManager().getDefaultDisplay();
DisplayMetrics outMetrics = new DisplayMetrics();
display.getMetrics(outMetrics);
float scWidth = outMetrics.widthPixels;
trupImage.getLayoutParams().width = (int) scWidth;
trupImage.getLayoutParams().height = (int) (scWidth * 0.6f);
Where 0.6 is the ratio adjustment (you could also calc automatically of course if you know the w & h of image).
PS:
Here is the XML side:
<ImageView
android:id="#+id/trupImage"
android:layout_width="match_parent"
android:background="#color/orange"
android:layout_height="match_parent"
android:adjustViewBounds="true"
android:scaleType="fitCenter" />
if you want to fit the image whole parent block
it will stretch the image
android:layout_width="match_parent"
android:layout_height="match_parent"
android:scaleType="fitXY"
And if you want to fit image whole parent with original ratio of image
it will crop out some part of image
android:layout_width="match_parent"
android:layout_height="match_parent"
android:adjustViewBounds="true"
android:scaleType="centerCrop"
This works for me.
Create a class extends ImageView
package com.yourdomain.utils;
import android.content.Context;
import android.graphics.drawable.Drawable;
import android.util.AttributeSet;
import android.widget.ImageView;
public class ResizableImageView extends ImageView {
public ResizableImageView(Context context, AttributeSet attrs) {
super(context, attrs);
}
#Override
protected void onMeasure(int widthMeasureSpec, int heightMeasureSpec) {
Drawable d = getDrawable();
if (d != null) {
int width = MeasureSpec.getSize(widthMeasureSpec);
int height = (int) Math.ceil((float) width * (float) d.getIntrinsicHeight() / (float) d.getIntrinsicWidth());
setMeasuredDimension(width, height);
} else {
super.onMeasure(widthMeasureSpec, heightMeasureSpec);
}
}
}
In xml use the following instead of ImageView
<com.yourdomain.utils.ResizableImageView
android:layout_width="match_parent"
android:layout_height="wrap_content"
android:src="#drawable/test" />
I think you cant do it only with XML, you need to resize yourself, the bitmap
Display display = getWindowManager().getDefaultDisplay();
int width = display.getWidth();
try {
((ImageView) findViewById(R.id.background))
.setImageBitmap(ShrinkBitmap(width));
} catch (FileNotFoundException e) {
e.printStackTrace();
}
then
private Bitmap ShrinkBitmap(int width)
throws FileNotFoundException {
BitmapFactory.Options bmpFactoryOptions = new BitmapFactory.Options();
bmpFactoryOptions.inJustDecodeBounds = true;
Bitmap bitmap = BitmapFactory.decodeResource(getResources(),
R.drawable.img, bmpFactoryOptions);
int widthRatio = (int) android.util.FloatMath
.ceil(bmpFactoryOptions.outWidth / (float) width);
bmpFactoryOptions.inSampleSize = widthRatio;
if (bmpFactoryOptions.inSampleSize <= 0)
bmpFactoryOptions.inSampleSize = 0;
bmpFactoryOptions.inPreferredConfig = Bitmap.Config.ARGB_8888;
bmpFactoryOptions.inJustDecodeBounds = false;
bitmap = BitmapFactory.decodeResource(getResources(),
R.drawable.img, bmpFactoryOptions);
return bitmap;
}
And the layout
<ImageView
xmlns:android="http://schemas.android.com/apk/res/android"
android:id="#+id/background"
android:layout_width="wrap_content"
android:layout_height="wrap_content"
/>

How to fill the image within ImageView by maintaining aspect ratio?

I saw many questions on this same topic and tried by using
android:adjustViewBounds="true"
android:scaleType="fitCenter"
still my image is displaying as it is.If I change the
android:scaleType="fitCenter"
to
fitXY working fine.But as per document this one not maintains aspect ratio.So How can I change the code to work as expected?
<?xml version="1.0" encoding="utf-8"?>
<LinearLayout xmlns:android="http://schemas.android.com/apk/res/android"
android:layout_width="fill_parent"
android:layout_height="fill_parent"
android:orientation="vertical">
<LinearLayout
android:id="#+id/card"
android:layout_marginTop="25dp"
android:layout_width="fill_parent"
android:layout_height="wrap_content"
android:background="#drawable/card" >
<ImageView
android:id="#+id/idImage"
android:layout_width="fill_parent"
android:layout_height="110dp"
android:layout_margin="10dp"
android:adjustViewBounds="true"
android:scaleType="fitCenter"
android:src="#drawable/783454" />
</LinearLayout>
</LinearLayout>
![enter image description here][1]
![enter image description here][2]
Where iam missing the concept?
Please look at this code, this is how I was scaling bitmaps to fit screen properly. Maybe it will be helpful and give you ideas regarding to your task.
private void loadImage() {
ImageView imageView = (ImageView)findViewById(R.id.imageView);
Bitmap imageBitmap = ... load original image bitmap;
Bitmap scaledBitmap = imageBitmap;
// Scaling
int imgSrcHeight = imageBitmap.getHeight();
int imgSrcWidth = imageBitmap.getWidth();
int scaledHeight = 0;
int scaledWidth = 0;
int ctnrHeight = imageView.getMeasuredHeight();
int ctnrWidth = imageView.getMeasuredWidth();
int mHeight = imgSrcHeight - ctnrHeight;
int mWidth = imgSrcWidth - ctnrWidth;
if(mHeight > 0 && mWidth > 0)
{
if(mHeight > mWidth)
{
// scale to fit height
if(mHeight > 0)
{
scaledHeight = ctnrHeight;
// if height < 0 it means it's already inside of content
int coefOverhight = (ctnrHeight * 100)/imgSrcHeight;
scaledWidth = (int)(imgSrcWidth * ((coefOverhight)/100.0));
}
}
else
{
// scale to fit width
if(mWidth > 0)
{
scaledWidth = ctnrWidth;
int coefOverwidth = (ctnrWidth * 100)/imgSrcWidth;
scaledHeight = (int)(imgSrcHeight * ((coefOverwidth)/100.0));
}
}
}
else
{
scaledHeight = imgSrcHeight;
scaledWidth = imgSrcWidth;
}
scaledBitmap = Bitmap.createScaledBitmap(imageBitmap, scaledWidth, scaledHeight, true);
imageView.setImageBitmap(scaledBitmap);
}

Categories

Resources