2015-08-26 12 views
15

Gibt es eine Möglichkeit, Glide zu verwenden, um einen Platzhalter zuzuweisen, aber dieses Bild auf seiner ursprünglichen Skala beibehalten? Ich habe eine ImageView mit variabler Größe (abhängig von der eingehenden Bild), die ich vor dem Aufruf Glide.with().load().into() eingestellt habe und ich möchte einen Platzhalter dafür verwenden, aber nicht die Größe des PH auf die Größe der ImageView Größe ändern möchte, möchte ich es um seine ursprüngliche Größe zu behalten.Glide: Load Drawable aber nicht skalieren Platzhalter

Bisher konnte ich keinen Weg finden, dies zu tun.

Antwort

11

Re: Gregs comment: Ich gab es einen weiteren Schuss (mit fast einem Jahr zusätzliche XP) und kam mit dieser:

<ImageView android:scaleType="center" ... /> 

ähnlich wie meine anderen Lösung und die folgende Animation Wrapper:

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

Trivial Teile der Implementierungen sind weggelassen, jeder Konstruktor der Klasse initialisiert die Felder von Argumenten. Vollständiger Code verfügbar unter GitHub in TWiStErRob/glide-support.

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

Hinweis, wie die beiden Lösungen:

crossFaded placeholder


Wenn Sie eine ältere Version von Glide (vor 3.8.0) stecken, kann der gleiche Effekt erreicht werden durch benötigen die gleiche Menge an Klassen, aber die Post-3.8.0-Lösung hat eine bessere Trennung von Bedenken und kann in einer Variablen zwischengespeichert werden, um Zuweisungen zu verhindern.

+0

Sehr schön gemacht danke –

+0

Diese Lösung funktioniert für uns auf Android 5.x und darunter. Auf 6 und N sieht es jedoch so aus, als ob sich die PaddingAnimation nicht wie erwartet verhält, und wir sehen erneut, wie der Platzhalter für Verhalten während des Übergangs in die centerCrop-Ansicht wächst. Wir werden recherchieren, aber wenn irgendjemand sonst den Fehler auf 6 & N gesehen hat, würde ich gerne irgendwelche Lösungen finden. –

+0

@JakeHall können Sie bitte eine Bildschirmkappe davon teilen? Sieht InsetDrawable wie erwartet aus, wenn es in einem eigenständigen ImageView verwendet wird? Ist es möglich, dass Ihr Platzhalter zwischen diesen Versionen inkonsistente Größen hat (d. H. Neuere Version -> höhere dpi -> anderes Asset). Ich denke, die Mathematik und "scaleType = center" funktioniert nur, wenn der Platzhalter kleiner als die Ansicht/voll geladene Ressource ist; Beachten Sie, dass padXY zum Beispiel negativ werden kann. – TWiStErRob

13

Es gibt eine known Glide issue of placeholders distorting loaded images and vice versa. Ich denke jedoch, dass Sie davon nicht betroffen sind.

Es klingt, als ob Sie den Platzhalter mit scaleType="center" anzeigen möchten und das geladene Bild scaleType="fitCenter" sein soll. Hier ist, wie Sie das in Glide ausdrücken. In android:scaleType="center" im XML und verwenden Sie die folgende Glide Lastlinie:

Glide.with(...).load(...).placeholder(R.drawable....).fitCenter().into(imageView); 

Der Trick ist, dass der Platzhalter über setImageDrawable() so eingestellt ist, die Image wird es wie gewohnt angezeigt werden, aber Sie sagen Glide die FitCenter explizit zu verwenden, die wird das geladene Bild über eine Transformation in die Größe des ImageView-Layouts passen und dann über setImageDrawable() einstellen. Da das angepasste Bild perfekt passt, zeichnet center nur das Bild, das den gesamten Bereich der Ansicht abdeckt.

Sie können .centerCrop() auch auf die gleiche Weise verwenden.

Wenn etwas nicht stimmt, können Sie versuchen .asBitmap() und .dontAnimate(), sie helfen die meiste Zeit auf die eine oder andere Weise.

+0

Problem mit dieser Lösung: Während es scheint zunächst zu arbeiten, Bekanntmachung Während des Übergangs, wenn Glide den Platzhalter auf das reale Bild überblendet, wird das Platzhalterbild auf fitCenter hochskaliert. Dies ist ein großes Problem, da ich diesen Überblendungsübergang hier beibehalten möchte. DontAnimate() vereitelt den Zweck, dies zu versuchen. Irgendwelche Ideen? –

+0

@GregEnnis siehe neue Antwort: http://StackOverflow.com/a/36944010/253468 – TWiStErRob

+0

Vielen Dank für diese Antwort. Es ist eine ziemlich einfache Problemumgehung! – artman

2

ich es unten erwähnt wie:

Die Idee ist, den Maßstab Typen einzustellen, wie durch den Platzhalter erforderlich zunächst & Hörer befestigen wieder die Tonleiter zu ändern, wie durch das heruntergeladene Bild nach dem Bild erforderlich wird heruntergeladen.

//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); 

Mein Übergang ziehbar (R.drawable.anim_image_placeholder):

(nicht erforderlich, wenn ein statisches Bild mit)

<?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> 
+0

Ihre Lösung hat mir geholfen –

+0

Es fühlt sich an, als könnten Sie das gleiche Verhalten erreichen, wenn Sie '.animate (android.R.anim.fade_in)' ohne 'scaleType 'Hacks, jedoch habe ich diese Theorie nicht getestet. Ich denke, diese einfache Animation wird funktionieren, weil 'setImageResource' im Wesentlichen die' ImageView' löscht, so dass '.crossFade()' bereits deaktiviert ist und auf Fade-In zurückgreift (siehe 'DrawableCrossFadeFactory.DefaultAnimationFactory' und' DrawableCrossFadeViewAnimation. animieren'). – TWiStErRob