I have an imageView.
<ImageView
android:id="@+id/backgroud"
android:layout_width="match_parent"
android:layout_height="wrap_content"
android:scaleType="centerInside"
app:layout_constraintEnd_toEndOf="parent"
app:layout_constraintStart_toStartOf="parent"
app:layout_constraintTop_toTopOf="parent"/>
I need to download the image from the internet and the size of received image is more then the size of ImageView generally. I am Picasso library. But It always does not respect aspect ratio of image or boundaries of ImageView. I am using Picasso to download the image with Target Object. Seems that the problem is related to Picasso itself, because if i set the image from xml it respects the aspect ratio of image.
getPicassoInstance().load(url)
.into(binding.backgroud)
.into(backgroud, object :
Callback {
override fun onError(e: Exception?) {
Timber.w("Could not load the background image$e")
}
override fun onSuccess() {
}
})
I've tried other Picasso approaches like using 'centerInside' but they are not working as well. Generally it stretches the image to whole width of ImageView without preserving aspect ratio of downloaded image. The width of downloaded image more then the size of phone in portrait mode.
This is the code used in my app:
/**
* show the chosen image identified by uri.
*
*
* A Uniform Resource Identifier (URI) is a compact sequence of characters that identifies an abstract or physical resource
*
* @param context Context
* @param uri uri of the image
* @param myImage ImageView where the image will be displayed
* @see scaleImage
*/
@JvmStatic
fun showImage(context: Context, uri: Uri?, myImage: ImageView) {
var bitmap: Bitmap? = null
//
try {
val source = ImageDecoder.createSource(
context.contentResolver,
uri!!
)
bitmap = ImageDecoder.decodeBitmap(source) { decoder, _, _ ->
decoder.setTargetSampleSize(1) // shrinking by
decoder.isMutableRequired = true // this resolve the hardware type of bitmap problem
}
} catch (e: Exception) {
e.printStackTrace()
}
//
// On devices running SDK < 24 (Android 7.0), this method will fail to apply
// correct density scaling to images loaded from content and file schemes.
// Applications running on devices with SDK >= 24 MUST specify the
// targetSdkVersion in their manifest as 24 or above for density scaling
// to be applied to images loaded from these schemes.
myImage.setImageBitmap(bitmap)
scaleImage(context, bitmap, myImage)
}
/**
* scale the image represented in the bitmap.
* REFER to [stackoverflow](https://stackoverflow.com/questions/8232608/fit-image-into-imageview-keep-aspect-ratio-and-then-resize-imageview-to-image-d)
* answer of [Jarno Argillander](https://stackoverflow.com/users/1030049/jarno-argillander)
*
* @param context Context
* @param bitmap bitmap of the image
* @param view imageview where the image will be displayed
* @see dpToPx
*/
@Throws(NoSuchElementException::class)
@JvmStatic
private fun scaleImage(context: Context, bitmap: Bitmap?, view: ImageView) {
// Get current dimensions AND the desired bounding box
var width: Int
width = try {
bitmap!!.width
} catch (e: NullPointerException) {
throw NoSuchElementException("Can't find bitmap on given view/drawable")
}
var height = bitmap.height
val bounding = dpToPx(context,150)
// Log.i("Test", "original width = " + Integer.toString(width));
// Log.i("Test", "original height = " + Integer.toString(height));
// Log.i("Test", "bounding = " + Integer.toString(bounding));
// Determine how much to scale: the dimension requiring less scaling is
// closer to the its side. This way the image always stays inside your
// bounding box AND either x/y axis touches it.
val xScale = bounding.toFloat() / width
val yScale = bounding.toFloat() / height
val scale = if (xScale <= yScale) xScale else yScale
// Log.i("Test", "xScale = " + Float.toString(xScale));
// Log.i("Test", "yScale = " + Float.toString(yScale));
// Log.i("Test", "scale = " + Float.toString(scale));
// Create a matrix for the scaling and add the scaling data
val matrix = Matrix()
matrix.postScale(scale, scale)
// Create a new bitmap and convert it to a format understood by the ImageView
val scaledBitmap = Bitmap.createBitmap(bitmap, 0, 0, width, height, matrix, true)
width = scaledBitmap.width // re-use
height = scaledBitmap.height // re-use
val result = BitmapDrawable(context.resources, scaledBitmap)
// Log.i("Test", "scaled width = " + Integer.toString(width));
// Log.i("Test", "scaled height = " + Integer.toString(height));
// Apply the scaled bitmap
view.setImageDrawable(result)
// Now change ImageView's dimensions to match the scaled image
val params = view.layoutParams as ConstraintLayout.LayoutParams
params.width = width
params.height = height
view.layoutParams = params
// Log.i("Test", "done");
}
/**
* calculate the dimensions of desired bounding box.
*
*
* @param dp int with dimensions of desired bounding box
* @return int with dimensions of desired bounding box in px
*/
@JvmStatic
private fun dpToPx(context: Context, dp: Int): Int {
val density = context.getApplicationContext().resources.displayMetrics.density
return Math.round(dp.toFloat() * density)
}