Android 使用wrap_内容的Facebook壁画

Android 使用wrap_内容的Facebook壁画,android,facebook,fresco,Android,Facebook,Fresco,我有一堆我想用fresco加载的绘图,我想用wrap\u contentsize来处理这些图像,我怎样才能用fresco在xml中实现呢?或者,如果xml不可能,您如何在代码中实现它 <com.facebook.drawee.view.SimpleDraweeView android:id="@+id/myImage" android:layout_width="wrap_content" android:layout_heigh

我有一堆我想用fresco加载的绘图,我想用
wrap\u content
size来处理这些图像,我怎样才能用fresco在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"/>


除非我设置了一个固定的大小,否则上面的代码不起作用。

通过扩展
SimpleDraweView
找到了一个解决方案,它允许我使用
wrap\u内容
,而且效果很好!无论我如何阻止您在
setContentView
中设置大小,并且预览不起作用,如果您能编辑此答案以修复这些问题,我都会很高兴

用法
我是壁画团队的一员,是我做出了不支持包裹内容的设计决定。其基本原理在本节中进行了解释。但简而言之,问题是您不能保证图像立即可用(您可能需要先获取它),这意味着一旦图像到达,视图大小就必须更改。在大多数情况下,这是不可取的,您可能应该重新考虑您的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);

我是从头开始写这段代码的,实际上我还没有对它进行测试。但是这个想法应该很清楚,并且应该稍加调整。

根据@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());
        }
    }
}

在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
val listener=object:BaseControllerListener(){
覆盖最终图像集(id:String?、imageInfo:imageInfo?、可设置动画:可设置动画?){
super.onFinalImageSet(id、imageInfo、可设置动画)
itemView.PaureGif.layoutParams.height=ViewGroup.layoutParams.WRAP\u内容
itemView.DropeGif.aspectRatio=(imageInfo?.width?.toFloat()?:0.toFloat())/(imageInfo?.height?.toFloat()?:0.toFloat())
}
}
val controller=Fresco.newDraineControllerBuilder()
.setUri(uriGif)
.setControllerListener(侦听器)
.setAutoPlayAnimations(真)
.build()
itemView.drauegif.controller=控制器

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

onFinalImageSet中调用
updateWrapSize

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

Tnx为您解答。无论内容支持如何,我建议您重新考虑您的决定。在许多情况下,人们使用可绘制资源,这些资源适用于静态图像或某些动画。每个应用程序都以这样或那样的方式获得了其中的一些。很高兴知道Frasco会照顾好我的记忆恐惧。如果有帮助的话,你可以把它命名为StaticDrawee。在大多数情况下,不应该真正使用包装内容,因为有更好的替代方案,但总会有合法的例外。我将考虑如何使这个特定的流程更简单。offtopic:如果你有一个包含大量图像的recyclerview,当用户点击它时,你会显示完整的图像(在另一个片段/全屏活动中),但在此之前,为SimpleDraweView设置一个固定的大小(我认为每个人都是这样做的)嗯,如果我错了,请纠正我@plamenko,但这不适用于recyclerview环境,因为DropeReview引用可以随时替换,甚至在fresco完成下载之前,所以它不会工作。@Ivan,如果您的意思是在视图被回收并且之前设置的控制器侦听器仍然保留对该视图的引用的场景中,那么这应该不是问题。在回收抽屉视图并设置新控制器时,先前设置的控制器将立即分离,其侦听器将接收onRelease,而不会接收其他事件。由于所有这些都发生在主线程(UI线程)上,因此也不应该存在同步问题。为了使其正常工作,您需要设置宽度或高度,否则纵横比是无用的。所以我认为这是行不通的,你测试过吗?这正是课堂描述中提到的。我正在使用它。工作完美。不管怎样,我用
.xml
编辑了答案,它也适用于很多人@meysam扩展你的评论或gist.github.com你的代码?它对我也不起作用。当设置android:layout\u width=“match\u parent”android:layout\u height=“wrap\u content”时,我只得到了1行1px。然后,当我为两个WrapContentDraweView设置wrap_内容时,如果发现WrapContentDraweView不工作,请确保覆盖了正确的
setImageUri
方法
SimpleDraweView
有许多
setImageUri
方法,但实际上只有一个方法在执行
setController
工作。小心!可能是被零除
<com.example.ui.views.WrapContentDraweeView
    android:id="@+id/simple_drawee_view"
    android:layout_width="match_parent"
    android:layout_height="wrap_content"
    />
       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
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());
            }
        }
    }