フレスコ画を使用してロードしたいドローアブルがたくさんあります。それらの画像に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"/>
固定サイズを設定しないと、上記のコードは機能しません。
私は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);
私は頭のてっぺんからこのコードを書きましたが、実際にはテストしていません。しかし、アイデアは明確でなければならず、わずかな調整で機能するはずです。
@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"
/>
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のソリューションでした。
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());
}
}
}
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);
}
}