ピカソを使用して、画像のサイズを全幅と可変高さに変更します


84

ImageView可変サイズ(幅と高さ)を含むアダプターを備えたlistViewがあります。ピカソで読み込まれた画像のサイズを、レイアウトの最大幅と画像のアスペクト比で指定された可変の高さに変更する必要があります。

私はこの質問をチェックしました: ピカソで画像を全幅と固定高さにサイズ変更します

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()ディメンションの1つをとしてリクエストを追加するだけ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 2014年

1
うーん、このチェックを追加すると、この問題は発生しなくなりましたが、画像のサイズは変更されません...
mrroboaat 2014

2
@ Lukasz'Severiaan'Grela私も同じ問題を抱えていました。:あなたの周りの引数を有効にする必要があり、元の質問と一致するように、この例を修正するには.resize(holder.message_picture.getWidth(), 0)
クリスティ

4
あなたは私にその考えを与えました。ありがとう。これらに可変の高さが、使用して全幅イメージを持つようにしたい: Display display = getWindowManager().getDefaultDisplay(); Point size = new Point(); display.getSize(size); int width = size.x; .resize(width, 0)
fahrulazmi

1
この方法を使用しました。アプリをバックグラウンドに移動して戻ったときに、onGlobalLayout()呼び出されず、画像が表示されません。
Gokhan Arik 2016

82

私は同じ問題に遭遇し、解決策を見つけるのにしばらく時間がかかりましたが、最終的に私のために働く何かに遭遇しました。

まず、ピカソの呼び出しをに変更しました

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"

うまくいけば、それはあなたにもうまくいくでしょう。


2
ありがとう、でもこれは私にはうまくいきません。写真が表示されず、ビットマップのサイズに関するlogcat警告が表示されます(従来のメッセージ:2048x2048が最大サイズです)。
ウェンディゴ2014

4
それを聞いてすみません。それがこの方法の欠点です。ピカソが画像のサイズを変更することはまったくありません。フルサイズでロードするだけです。メモリの問題を引き起こす可能性があります。
drspaceboo 2014

どうもありがとうございました。それは魅力のように、素早く簡単に機能します;)
Foo

@drspacebooあなたlayout_widthlayout_heightImageViewには何がありますか?私はしようとしているmatch_parentwrap_content:(それぞれが、それは動作しません
ヴィッキーChijwani

メモリから@VickyChijwaniは私が私が持っていたと思う0dpmatch_parentの重量で1100%ではないことを確認し、私たちはもはや我々のアプリケーションでこれを持っていないと思います。
drspaceboo 2015年

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

さらに、このスニップには、非表示をロードするためのコールバックとエラー描画可能な組み込みピカソが含まれています。

エラーをデバッグするためにさらに情報が必要な場合onError Callbackは、情報が「null」であるため、カスタムリスナー(Picassoビルダー)を実装する必要があります。UIの動作にエラーがあることだけを知っています。

これが誰かが多くの時間を節約するのに役立つことを願っています。


結果と同じ場合にのみ、ソースをリサイクルしているように見えます。とにかくリサイクルして結果を返してみませんか?
ウェンガー

@ウェンガー、いいえ、ピカソはそうすると文句を言います。
ジョージヒリアード2014年

すごい!!本当に素晴らしい
ElOjcar 2017

うん、これはうまくいった。しかし、私の場合、ImageViewの幅をmatch_parent、つまり特定の幅に設定する必要がありました。「wrap_content」は変換で0(ゼロ)を返し、例外を発生させます。
angryITguy

スクロール中にholder.message_picture.getWidth()0が返されることがあり、エラーが発生しますwidth and height must be > 0。このエラーを修正する方法はありますか?
Shahood ulHassan19年

9

受理の回答は全てに便利ですが、あなたが複数結合している場合は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);

それがあなたを助けることを願っています。


おかげで、ImageViewの素晴らしいソリューション、1つの質問:パラメーターで渡されたImageViewと同じVideoViewサイズでこれを行うことができますか?
Vrajesh 2017年

@Pratik私はrecyclerviewを持っていて、速くスクロールすると、例外が発生しました:変換変換desiredWidthが例外でクラッシュしました。原因:java.lang.IllegalArgumentException:幅と高さは0
より大きい

スクロール中にimageView.getWidth()0が返されることがあり、エラーが発生しますwidth and height must be > 0。このエラーを修正する方法はありますか?
Shahood ulHassan19年

その場合、画像のURLがnullである可能性があるため、nullかどうかを最初に確認してください。
PratikButani19年

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

レイアウト完了リスナーの追加に注意を払い、レイアウトプロセスが完了したときに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());

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 ulHassan19年

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

このコードを試してみてください。


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.