18

我有一堆我想使用 fresco 加载的可绘制对象,我想wrap_content为这些图像使用大小,我怎样才能在 xml 中使用 fresco 来做呢?或者如果 xml 是不可能的,你如何在代码中做到这一点?

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

除非我设置固定大小,否则上述代码不起作用。

4

5 回答 5

41

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

我从头顶写了这段代码,我还没有实际测试过。但是这个想法应该是明确的,并且应该进行细微的调整。

于 2015-12-03T20:12:30.060 回答
28

根据@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"
    />
于 2016-03-28T22:12:49.653 回答
1

在 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

对我来说,这是我的 RecyclerView 中的一个解决方案,因为我希望直接在我的 ViewHolder 中设置 layoutParams。

于 2019-07-10T15:22:16.170 回答
0

调用updateWrapSize_onFinalImageSet

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());
            }
        }
    }
于 2019-12-05T05:33:48.563 回答
0

通过扩展找到了一个解决方案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);
    }
}
于 2015-11-27T11:37:29.693 回答