使用Picasso将图像调整为全宽和可变高度

时间:2022-11-19 13:15:59

I have a listView with an adapter that contains ImageView of variable size (width and height). I need resize the pictures load with Picasso to the max width of layout and a variable height given by the aspect ratio of the picture.

我有一个带有适配器的listView,其中包含可变大小(宽度和高度)的ImageView。我需要将Picasso的图片大小调整为布局的最大宽度,并根据图片的宽高比给出可变高度。

I have checked this question: Resize image to full width and fixed height with Picasso

我已经检查了这个问题:用Picasso将图像调整到全宽和固定高度

The fit() works but I haven't found nothing to keep the aspect ratio of the picture.

fit()有效,但我没有发现任何东西来保持图片的宽高比。

This code partially works if I fixed the height in the layout of the adapter:

如果我修改了适配器布局中的高度,则此代码部分有效:

Picasso.with(this.context).load(message_pic_url)
.placeholder(R.drawable.profile_wall_picture)
.fit().centerInside()
.into(holder.message_picture);

But it generates blank spaces between the pictures of the listView because the pictures may be that not have that height.

但是它会在listView的图片之间生成空格,因为图片可能没有那个高度。

Thanks in advance.

提前致谢。

10 个解决方案

#1


73  

As of Picasso 2.4.0, this operation is now directly supported. Simply add a .resize() request with one of the dimensions as 0. For example, to have a variable width, your call would become:

从Picasso 2.4.0开始,现在可以直接支持此操作。只需添加一个尺寸为0的.resize()请求。例如,要使宽度可变,您的调用将变为:

Picasso.with(this.context)
       .load(message_pic_url)
       .placeholder(R.drawable.profile_wall_picture)
       .resize(0, holder.message_picture.getHeight()),
       .into(holder.message_picture);

Note that this call uses .getHeight() and therefore assumes the message_picture has already been measured. If that isn't the case, such as when you have inflated a new view in a ListAdapter, you can delay this call until after measurement by adding an OnGlobalLayoutListener to the view:

请注意,此调用使用.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);
            }
        });

#2


64  

I came across the same issue and it took me a while to track down a solution but I finally came across something that works for me.

我遇到了同样的问题,我花了一段时间来追踪解决方案,但我终于找到了适合我的东西。

Firstly I changed the Picasso call to

首先我改变了毕加索的电话

Picasso.with(this.context).load(message_pic_url)
.placeholder(R.drawable.profile_wall_picture)
.into(holder.message_picture);

Removing the fit and the centerInside. Next you need to add the following lines to the ImageView in your XML

删除适合度和centerInside。接下来,您需要将以下行添加到XML中的ImageView

android:scaleType="fitStart"
android:adjustViewBounds="true"

Hopefully it will work for you as well.

希望它也适合你。

#3


54  

Finally I solved it doing a transformation of Picasso, here is the snippet:

最后我解决了它对Picasso的转换,这里是片段:

    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);
            }
    });

This line is for customize with your desired width:

此行用于自定义您想要的宽度:

int targetWidth = holder.message_picture.getWidth();

Additionally this snipped include Callback for loading hide and error drawable built-in Picasso.

此外,这个剪辑包括用于加载隐藏的回调和错误可绘制的内置毕加索。

If you need more information to debug any error, you MUST implement a custom listener (Picasso builder) beacuse the onError Callback information is "null". You only know that there is an error for UI behavior.

如果您需要更多信息来调试任何错误,您必须实现自定义侦听器(Picasso构建器),因为onError回调信息为“null”。您只知道UI行为有错误。

I hope this helps someone to save many hours.

我希望这可以帮助别人节省很多时间。

#4


7  

May Accepted Answer is Useful to all but If you are binding Multiple ViewHolder for Multiple Views then you can reduce your code by Creating Class for Transformation and passing ImageView from ViewHolder.

可以接受的答案对所有人都很有用但是如果您正在为多个视图绑定多个ViewHolder,则可以通过创建转换类并从ViewHolder传递ImageView来减少代码。

