web-dev-qa-db-ja.com

wrap_contentを使用したFacebookフレスコ

フレスコ画を使用してロードしたいドローアブルがたくさんあります。それらの画像にwrap_contentサイズを使用したいのですが、フレスコ画を使用してxmlでそれを行うにはどうすればよいですか?または、xmlが不可能な場合、コードでどのように実行しますか?

<com.facebook.drawee.view.SimpleDraweeView
          Android:id="@+id/myImage"
          Android:layout_width="wrap_content"
          Android:layout_height="wrap_content"
          fresco:placeholderImage="@mipmap/myImage"/>

固定サイズを設定しないと、上記のコードは機能しません。

16
Ilya Gazman

私はFrescoチームの一員であり、ラップコンテンツをサポートしないという設計上の決定を下したのは私です。理論的根拠は ドキュメント で説明されています。ただし、問題は、画像がすぐに利用可能になることを保証できないことです(最初に画像を取得する必要がある場合があります)。つまり、画像が到着したらビューサイズを変更する必要があります。これはほとんどの場合望ましくないため、UIを再考する必要があります。

とにかく、あなたが本当にそれをする必要がある/したいなら、あなたはこのようにそれをすることができます:

void updateViewSize(@Nullable ImageInfo imageInfo) {
  if (imageInfo != null) {
    draweeView.getLayoutParams().width = imageInfo.getWidth();
    draweeView.getLayoutParams().height = ViewGroup.LayoutParams.WRAP_CONTENT;
    draweeView.setAspectRatio((float) imageInfo.getWidth() / imageInfo.getHeight());
  }
}

ControllerListener listener = new BaseControllerListener {
    @Override
    public void onIntermediateImageSet(String id, @Nullable ImageInfo imageInfo) {
      updateViewSize(imageInfo);
    }

    @Override
    public void onFinalImageSet(String id, @Nullable ImageInfo imageInfo, @Nullable Animatable animatable) {
      updateViewSize(imageInfo);
    }
  };

DraweeController controller = draweeControllerBuilder
  .setUri(uri)
  .setControllerListener(listener)
  .build();
draweeView.setController(controller);

私は頭のてっぺんからこのコードを書きましたが、実際にはテストしていません。しかし、アイデアは明確でなければならず、わずかな調整で機能するはずです。

35
plamenko

@plamenkoの回答に基づいて、次のようにカスタムビューを作成しました。

/**
 * Works when either height or width is set to wrap_content
 * The view is resized based on the image fetched
 */
public class WrapContentDraweeView extends SimpleDraweeView {

    // we set a listener and update the view's aspect ratio depending on the loaded image
    private final ControllerListener listener = new BaseControllerListener<ImageInfo>() {
        @Override
        public void onIntermediateImageSet(String id, @Nullable ImageInfo imageInfo) {
            updateViewSize(imageInfo);
        }

        @Override
        public void onFinalImageSet(String id, @Nullable ImageInfo imageInfo, @Nullable Animatable animatable) {
            updateViewSize(imageInfo);
        }
    };

    public WrapContentDraweeView(Context context, GenericDraweeHierarchy hierarchy) {
        super(context, hierarchy);
    }

    public WrapContentDraweeView(Context context) {
        super(context);
    }

    public WrapContentDraweeView(Context context, AttributeSet attrs) {
        super(context, attrs);
    }

    public WrapContentDraweeView(Context context, AttributeSet attrs, int defStyle) {
        super(context, attrs, defStyle);
    }

    public WrapContentDraweeView(Context context, AttributeSet attrs, int defStyleAttr, int defStyleRes) {
        super(context, attrs, defStyleAttr, defStyleRes);
    }

    @Override
    public void setImageURI(Uri uri, Object callerContext) {
        DraweeController controller = ((PipelineDraweeControllerBuilder)getControllerBuilder())
                .setControllerListener(listener)
                .setCallerContext(callerContext)
                .setUri(uri)
                .setOldController(getController())
                .build();
        setController(controller);
    }

    void updateViewSize(@Nullable ImageInfo imageInfo) {
        if (imageInfo != null) {
            setAspectRatio((float) imageInfo.getWidth() / imageInfo.getHeight());
        }
    }
}

このクラスをXMLに含めることができます。これは、使用例です。

<com.example.ui.views.WrapContentDraweeView
    Android:id="@+id/simple_drawee_view"
    Android:layout_width="match_parent"
    Android:layout_height="wrap_content"
    />
26
vedant

