Изменить размер изображения до полной ширины и переменной высоты с помощью Picasso
У меня есть listView с адаптером, который содержит ImageView
переменного размера (ширина и высота). Мне нужно изменить размер изображений, загружаемых с помощью Picasso, до максимальной ширины макета и переменной высоты, заданной соотношением сторон изображения.
Я проверил этот вопрос: измените размер изображения на полную ширину и фиксированную высоту с помощью Picasso
fit()
работает, но я не нашел ничего, чтобы сохранить соотношение сторон изображения.
Этот код частично работает, если я установил высоту в макете адаптера:
Picasso.with(this.context).load(message_pic_url)
.placeholder(R.drawable.profile_wall_picture)
.fit().centerInside()
.into(holder.message_picture);
Но он генерирует пустые места между изображениями listView, потому что изображения могут не иметь такую высоту.
Заранее спасибо.
13 ответов
В конце концов я решил это сделать преобразование Пикассо, вот фрагмент:
Transformation transformation = new Transformation() {
@Override
public Bitmap transform(Bitmap source) {
int targetWidth = holder.message_picture.getWidth();
double aspectRatio = (double) source.getHeight() / (double) source.getWidth();
int targetHeight = (int) (targetWidth * aspectRatio);
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";
}
};
mMessage_pic_url = message_pic_url;
Picasso.with(this.context)
.load(message_pic_url)
.error(android.R.drawable.stat_notify_error)
.transform(transformation)
.into(holder.message_picture, new Callback() {
@Override
public void onSuccess() {
holder.progressBar_picture.setVisibility(View.GONE);
}
@Override
public void onError() {
Log.e(LOGTAG, "error");
holder.progressBar_picture.setVisibility(View.GONE);
}
});
Эта строка для настройки с желаемой шириной:
int targetWidth = holder.message_picture.getWidth();
Кроме того, этот фрагмент включает функцию обратного вызова для загрузки встроенного в Picasso скрытия и отрисовки ошибок.
Если вам нужна дополнительная информация для отладки какой-либо ошибки, вы ДОЛЖНЫ реализовать пользовательский прослушиватель (построитель Picasso), так как onError
Callback
информация является "нулевой". Вы только знаете, что есть ошибка для поведения пользовательского интерфейса.
Надеюсь, это поможет кому-то сэкономить много часов.
Начиная с Picasso 2.4.0, эта операция теперь поддерживается напрямую. Просто добавьте .resize()
запрос с одним из измерений как 0
, Например, чтобы иметь переменную ширину, ваш вызов стал бы:
Picasso.with(this.context)
.load(message_pic_url)
.placeholder(R.drawable.profile_wall_picture)
.resize(0, holder.message_picture.getHeight()),
.into(holder.message_picture);
Обратите внимание, что этот вызов использует .getHeight()
и, следовательно, предполагает message_picture
уже был измерен. Если это не так, например, когда вы раздули новый вид в ListAdapter
Вы можете отложить этот вызов до измерения, добавив OnGlobalLayoutListener
к мнению:
holder.message_picture.getViewTreeObserver()
.addOnGlobalLayoutListener(new ViewTreeObserver.OnGlobalLayoutListener() {
// Wait until layout to call Picasso
@Override
public void onGlobalLayout() {
// Ensure we call this only once
imageView.getViewTreeObserver()
.removeOnGlobalLayoutListener(this);
Picasso.with(this.context)
.load(message_pic_url)
.placeholder(R.drawable.profile_wall_picture)
.resize(0, holder.message_picture.getHeight())
.into(holder.message_picture);
}
});
Я столкнулся с той же проблемой, и мне потребовалось некоторое время, чтобы найти решение, но я, наконец, наткнулся на то, что работает для меня.
Сначала я изменил вызов Пикассо на
Picasso.with(this.context).load(message_pic_url)
.placeholder(R.drawable.profile_wall_picture)
.into(holder.message_picture);
Удаление fit
и centerInside
, Затем вам нужно добавить следующие строки в ImageView в вашем XML
android:scaleType="fitStart"
android:adjustViewBounds="true"
Надеюсь, это сработает и для вас.
Может Принятый Ответ Полезен для всех, но если вы связываете Несколько ViewHolder
для нескольких Views
затем вы можете уменьшить свой код, создав класс для преобразования и передав ImageView из ViewHolder
,
/**
* Created by Pratik Butani
*/
public class ImageTransformation {
public static Transformation getTransformation(final ImageView imageView) {
return new Transformation() {
@Override
public Bitmap transform(Bitmap source) {
int targetWidth = imageView.getWidth();
double aspectRatio = (double) source.getHeight() / (double) source.getWidth();
int targetHeight = (int) (targetWidth * aspectRatio);
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";
}
};
}
}
Звонить из ViewHolder
:
Picasso.with(context).load(baseUrlForImage)
.transform(ImageTransformation.getTransformation(holder.ImageView1))
.error(R.drawable.ic_place_holder_circle)
.placeholder(R.drawable.ic_place_holder_circle)
.into(holder.mMainPhotoImageView1);
Надеюсь, это поможет вам.
Picasso.with(this).load(url).resize(1800, 1800).centerInside().into(secondImageView)
<ImageView
android:id="@+id/SecondImage"
android:layout_width="fill_parent"
android:layout_height="wrap_content"
android:layout_alignParentStart="true"
android:layout_alignParentLeft="true"
android:adjustViewBounds="true"
android:layout_margin="10dp"
android:visibility="gone"/>
Это поможет вам с переменной высотой изображений для всех устройств
imageView.post(new Runnable() {
@Override public void run() {
Picasso.with(context)
.resize(0, imageView.getHeight())
.onlyScaleDown()
.into(imageView, new ImageCallback(callback, null));
}
});
Думаю, вам подойдет значение fitXY, вот пример, который сработал у меня:
<ImageView
android:id="@+id/imageView_answer"
android:layout_width="match_parent"
android:layout_height="match_parent"
android:gravity="center"
android:scaleType="fitXY"
app:layout_constraintBottom_toBottomOf="parent"
app:layout_constraintEnd_toEndOf="parent"
app:layout_constraintStart_toStartOf="parent"
app:layout_constraintTop_toTopOf="parent"
android:contentDescription="@string/answer_image" />
@Override
protected void onResume() {
super.onResume();
imageView.getViewTreeObserver().addOnGlobalLayoutListener(new ViewTreeObserver.OnGlobalLayoutListener() {
@Override
public void onGlobalLayout() {
loadImageIfReady();
}
});
}
private void loadImageIfReady() {
if (imageView.getMeasuredWidth() <= 0 || mPayload == null)
this.finish(); // if not ready GTFO
Picasso.with(this)
.load(mPayload)
.resize(imageView.getMeasuredWidth(), imageView.getMeasuredWidth())
.centerInside()
.into(imageView);
}
Я написал простой помощник, который позаботится о добавлении слушателя макета и вызова (imageView) после завершения процесса макета.
public class PicassoDelegate {
private RequestCreator mRequestCreator;
public PicassoDelegate(ImageView target, RequestCreator requestCreator) {
if (target.getWidth() > 0 && target.getHeight() > 0) {
complete(target, requestCreator);
} else {
mRequestCreator = requestCreator;
target.addOnLayoutChangeListener(new View.OnLayoutChangeListener() {
@Override
public void onLayoutChange(View v, int left, int top, int right, int bottom, int oldLeft, int oldTop, int oldRight, int oldBottom) {
v.removeOnLayoutChangeListener(this);
complete((ImageView) v, mRequestCreator);
}
});
}
}
private void complete(ImageView target, RequestCreator requestCreator) {
if (target.getWidth() > 0 && target.getHeight() > 0) {
requestCreator.resize(target.getWidth(), target.getHeight());
}
requestCreator.into(target);
}
}
Таким образом, вы можете легко использовать это, например, в onViewCreated() фрагмента
new PicassoDelegate(customerPhoto, Picasso.with(getActivity()).load(user.getPhotoUrl()).centerCrop());
Picasso.get()
.load(message_pic_url)
.fit()
.centerCrop()
.placeholder(R.drawable.profile_wall_picture)
.into(holder.message_picture);
Попробуйте этот код, работал для меня.
Расширить ImageView, затем переопределить метод onMeasure, как показано ниже.
@Override
protected void onMeasure(int widthMeasureSpec, int heightMeasureSpec){
Drawable d = getDrawable();
if(d!=null && fittingType == FittingTypeEnum.FIT_TO_WIDTH){
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);
}
}
На самом деле я получал при загрузке изображения в CustomImageView, который имел масштабируемую функциональность
Ошибка была
java.lang.RuntimeException: Transformation transformation desiredWidth crashed with exception.
Я решил это, отредактировав код, полученный из принятого ответа, и получил максимальную ширину моего дисплея, как будто ширина моего изображения уже совпадала с match_parent
if (!imgUrl.equals("")) {
DisplayMetrics displayMetrics = new DisplayMetrics();
((Activity) context).getWindowManager().getDefaultDisplay().getMetrics(displayMetrics);
int height = displayMetrics.heightPixels;
int width = displayMetrics.widthPixels;
Picasso.with(context).load(imgUrl)
.transform(getTransformation(width, imageView))
.into(imageView, new Callback() {
@Override
public void onSuccess() {
if (progressBar != null) {
progressBar.setVisibility(View.GONE);
}
}
@Override
public void onError() {
if (progressBar != null) {
progressBar.setVisibility(View.GONE);
}
}
});
}
public static Transformation getTransformation(final int width, final ImageView imageView) {
return new Transformation() {
@Override
public Bitmap transform(Bitmap source) {
int targetWidth = width;
double aspectRatio = (double) source.getHeight() / (double) source.getWidth();
int targetHeight = (int) (targetWidth * aspectRatio);
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";
}
};
}
public class CropSquareTransformation implements Transformation {
private int mWidth;
private int mHeight;
@Override public Bitmap transform(Bitmap source) {
int size = Math.min(source.getWidth(), source.getHeight());
mWidth = (source.getWidth() - size) / 2;
mHeight = (source.getHeight() - size) / 2;
Bitmap bitmap = Bitmap.createBitmap(source, mWidth, mHeight, size, size);
if (bitmap != source) {
source.recycle();
}
return bitmap;
}
@Override public String key() {
return "CropSquareTransformation(width=" + mWidth + ", height=" + mHeight + ")";
}
Дополнительные преобразования: https://github.com/wasabeef/picasso-transformations