Facebook Fresco using wrap_content

fresco android
fresco setimageuri
simpledraweeview android example
fresco example
fresco set drawable
facebook draweeview
fresco scaling
fresco initialize

I got a bunch of drawables that I want to load using fresco, I want to use wrap_content size for those images, how can I do it in xml with fresco? Or if xml is not possible how do you do it in code?

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

The above code is not working unless I set a fixed size.

I am part of the Fresco team and I was the one who made the design decision to not support wrap-content. The rationale is explained in the documentation. But in short, the problem is that you can't guarantee that the image will be available immediately (you may need to fetch it first) and that means that the view size would have to change once the image arrives. This is in most cases not desirable and you should probably rethink your UI.

Anyways, if you really really need/want to do that, you can do it like this:

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

I wrote this code from the top of my head, I haven't actually tested it. But the idea should be clear, and it should work with minor adjustments.

How to use Fresco to fit screen? � Issue #1026 � facebook/fresco , In Android-Universal-Image-Loader,I can use the layout to fit screen width and wrap content height in listview. But it doesn't work in fresco. When using Fresco, you will use SimpleDraweeView to display images. These can be used in XML layouts. The simplest usage example of SimpleDraweeView is:

Based on @plamenko's answer, I made a custom view as follows:

/**
 * 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());
        }
    }
}

You can include this class in the XML, an example usage:

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

facebook/fresco, When using Fresco, you will use SimpleDraweeView to display images. These can be used in XML <com.facebook.drawee.view. NOTE: SimpleDraweeView does not support wrap_content for layout_width or layout_height attributes. I'm using the Fresco library in my app to load images. The problem is that I can't set my images height to "wrap_content" because "wrap_content" is not supported in the Fresco library. So how can I make my images to look good using a DraweeView? I looked here but I couldn't find a solution to this problem : frescolib/wrap_content. For example:

Found a solution by extending SimpleDraweeView, it allows me to use wrap_content and it works just fine! How ever I prevent you from setting the size in setContentView and the preview is not working, I be glad if could edit this answer to fix those.

Usage
<com.gazman.WrapContentDraweeView 
          android:id="@+id/myImage"
          android:layout_width="wrap_content"
          android:layout_height="wrap_content"
          fresco:placeholderImage="@mipmap/myImage"/>
Source code
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);
    }
}

Using SimpleDraweeView, Fresco is a powerful library for displaying images in Android, supporting applications dependencies { implementation 'com.facebook.fresco:fresco:1.10. 0' } Note: DraweeView doesn't support specifying wrap_content for the layout_width or� First, in addition to the normal Fresco Gradle dependency, you have to add the OkHttp 3 dependency to your build.gradle: compile "com.facebook.fresco:imagepipeline-okhttp3:1.2.0" // Or a newer version. When you initialize Fresco (usually in your custom Application implementation), you can now specify your OkHttp client:

In Kotlin you can try something like this :

       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

For me it was a solution in my RecyclerView because I was looking to set the layoutParams directly in my ViewHolder.

Displaying Images with the Fresco Library, I got a bunch of drawables that I want to load using fresco, I want to use wrap_content size for those images, how can I do it in xml with fresco? Or if xml is not� If you are using a recycler view, then match_parent is undefined, so you can't use that. You have to use wrap_content, and then you can rely on the aspect ratio of the image, rather than specifying one yourself.

invoke updateWrapSize in 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());
            }
        }
    }

Facebook Fresco using wrap_content, First, add Fresco to your build.gradle as shown in the Remarks section: Fresco does not support wrap_content for image dimensions since you might have multiple <com.facebook.drawee.view. If you are correctly following the steps from Shipping Your App with Fresco, your release builds should not grow more than 500 KiB when adding Fresco. Adding support for animations ( com.facebook.fresco:animated-gif , com.facebook.fresco:animated-webp ) and WebP on old devices ( com.facebook.fresco:webpsupport ) is optional.

Fresco, clear both memory and disk caches Fresco. How do I use Fresco in a RecyclerView? Why can't I use Android's wrap_content attribute on a DraweeView? Join GitHub today. GitHub is home to over 40 million developers working together to host and review code, manage projects, and build software together.

FAQ, In a recent project development, I used fresco as the image loading engine Loading Use compile 'com.facebook.fresco:animated-webp:1.3.0' The width of SimpleDraweeView cannot be wrap_content at the same time. You can always make your own drawable background for the facebook button and set it as the background of the button. The final thing we do is simply convert the click on my custom button to a click on the facecbook button:

关于android:使用wrap_content的Facebook Fresco,

Comments
  • Tnx for you answer. I recommend you to reconsider your decision regardless wrap content support. In many cases people use drawables assets, those good for static images or some animations. Each application got some of those in one way or another. And it's nice knowing Frasco will take care my memory fear away. You can name it StaticDrawee if it helps.
  • Yeah. In most cases wrap-content should not really be used as there are better alternatives, but then there are always going to be legitimate exceptions. I'll think of how to make this particular flow simpler.
  • offtopic for anyone coming here: If you have a recyclerview with lots of images, you display the full image(in another fragment/fullscreen activity) when the user taps on it, but until then set a fixed size for SimpleDraweeView (I think that's how everybody does it)
  • Uhm, correct me if I'm wrong @plamenko, but this is not suitable for a recyclerview environment, since the draweeView reference can be replaced at any time, even before fresco finishes it's download, so, it wouldn't work.
  • @Ivan, If you mean on the scenario where the view get recycled and the previously set controller listener still holds the reference to that view, this should not be a problem. At the moment you recycle drawee view and set a new controller, the previously set controller will be detached immediately and its listener will receive onRelease and no other event. Since all this happens on the main thread (UI thread), there should be no synchronization issues either.
  • In order for this to work, you need to set either the width or the height, otherwise the aspect ratio is useless. So I don't think this will work, did you tested it?
  • That's exactly what's mentioned in the class description. And I am using it. Works perfectly. Anyway, I edited the answer with the .xml as well
  • It is working for a lot of people. @meysam expand your comment or gist.github.com your code?
  • It's not working for me too. when set android:layout_width="match_parent" android:layout_height="wrap_content" I got only 1 line of 1px. then when I set wrap_content for both the WrapContentDraweeView shows nothing (on fresco 0.14.1)
  • For those who found it not working, make sure you have override the correct setImageUri method. SimpleDraweeView has a number of setImageUri methods but only one of them is actually doing the setController work.
  • Be careful! Potentially you are dividing by zero