Picasso를 사용하여 이미지를 전체 너비 및 가변 높이로 크기 조정


84

ImageView가변 크기 (너비 및 높이) 가 포함 된 어댑터가있는 listView가 있습니다 . Picasso를 사용하여 그림로드의 크기를 레이아웃의 최대 너비와 그림의 가로 세로 비율로 지정된 가변 높이로 조정해야합니다.

이 질문을 확인했습니다 : Picasso를 사용하여 이미지를 전체 너비와 고정 높이로 크기 조정

fit()작동하지만 사진의 가로 세로 비율을 유지하기 위해 아무것도 발견하지 않았습니다.

이 코드는 어댑터 레이아웃에서 높이를 고정하면 부분적으로 작동합니다.

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

그러나 그림이 해당 높이가 없을 수 있기 때문에 listView 그림 사이에 공백을 생성합니다.

미리 감사드립니다.

답변:


89

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

8
이 솔루션을 사용하면 java.lang.IllegalArgumentException: At least one dimension has to be positive number.회전 오류가 발생합니다. 이것은 조각에 있습니다. 왜 이런 일이 발생할 수 있는지에 대한 아이디어가 있습니까?
Lukasz 'Severiaan'Grela

1
내가이 검사를 추가하면 흠은 더 이상하지이 문제가 있지만, 이미지 크기를 조정하지 않습니다 ...
mrroboaat

2
@ Lukasz'Severiaan'Grela 나도 같은 문제가 있었다. 이 예를 원래 질문과 일치하도록 수정하려면 다음과 같이 논쟁을 .resize(holder.message_picture.getWidth(), 0)
Christiaan

4
당신이 나에게 아이디어를 주었다. 감사. 이들에 변수 높이를 사용하여 전체 폭 이미지를 갖고 싶어 : Display display = getWindowManager().getDefaultDisplay(); Point size = new Point(); display.getSize(size); int width = size.x; .resize(width, 0)
fahrulazmi

1
이 방법을 사용 onGlobalLayout()했는데 , 앱을 백그라운드로 가져 갔다가 돌아올 때 호출되지 않고 이미지가 표시되지 않습니다.
Gokhan Arik

82

나는 같은 문제를 만났고 해결책을 찾는 데 시간이 걸렸지 만 마침내 나를 위해 일하는 것을 발견했습니다.

먼저 Picasso 호출을

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

제거 단계 fit와를 centerInside. 다음으로 XML의 ImageView에 다음 줄을 추가해야합니다.

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

바라건대 그것은 당신에게도 효과가있을 것입니다.


2
고맙지 만 이것은 나를 위해 작동하지 않습니다. 그림을 볼 수없고 비트 맵 크기에 대한 logcat 경고가 표시됩니다 (클래식 메시지 : 2048x2048이 최대 크기입니다).
wendigo 2014

4
유감입니다. 이것이이 방법의 단점입니다. Picasso가 이미지 크기를 전혀 조정하지 않고 전체 크기로로드하기 만하면됩니다. 메모리 문제를 일으킬 수 있습니다.
drspaceboo 2014

대단히 감사합니다. 매력처럼 빠르고 쉽게 작동합니다.)
Foo

@drspaceboo 귀하 layout_widthlayout_heightImageView는 무엇입니까? 나는 match_parentwrap_content각각 시도 하고 있지만 작동하지 않습니다 :(
Vicky Chijwani

메모리에서 @VickyChijwani는 내가 가진 생각 0dpmatch_parent의 무게 1확실하지만 100 %와 나는 우리가 더 이상 우리의 응용 프로그램이 있다고 생각하지 않습니다.
drspaceboo

60

마지막으로 피카소를 변환하여 해결했습니다. 여기에 스 니펫이 있습니다.

    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를로드하기위한 콜백이 포함됩니다.

오류를 디버깅하기 위해 추가 정보가 필요한 경우 onError Callback정보가 "null"이므로 사용자 정의 리스너 (Picasso 빌더)를 구현해야합니다 . UI 동작에 오류가 있다는 것만 알고 있습니다.

누군가가 많은 시간을 절약하는 데 도움이되기를 바랍니다.


결과와 동일한 경우에만 소스를 재활용하는 것 같습니다. 재활용하고 결과 만 반환하고 싶지 않습니까?
Wenger

@Wenger, 아니요, Picasso는 그렇게하면 불평합니다.
George Hilliard 2014

큰!! 정말 좋은
ElOjcar

네, 작동했습니다. 하지만 내 경우에는 ImageView 너비를 match_parent 또는 특정 너비로 ​​설정해야했습니다. "wrap_content"는 변환에서 0 (영)을 반환하고 예외를 발생시킵니다.
angryITguy

스크롤하는 동안 때때로 holder.message_picture.getWidth()0을 반환하고 오류가 발생 width and height must be > 0합니다. 이 오류를 수정하는 방법에 대한 아이디어가 있습니까?
Shahood ul Hassan

9

허용의 대답은 모두에게 유용하지만 여러 바인딩하는 경우 ViewHolder복수를 위해 Views당신은을위한 클래스를 생성하여 코드를 줄일 수 있습니다 변환 및 전달 이미지 뷰를 에서 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);

그것이 당신을 도울 수 있기를 바랍니다.


감사합니다. ImageView에 대한 훌륭한 솔루션, 한 가지 질문 : 매개 변수에 전달 된 ImageView와 동일한 VideoView 크기에 대해이 작업을 수행 할 수 있습니까?
Vrajesh

@Pratik 나는 recyclerview를 가지고 있으며 빠르게 스크롤하면 예외가 발생했습니다. 변형 변환 desiredWidth가 예외와 함께 충돌했습니다. 원인 : java.lang.IllegalArgumentException : 너비와 높이는> 0이어야합니다
Vrajesh

스크롤하는 동안 때때로 imageView.getWidth()0을 반환하고 오류가 발생 width and height must be > 0합니다. 이 오류를 수정하는 방법에 대한 아이디어가 있습니까?
Shahood ul Hassan

이 경우 이미지 URL이 null 일 수 있으므로 null인지 아닌지 먼저 확인하십시오.
Pratik Butani

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

이것은 모든 장치에 대해 다양한 이미지 높이를 지원합니다.


0

레이아웃 완료 리스너를 추가하고 레이아웃 프로세스가 완료되면 (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());

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

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

더 많은 변환 : https://github.com/wasabeef/picasso-transformations


이 경우 layout_widthlayout_height의 무엇이어야 ImageView합니까?
Shahood ul Hassan

0

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

0

실제로 확대 / 축소 가능한 기능이있는 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";
            }
        };
    }

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

이 코드를 사용해보세요. Worked for me.


0
@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);


    }
당사 사이트를 사용함과 동시에 당사의 쿠키 정책개인정보 보호정책을 읽고 이해하였음을 인정하는 것으로 간주합니다.
Licensed under cc by-sa 3.0 with attribution required.