Kotlinでは、次のようなものを試すことができます:

       val listener = object : BaseControllerListener<ImageInfo>() {
        override fun onFinalImageSet(id: String?, imageInfo: ImageInfo?, animatable: Animatable?) {
            super.onFinalImageSet(id, imageInfo, animatable)
            itemView.draweeGif.layoutParams.height = ViewGroup.LayoutParams.WRAP_CONTENT
            itemView.draweeGif.aspectRatio = (imageInfo?.width?.toFloat() ?: 0.toFloat()) / (imageInfo?.height?.toFloat() ?: 0.toFloat())
        }
    }

    val controller = Fresco.newDraweeControllerBuilder()
        .setUri(uriGif)
        .setControllerListener(listener)
        .setAutoPlayAnimations(true)
        .build()
    itemView.draweeGif.controller = controller

私にとっては、ViewHolderでlayoutParamsを直接設定しようとしていたため、RecyclerViewのソリューションでした。

0
Jéwôm'

updateWrapSizeonFinalImageSetを呼び出します

void updateWrapSize(@Nullable ImageInfo imageInfo) {
        if (imageInfo != null) {
            boolean wrapH = getLayoutParams().height == ViewGroup.LayoutParams.WRAP_CONTENT;
            boolean wrapW = getLayoutParams().width == ViewGroup.LayoutParams.WRAP_CONTENT;
            if (wrapH || wrapW) {
                if (wrapW && !wrapH) {
                    getLayoutParams().width = (int) (imageInfo.getWidth() * (float) getLayoutParams().height / imageInfo.getHeight());
                } else if (wrapH && !wrapW) {
                    getLayoutParams().height = (int) (imageInfo.getHeight() * (float) getLayoutParams().width / imageInfo.getWidth());
                } else {
                    getLayoutParams().width = ViewGroup.LayoutParams.WRAP_CONTENT;
                    getLayoutParams().height = ViewGroup.LayoutParams.WRAP_CONTENT;
                }
                setAspectRatio((float) imageInfo.getWidth() / imageInfo.getHeight());
            }
        }
    }
0
legendmohe

SimpleDraweeViewを拡張して解決策を見つけました。これにより、wrap_contentを使用できるようになり、問題なく動作します。 setContentViewでサイズを設定できず、プレビューが機能しない場合でも、この回答を編集して修正できれば幸いです。

使用法

<com.gazman.WrapContentDraweeView 
          Android:id="@+id/myImage"
          Android:layout_width="wrap_content"
          Android:layout_height="wrap_content"
          fresco:placeholderImage="@mipmap/myImage"/>

ソースコード

public class WrapContentDraweeView extends SimpleDraweeView {

    private int outWidth;
    private int outHeight;

    public WrapContentDraweeView(Context context, GenericDraweeHierarchy hierarchy) {
        super(context, hierarchy);
    }

    public WrapContentDraweeView(Context context) {
        super(context);
    }

    public WrapContentDraweeView(Context context, AttributeSet attrs) {
        super(context, attrs);
        init(context, attrs);
    }

    public WrapContentDraweeView(Context context, AttributeSet attrs, int defStyle) {
        super(context, attrs, defStyle);
        init(context, attrs);
    }

    public WrapContentDraweeView(Context context, AttributeSet attrs, int defStyleAttr, int defStyleRes) {
        super(context, attrs, defStyleAttr, defStyleRes);
        init(context, attrs);
    }

    private void init(Context context, AttributeSet attrs) {
        if (attrs == null) {
            return;
        }

        TypedArray gdhAttrs = context.obtainStyledAttributes(
                attrs,
                R.styleable.GenericDraweeView);
        try {
            int placeholderId = gdhAttrs.getResourceId(
                    R.styleable.GenericDraweeView_placeholderImage,
                    0);
            if(placeholderId != 0){
                if(isInEditMode()){
                    setImageResource(placeholderId);
                }
                else {
                    loadSize(placeholderId, context.getResources());
                }
            }
        } finally {
            gdhAttrs.recycle();
        }
    }

    private void loadSize(int placeholderId, Resources resources) {
        BitmapFactory.Options options = new BitmapFactory.Options();
        options.inJustDecodeBounds = true;
        BitmapFactory.decodeResource(resources, placeholderId, options);
        outWidth = options.outWidth;
        outHeight = options.outHeight;
    }

    @Override
    public void setLayoutParams(ViewGroup.LayoutParams params) {
        params.width = outWidth;
        params.height = outHeight;
        super.setLayoutParams(params);
    }
}
0
Ilya Gazman