Fix AsyncDrawable display when it has placeholder with empty bounds
This commit is contained in:
parent
c939c0fa5c
commit
33701a179f
@ -1,5 +1,10 @@
|
||||
# Changelog
|
||||
|
||||
# 4.2.2-SNAPSHOT
|
||||
* Fixed `AsyncDrawable` display when it has placeholder with empty bounds ([#189])
|
||||
|
||||
[#189]: https://github.com/noties/Markwon/issues/189
|
||||
|
||||
# 4.2.1
|
||||
* Fix SpannableBuilder `subSequence` method
|
||||
* Introduce Nougat check in `BulletListItemSpan` to position bullet (for bullets to be
|
||||
|
@ -8,7 +8,7 @@ android.enableJetifier=true
|
||||
android.enableBuildCache=true
|
||||
android.buildCacheDir=build/pre-dex-cache
|
||||
|
||||
VERSION_NAME=4.2.1
|
||||
VERSION_NAME=4.2.2-SNAPSHOT
|
||||
|
||||
GROUP=io.noties.markwon
|
||||
POM_DESCRIPTION=Markwon markdown for Android
|
||||
|
@ -164,21 +164,45 @@ public class AsyncDrawable extends Drawable {
|
||||
@SuppressWarnings("WeakerAccess")
|
||||
protected void setPlaceholderResult(@NonNull Drawable placeholder) {
|
||||
// okay, if placeholder has bounds -> use it, otherwise use original imageSize
|
||||
|
||||
final Rect rect = placeholder.getBounds();
|
||||
|
||||
if (rect.isEmpty()) {
|
||||
// if bounds are empty -> just use placeholder as a regular result
|
||||
DrawableUtils.applyIntrinsicBounds(placeholder);
|
||||
setResult(placeholder);
|
||||
} else {
|
||||
// it's important to NOT pass to imageSizeResolver when placeholder has bounds
|
||||
// this is done, so actual result and placeholder can have _different_
|
||||
// bounds. Assume image is loaded with HTML and has ImageSize width=100%,
|
||||
// so, even if placeholder has exact bounds, it will still be scaled up.
|
||||
|
||||
// this condition should not be true for placeholder (at least for now)
|
||||
// (right now this method is always called from constructor)
|
||||
if (result != null) {
|
||||
// but it is, unregister current result
|
||||
result.setCallback(null);
|
||||
}
|
||||
|
||||
final Rect rect = placeholder.getBounds();
|
||||
|
||||
if (rect.isEmpty()) {
|
||||
// check for intrinsic bounds
|
||||
final Rect intrinsic = DrawableUtils.intrinsicBounds(placeholder);
|
||||
if (intrinsic.isEmpty()) {
|
||||
// @since 4.2.2.-SNAPSHOT
|
||||
// if intrinsic bounds are empty, use _any_ non-empty bounds,
|
||||
// they must be non-empty so when result is obtained - proper invalidation will occur
|
||||
// (0, 0, 1, 0) is still considered empty
|
||||
placeholder.setBounds(0, 0, 1, 1);
|
||||
} else {
|
||||
// use them
|
||||
placeholder.setBounds(intrinsic);
|
||||
}
|
||||
|
||||
// it is very important (if we have a placeholder) to set own bounds to it (and they must not be empty
|
||||
// otherwise result won't be rendered)
|
||||
// @since 4.2.2-SNAPSHOT
|
||||
setBounds(placeholder.getBounds());
|
||||
setResult(placeholder);
|
||||
|
||||
} else {
|
||||
|
||||
// this method is not the same as above, as we do not want to trigger image-size-resolver
|
||||
// in case when placeholder has exact bounds
|
||||
|
||||
// placeholder has bounds specified -> use them until we have real result
|
||||
this.result = placeholder;
|
||||
this.result.setCallback(callback);
|
||||
|
@ -4,6 +4,7 @@ import android.graphics.Canvas;
|
||||
import android.graphics.ColorFilter;
|
||||
import android.graphics.Rect;
|
||||
import android.graphics.drawable.Drawable;
|
||||
|
||||
import androidx.annotation.NonNull;
|
||||
import androidx.annotation.Nullable;
|
||||
|
||||
@ -18,7 +19,12 @@ import static org.junit.Assert.assertFalse;
|
||||
import static org.junit.Assert.assertNotNull;
|
||||
import static org.junit.Assert.assertNull;
|
||||
import static org.junit.Assert.assertTrue;
|
||||
import static org.mockito.ArgumentMatchers.any;
|
||||
import static org.mockito.Mockito.mock;
|
||||
import static org.mockito.Mockito.never;
|
||||
import static org.mockito.Mockito.times;
|
||||
import static org.mockito.Mockito.verify;
|
||||
import static org.mockito.Mockito.when;
|
||||
|
||||
@RunWith(RobolectricTestRunner.class)
|
||||
@Config(manifest = Config.NONE)
|
||||
@ -78,6 +84,123 @@ public class AsyncDrawableTest {
|
||||
assertNotNull(result2.getCallback());
|
||||
}
|
||||
|
||||
@Test
|
||||
public void placeholder_no_bounds_no_intrinsic_bounds() {
|
||||
// when there is a placeholder and its
|
||||
// * bounds are empty
|
||||
// * intrinsic bounds are empty
|
||||
// AsyncDrawable.this must have any non-empty bounds (otherwise result won't be rendered,
|
||||
// due to missing invalidation call)
|
||||
|
||||
final Drawable placeholder = new AbstractDrawable() {
|
||||
@Override
|
||||
public int getIntrinsicWidth() {
|
||||
return 0;
|
||||
}
|
||||
|
||||
@Override
|
||||
public int getIntrinsicHeight() {
|
||||
return 0;
|
||||
}
|
||||
};
|
||||
|
||||
assertTrue(placeholder.getBounds().isEmpty());
|
||||
|
||||
final AsyncDrawableLoader loader = mock(AsyncDrawableLoader.class);
|
||||
when(loader.placeholder(any(AsyncDrawable.class))).thenReturn(placeholder);
|
||||
|
||||
final AsyncDrawable drawable = new AsyncDrawable(
|
||||
"",
|
||||
loader,
|
||||
mock(ImageSizeResolver.class),
|
||||
null
|
||||
);
|
||||
|
||||
final Rect bounds = drawable.getBounds();
|
||||
assertFalse(bounds.toShortString(), bounds.isEmpty());
|
||||
assertEquals(bounds.toShortString(), bounds, placeholder.getBounds());
|
||||
}
|
||||
|
||||
@Test
|
||||
public void placeholder_no_bounds_has_intrinsic() {
|
||||
// placeholder has no bounds, but instead has intrinsic bounds
|
||||
|
||||
final Drawable placeholder = new AbstractDrawable() {
|
||||
@Override
|
||||
public int getIntrinsicWidth() {
|
||||
return 42;
|
||||
}
|
||||
|
||||
@Override
|
||||
public int getIntrinsicHeight() {
|
||||
return 24;
|
||||
}
|
||||
};
|
||||
|
||||
assertTrue(placeholder.getBounds().isEmpty());
|
||||
|
||||
final AsyncDrawableLoader loader = mock(AsyncDrawableLoader.class);
|
||||
when(loader.placeholder(any(AsyncDrawable.class))).thenReturn(placeholder);
|
||||
|
||||
final AsyncDrawable drawable = new AsyncDrawable(
|
||||
"",
|
||||
loader,
|
||||
mock(ImageSizeResolver.class),
|
||||
null
|
||||
);
|
||||
|
||||
final Rect bounds = drawable.getBounds();
|
||||
assertFalse(bounds.isEmpty());
|
||||
assertEquals(0, bounds.left);
|
||||
assertEquals(42, bounds.right);
|
||||
assertEquals(0, bounds.top);
|
||||
assertEquals(24, bounds.bottom);
|
||||
|
||||
assertEquals(bounds, placeholder.getBounds());
|
||||
}
|
||||
|
||||
@Test
|
||||
public void placeholder_has_bounds() {
|
||||
|
||||
final Rect rect = new Rect(0, 0, 12, 99);
|
||||
final Drawable placeholder = mock(Drawable.class);
|
||||
when(placeholder.getBounds()).thenReturn(rect);
|
||||
|
||||
assertFalse(rect.isEmpty());
|
||||
|
||||
final AsyncDrawableLoader loader = mock(AsyncDrawableLoader.class);
|
||||
when(loader.placeholder(any(AsyncDrawable.class))).thenReturn(placeholder);
|
||||
|
||||
final AsyncDrawable drawable = new AsyncDrawable(
|
||||
"",
|
||||
loader,
|
||||
mock(ImageSizeResolver.class),
|
||||
null
|
||||
);
|
||||
|
||||
final Rect bounds = drawable.getBounds();
|
||||
assertEquals(rect, bounds);
|
||||
|
||||
verify(placeholder, times(1)).getBounds();
|
||||
verify(placeholder, never()).getIntrinsicWidth();
|
||||
verify(placeholder, never()).getIntrinsicHeight();
|
||||
verify(placeholder, never()).setBounds(any(Rect.class));
|
||||
}
|
||||
|
||||
@Test
|
||||
public void no_placeholder_empty_bounds() {
|
||||
// when AsyncDrawable has no placeholder, then its bounds must be empty at the start
|
||||
|
||||
final AsyncDrawable drawable = new AsyncDrawable(
|
||||
"",
|
||||
mock(AsyncDrawableLoader.class),
|
||||
mock(ImageSizeResolver.class),
|
||||
null
|
||||
);
|
||||
|
||||
assertTrue(drawable.getBounds().isEmpty());
|
||||
}
|
||||
|
||||
private static class AbstractDrawable extends Drawable {
|
||||
|
||||
@Override
|
||||
|
@ -2,6 +2,8 @@ package io.noties.markwon.sample.recycler;
|
||||
|
||||
import android.app.Activity;
|
||||
import android.content.Context;
|
||||
import android.graphics.drawable.ColorDrawable;
|
||||
import android.graphics.drawable.Drawable;
|
||||
import android.net.Uri;
|
||||
import android.os.Bundle;
|
||||
import android.text.TextUtils;
|
||||
@ -27,7 +29,12 @@ import io.noties.markwon.MarkwonConfiguration;
|
||||
import io.noties.markwon.MarkwonVisitor;
|
||||
import io.noties.markwon.core.CorePlugin;
|
||||
import io.noties.markwon.html.HtmlPlugin;
|
||||
import io.noties.markwon.image.AsyncDrawable;
|
||||
import io.noties.markwon.image.ImagesPlugin;
|
||||
import io.noties.markwon.image.file.FileSchemeHandler;
|
||||
import io.noties.markwon.image.network.OkHttpNetworkSchemeHandler;
|
||||
import io.noties.markwon.image.picasso.PicassoImagesPlugin;
|
||||
import io.noties.markwon.image.svg.SvgMediaDecoder;
|
||||
import io.noties.markwon.recycler.MarkwonAdapter;
|
||||
import io.noties.markwon.recycler.SimpleEntry;
|
||||
import io.noties.markwon.recycler.table.TableEntry;
|
||||
@ -74,13 +81,14 @@ public class RecyclerActivity extends Activity {
|
||||
private static Markwon markwon(@NonNull Context context) {
|
||||
return Markwon.builder(context)
|
||||
.usePlugin(CorePlugin.create())
|
||||
// .usePlugin(ImagesPlugin.create(plugin -> {
|
||||
// plugin
|
||||
// .addSchemeHandler(FileSchemeHandler.createWithAssets(context))
|
||||
// .addSchemeHandler(OkHttpNetworkSchemeHandler.create())
|
||||
// .addMediaDecoder(SvgMediaDecoder.create());
|
||||
// }))
|
||||
.usePlugin(PicassoImagesPlugin.create(context))
|
||||
.usePlugin(ImagesPlugin.create(plugin -> {
|
||||
plugin
|
||||
.addSchemeHandler(FileSchemeHandler.createWithAssets(context))
|
||||
.addSchemeHandler(OkHttpNetworkSchemeHandler.create())
|
||||
.addMediaDecoder(SvgMediaDecoder.create())
|
||||
.placeholderProvider(drawable -> new ColorDrawable(0xFFff0000));
|
||||
}))
|
||||
// .usePlugin(PicassoImagesPlugin.create(context))
|
||||
// .usePlugin(GlideImagesPlugin.create(context))
|
||||
// .usePlugin(CoilImagesPlugin.create(context))
|
||||
// important to use TableEntryPlugin instead of TablePlugin
|
||||
|
Loading…
x
Reference in New Issue
Block a user