Facebook Fresco using wrap_content

前端 未结 5 711
日久生厌
日久生厌 2020-12-05 03:07

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

相关标签:
5条回答
  • 2020-12-05 03:39

    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.

    0 讨论(0)
  • 2020-12-05 03:43

    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());
                }
            }
        }
    
    0 讨论(0)
  • 2020-12-05 03:45

    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.

    0 讨论(0)
  • 2020-12-05 03:47

    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"
        />
    
    0 讨论(0)
  • 2020-12-05 03:52

    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);
        }
    }
    
    0 讨论(0)
提交回复
热议问题