Изменение размера изображения до полной ширины и переменной высоты с помощью 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, потому что изображения могут быть такими, которые не имеют этой высоты.

Спасибо заранее.

Ответ 1

Наконец, я решил это сделать преобразование Пикассо, вот фрагмент:

    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 равна "null". Вы знаете только, что для поведения пользовательского интерфейса существует ошибка.

Я надеюсь, что это поможет кому-то сэкономить много часов.

Ответ 2

Начиная с 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);
            }
        });

Ответ 3

Я столкнулся с той же проблемой, и мне потребовалось некоторое время, чтобы найти решение, но я, наконец, натолкнулся на то, что работает для меня.

Во-первых, я изменил вызов Пикассо на

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"

Надеюсь, это сработает и для вас.

Ответ 4

May Принято Ответ полезен для всех, но если вы привязываетесь Несколько 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);

Надеюсь, это поможет вам.

Ответ 5

    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"/>

Это поможет вам с переменной высотой изображений для всех устройств.

Ответ 6

Я написал простого помощника, который заботится о том, чтобы добавить полноэкранный макет и вызвать (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());

Ответ 7

imageView.post(new Runnable() {
      @Override public void run() {
        Picasso.with(context)
            .resize(0, imageView.getHeight())
            .onlyScaleDown()
            .into(imageView, new ImageCallback(callback, null));
      }
    });

Ответ 8

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

Ответ 9

расширяйте 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);
        }
    }

Ответ 10

На самом деле я попадал во время загрузки изображения в 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";
            }
        };
    }

Ответ 11

Picasso.get()
.load(message_pic_url)
.fit()
.centerCrop()
.placeholder(R.drawable.profile_wall_picture)
.into(holder.message_picture);

Попробуйте этот код, Работайте для меня.