Скольжение: загрузка возможна, но не масштабируется
Есть ли способ использовать Glide для назначения заполнителя, но сохраните это изображение в исходном масштабе?
У меня есть ImageView
с переменным размером (в зависимости от входящего изображения), который я установил перед вызовом Glide.with().load().into()
, и я хочу использовать заполнитель для него, но не хочу, чтобы PH изменялся до размера ImageView
, Я хочу, чтобы он сохранил свой первоначальный размер.
До сих пор я не мог найти способ сделать это.
Ответы
Ответ 1
Re: Комментарий Грега:
Я сделал еще один выстрел (с почти годом дополнительных XP) и придумал это:
<ImageView android:scaleType="center" ... />
аналогично моему другому решению и следующей оболочке анимации:
...
.fitCenter()
.animate(new PaddingAnimationFactory<>(new DrawableCrossFadeFactory<GlideDrawable>(2000)))
.into(imageView)
;
class PaddingAnimationFactory<T extends Drawable> implements GlideAnimationFactory<T> {
private final DrawableCrossFadeFactory<T> realFactory;
@Override public GlideAnimation<T> build(boolean isFromMemoryCache, boolean isFirstResource) {
return new PaddingAnimation<>(realFactory.build(isFromMemoryCache, isFirstResource));
}
}
class PaddingAnimation<T extends Drawable> implements GlideAnimation<T> {
private final GlideAnimation<? super T> realAnimation;
@Override public boolean animate(T current, final ViewAdapter adapter) {
int width = current.getIntrinsicWidth();
int height = current.getIntrinsicHeight();
return realAnimation.animate(current, new PaddingViewAdapter(adapter, width, height));
}
}
class PaddingViewAdapter implements ViewAdapter {
@Override public Drawable getCurrentDrawable() {
Drawable drawable = realAdapter.getCurrentDrawable();
if (drawable != null) {
int padX = Math.max(0, targetWidth - drawable.getIntrinsicWidth()) / 2;
int padY = Math.max(0, targetHeight - drawable.getIntrinsicHeight()) / 2;
if (padX != 0 || padY != 0) {
drawable = new InsetDrawable(drawable, padX, padY, padX, padY);
}
}
return drawable;
}
@Override public void setDrawable(Drawable drawable) {
if (VERSION.SDK_INT >= VERSION_CODES.M && drawable instanceof TransitionDrawable) {
// For some reason padding is taken into account differently on M than before in LayerDrawable
// PaddingMode was introduced in 21 and gravity in 23, I think NO_GRAVITY default may play
// a role in this, but didn't have time to dig deeper than this.
((TransitionDrawable)drawable).setPaddingMode(TransitionDrawable.PADDING_MODE_STACK);
}
realAdapter.setDrawable(drawable);
}
}
Тривиальные части реализации опущены, каждый конструктор классов инициализирует поля из аргументов. Полный код доступен на GitHub в TWiStErRob/glide-support.
![crossFaded placeholder]()
Если вы застряли в более старой версии Glide (до 3.8.0), то такой же эффект можно достичь:
.fitCenter()
.placeholder(R.drawable.glide_placeholder)
.crossFade(2000)
.into(new GlideDrawableImageViewTarget(imageView) {
@Override public void onResourceReady(GlideDrawable resource,
GlideAnimation<? super GlideDrawable> animation) {
super.onResourceReady(resource, new PaddingAnimation<>(animation));
}
})
Обратите внимание, что для двух решений требуется одинаковое количество классов, но решение после 3.8.0 лучше разделяет проблемы и может быть кэшировано в переменной, чтобы предотвратить выделение.
Ответ 2
Там известная проблема Glide заполнителей, искажающих загруженные изображения и наоборот. Однако я думаю, что на вас это не повлияло.
Похоже на то, что вы хотите показать, что местозаполнитель доступен с помощью scaleType="center"
, и вы хотите, чтобы загруженное изображение было scaleType="fitCenter"
. Вот как вы это выражаете в Glide. Добавьте android:scaleType="center"
в XML и используйте следующую строку нагрузки Glide:
Glide.with(...).load(...).placeholder(R.drawable....).fitCenter().into(imageView);
Фокус в том, что placeholder устанавливается через setImageDrawable()
, поэтому ImageView будет просто отображать его, как обычно, но вы говорите Glide, чтобы явно использовать FitCenter
, который будет хорошо вписываться в загруженное изображение в пределах размера изображения ImageView a Трансформация, а затем установите ее через setImageDrawable()
. Так как установленное изображение идеально подходит, center
будет просто рисовать изображение, охватывающее всю область обзора.
Вы также можете использовать .centerCrop()
таким же образом.
Если что-то не так, вы можете попробовать .asBitmap()
и .dontAnimate()
, они помогают большую часть времени тем или иным способом.
Ответ 3
Я делаю это, как указано ниже:
Идея состоит в том, чтобы установить тип шкалы в соответствии с требованиями владельца места на месте и приложить прослушиватель, чтобы снова изменить тип шкалы в соответствии с требованиями загруженного изображения после загрузки изображения.
//ivBuilderLogo = Target ImageView
//Set the scale type to as required by your place holder
//ScaleType.CENTER_INSIDE will maintain aspect ration and fit the placeholder inside the image view
holder.ivBuilderLogo.setScaleType(ImageView.ScaleType.CENTER_INSIDE);
//AnimationDrawable is required when you are using transition drawables
//You can directly send resource id to glide if your placeholder is static
//However if you are using GIFs, it is better to create a transition drawable in xml
//& use it as shown in this example
AnimationDrawable animationDrawable;
if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.LOLLIPOP)
animationDrawable=(AnimationDrawable)context.getDrawable(R.drawable.anim_image_placeholder);
else
animationDrawable=(AnimationDrawable)context.getResources().getDrawable(R.drawable.anim_image_placeholder);
animationDrawable.start();
Glide.with(context).load(logo_url)
.placeholder(animationDrawable)
.listener(new RequestListener<String, GlideDrawable>() {
@Override
public boolean onException(Exception e, String model, Target<GlideDrawable> target, boolean isFirstResource)
{
return false;
}
//This is invoked when your image is downloaded and is ready
//to be loaded to the image view
@Override
public boolean onResourceReady(GlideDrawable resource, String model, Target<GlideDrawable> target, boolean isFromMemoryCache, boolean isFirstResource)
{
//This is used to remove the placeholder image from your ImageView
//and load the downloaded image with desired scale-type(FIT_XY in this case)
//Changing the scale type from 'CENTER_INSIDE' to 'FIT_XY'
//will stretch the placeholder for a (very) short duration,
//till the downloaded image is loaded
//setImageResource(0) removes the placeholder from the image-view
//before setting the scale type to FIT_XY and ensures that the UX
//is not spoiled, even for a (very) short duration
holder.ivBuilderLogo.setImageResource(0);
holder.ivBuilderLogo.setScaleType(ImageView.ScaleType.FIT_XY);
return false;
}
})
.into( holder.ivBuilderLogo);
Мой переходный ресурс (R.drawable.anim_image_placeholder):
(не требуется, если используется статическое изображение)
<?xml version="1.0" encoding="utf-8"?>
<animation-list
xmlns:android="http://schemas.android.com/apk/res/android"
android:oneshot="false">
<item android:drawable="@drawable/loading_frame1" android:duration="100" />
<!--<item android:drawable="@drawable/loading_frame2" android:duration="100" />-->
<item android:drawable="@drawable/loading_frame3" android:duration="100" />
<!--<item android:drawable="@drawable/loading_frame4" android:duration="100" />-->
<item android:drawable="@drawable/loading_frame5" android:duration="100" />
<!--<item android:drawable="@drawable/loading_frame6" android:duration="100" />-->
<item android:drawable="@drawable/loading_frame7" android:duration="100" />
<!--<item android:drawable="@drawable/loading_frame8" android:duration="100" />-->
<item android:drawable="@drawable/loading_frame9" android:duration="100" />
<!--<item android:drawable="@drawable/loading_frame10" android:duration="100" />-->
</animation-list>