【问题标题】:Resize image to full width and variable height with Picasso使用毕加索将图像大小调整为全宽和可变高度
【发布时间】:2014-03-20 07:54:16
【问题描述】:

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

我已经检查了这个问题: Resize image to full width and fixed height with Picasso

fit() 有效,但我没有找到任何东西可以保持图片的纵横比。

如果我固定适配器布局中的高度,此代码部分有效:

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

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

提前致谢。

【问题讨论】:

    标签: android picasso


    【解决方案1】:

    从毕加索 2.4.0 开始,this operation is now directly supported。只需添加一个.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);
                }
            });
    

    【讨论】:

    • 使用这个解决方案我收到java.lang.IllegalArgumentException: At least one dimension has to be positive number. 旋转错误,这是在片段中,关于为什么会发生这种情况的任何想法?
    • 嗯,如果我添加这个检查,我没有这个问题了,但图像没有调整大小......
    • @Lukasz'Severiaan'Grela 我遇到了同样的问题。要修复此示例以匹配原始问题,您必须扭转论点:.resize(holder.message_picture.getWidth(), 0)
    • 你给了我这个主意。谢谢。对于那些想要具有可变高度的全宽图像的人,请使用:Display display = getWindowManager().getDefaultDisplay(); Point size = new Point(); display.getSize(size); int width = size.x;.resize(width, 0)
    • 我用了这个方法,当你把应用拉到后台回来的时候,onGlobalLayout()没有被调用,图片也不会出现。
    【解决方案2】:

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

    首先我将 Picasso 调用改为

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

    删除fitcenterInside。接下来,您需要将以下行添加到 XML 中的 ImageView

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

    希望它也对你有用。

    【讨论】:

    • 谢谢,但这对我不起作用。我看不到图片,收到关于 Bitmap 大小的 logcat 警告(经典消息:2048x2048 是最大大小)。
    • 很抱歉听到这个消息。这将是这种方法的缺点。根本没有让毕加索调整图像的大小,只需以全尺寸加载即可。可能会导致内存问题。
    • 非常感谢。它就像一个魅力,快速而简单;)
    • @drspaceboo 你在 ImageView 上的 layout_widthlayout_height 是什么?我分别尝试使用match_parentwrap_content,但它不起作用:(
    • @VickyChijwani 记忆中的我想我有0dpmatch_parent 的权重为1 但不是100% 肯定,我认为我们的应用程序中不再有这个。
    【解决方案3】:

    最后我通过毕加索的变换解决了,这里是sn-p:

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

    此外,此片段还包括用于加载隐藏和错误可绘制内置毕加索的回调。

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

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

    【讨论】:

    • 看起来你只是在回收与结果相同的源。难道你不想回收它并只返回结果吗?
    • @Wenger,不,如果你这样做,毕加索会抱怨。
    • 太棒了!!真的很棒
    • 是的,这行得通。但在我的情况下,我必须将 ImageView 宽度设置为 match_parent 或特定宽度。 "wrap_content" 在转换中返回 0(零),并引发异常。
    • 滚动时,holder.message_picture.getWidth() 有时会返回 0 并导致错误 width and height must be > 0。任何想法如何解决此错误?
    【解决方案4】:

    可能 Accepted 答案对所有人都有用,但如果您为多个 Views 绑定多个 ViewHolder,那么您可以通过为 Transformation创建类来减少代码> 并从 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";
                }
            };
        }
    }
    

    来自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);
    

    希望对你有所帮助。

    【讨论】:

    • 谢谢,ImageView 很好的解决方案,有一个问题:我们可以为 VideoView 的大小与传入参数的 ImageView 相同吗?
    • @Pratik 我有 recyclerview,当快速滚动时,出现异常:Transformation transformation desiredWidth 因异常而崩溃。引起:java.lang.IllegalArgumentException:宽度和高度必须> 0
    • 在滚动时,有时imageView.getWidth() 返回 0 并导致错误width and height must be > 0。任何想法如何解决此错误?
    • 在这种情况下,可能是您的图片 url 为空,因此请先检查它是否为空。
    【解决方案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.post(new Runnable() {
            @Override public void run() {
              Picasso.with(context)
                  .resize(0, imageView.getHeight())
                  .onlyScaleDown()
                  .into(imageView, new ImageCallback(callback, null));
            }
          });
      

      【讨论】:

        【解决方案7】:

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

        【讨论】:

          【解决方案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

          【讨论】:

          • 这种情况下ImageViewlayout_widthlayout_height应该是什么?
          【解决方案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.
            

            我通过编辑从接受的答案给出的代码解决了这个问题,我得到了显示的最大宽度,就好像我的 imageview 宽度已经是 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);
              

              试试这个代码,为我工作。

              【讨论】:

                【解决方案12】:
                @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);
                
                
                    }
                

                【讨论】:

                  猜你喜欢
                  • 2014-01-16
                  • 1970-01-01
                  • 2014-10-20
                  • 1970-01-01
                  • 2013-09-14
                  • 2015-05-19
                  • 2012-01-13
                  • 2017-07-14
                  相关资源
                  最近更新 更多