/**
 * 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";
            }
        };
    }
}

Calling from ViewHolder:

从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);

Hope it will Help you.

希望它会帮助你。

#5


1  

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

This will help you with variable height of images for all devices

这将帮助您为所有设备提供可变高度的图像

#6


0  

I've wrote simple helper that take care about adding layout complete listener and call into(imageView) when layout process complete.

我编写了简单的帮助程序,在布局过程完成时注意添加布局完整的侦听器并调用(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);
}

}

}

So you can easily use it like this for example in fragment's onViewCreated()

所以你可以很容易地使用它,例如在片段的onViewCreated()中

new PicassoDelegate(customerPhoto, Picasso.with(getActivity()).load(user.getPhotoUrl()).centerCrop());

#7


0  

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

#8


0  

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 + ")";
  }

More transformations: https://github.com/wasabeef/picasso-transformations

更多转换:https://github.com/wasabeef/picasso-transformations

#9


0  

extend ImageView then override onMeasure method like the following.

扩展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


0  

Actually i was getting in while loading image in CustomImageView which had zoomable functionality

实际上我在CustomImageView中加载图像时进入,它具有可缩放的功能

Error was

错误是

java.lang.RuntimeException: Transformation transformation desiredWidth crashed with exception.

I solved it by editing code given from accepted answer i got the max width of my display as if my imageview width was already match_parent.

我通过编辑从接受的答案给出的代码解决了它我得到了我的显示器的最大宽度,好像我的imageview宽度已经是match_parent。

if (!imgUrl.equals("")) {

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";
            }
        };
    }

#1


73  

As of Picasso 2.4.0, this operation is now directly supported. Simply add a .resize() request with one of the dimensions as 0. For example, to have a variable width, your call would become:

从Picasso 2.4.0开始,现在可以直接支持此操作。只需添加一个尺寸为0的.resize()请求。例如,要使宽度可变,您的调用将变为:

Picasso.with(this.context)
       .load(message_pic_url)
       .placeholder(R.drawable.profile_wall_picture)
       .resize(0, holder.message_picture.getHeight()),
       .into(holder.message_picture);

Note that this call uses .getHeight() and therefore assumes the message_picture has already been measured. If that isn't the case, such as when you have inflated a new view in a ListAdapter, you can delay this call until after measurement by adding an OnGlobalLayoutListener to the view:

请注意,此调用使用.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);
            }
        });

#2


64  

I came across the same issue and it took me a while to track down a solution but I finally came across something that works for me.

我遇到了同样的问题,我花了一段时间来追踪解决方案,但我终于找到了适合我的东西。

Firstly I changed the Picasso call to

首先我改变了毕加索的电话

Picasso.with(this.context).load(message_pic_url)
.placeholder(R.drawable.profile_wall_picture)
.into(holder.message_picture);

Removing the fit and the centerInside. Next you need to add the following lines to the ImageView in your XML

删除适合度和centerInside。接下来,您需要将以下行添加到XML中的ImageView

android:scaleType="fitStart"
android:adjustViewBounds="true"

Hopefully it will work for you as well.

希望它也适合你。

#3


54  

Finally I solved it doing a transformation of Picasso, here is the snippet:

最后我解决了它对Picasso的转换,这里是片段:

    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);
            }
    });

This line is for customize with your desired width:

此行用于自定义您想要的宽度:

int targetWidth = holder.message_picture.getWidth();

Additionally this snipped include Callback for loading hide and error drawable built-in Picasso.

此外,这个剪辑包括用于加载隐藏的回调和错误可绘制的内置毕加索。

If you need more information to debug any error, you MUST implement a custom listener (Picasso builder) beacuse the onError Callback information is "null". You only know that there is an error for UI behavior.

如果您需要更多信息来调试任何错误,您必须实现自定义侦听器(Picasso构建器),因为onError回调信息为“null”。您只知道UI行为有错误。

I hope this helps someone to save many hours.

我希望这可以帮助别人节省很多时间。

#4


7  

May Accepted Answer is Useful to all but If you are binding Multiple ViewHolder for Multiple Views then you can reduce your code by Creating Class for Transformation and passing ImageView from ViewHolder.

可以接受的答案对所有人都很有用但是如果您正在为多个视图绑定多个ViewHolder,则可以通过创建转换类并从ViewHolder传递ImageView来减少代码。

/**
 * 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";
            }
        };
    }
}

Calling from ViewHolder:

从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);

Hope it will Help you.

希望它会帮助你。

#5


1  

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

This will help you with variable height of images for all devices

这将帮助您为所有设备提供可变高度的图像

#6


0  

I've wrote simple helper that take care about adding layout complete listener and call into(imageView) when layout process complete.

我编写了简单的帮助程序,在布局过程完成时注意添加布局完整的侦听器并调用(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);
}

}

}

So you can easily use it like this for example in fragment's onViewCreated()

所以你可以很容易地使用它,例如在片段的onViewCreated()中

new PicassoDelegate(customerPhoto, Picasso.with(getActivity()).load(user.getPhotoUrl()).centerCrop());

#7


0  

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

#8


0  

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 + ")";
  }

More transformations: https://github.com/wasabeef/picasso-transformations

更多转换:https://github.com/wasabeef/picasso-transformations

#9


0  

extend ImageView then override onMeasure method like the following.

扩展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


0  

Actually i was getting in while loading image in CustomImageView which had zoomable functionality

实际上我在CustomImageView中加载图像时进入,它具有可缩放的功能

Error was

错误是

java.lang.RuntimeException: Transformation transformation desiredWidth crashed with exception.

I solved it by editing code given from accepted answer i got the max width of my display as if my imageview width was already match_parent.

我通过编辑从接受的答案给出的代码解决了它我得到了我的显示器的最大宽度,好像我的imageview宽度已经是match_parent。

if (!imgUrl.equals("")) {

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";
            }
        };
    }