2015-08-26 26 views
15

有沒有辦法使用Glide分配佔位符,但保持此圖像的原始比例? 我有一個ImageView與我調用Glide.with().load().into()之前設置的可變大小(取決於傳入的圖像),我想爲它使用佔位符,但不希望將PH調整爲ImageView的大小,我希望它保持原來的大小。滑動:加載可繪製但不縮放佔位符

到目前爲止,我找不到辦法做到這一點。

回答

11

回覆:Gregs comment: 我給它一個鏡頭(使用將近一年的額外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 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)); 
    } 
}) 

注意如何兩種解決方案:

crossFaded placeholder


如果你被困在一箇舊版本的Glide(3.8.0之前),相同的效果可以通過實現需要相同數量的類,但3.8.0後解決方案可以更好地分離問題,並且可以緩存在變量中以防止分配。

+0

非常好地完成了謝謝 –

+0

這個解決方案在android 5.x及更低版本上爲我們工作。然而,在6和N上,它看起來像PaddingAnimation的行爲並不像預期的那樣,我們再次看到行爲佔位符在轉換到centerCrop視圖期間增長。我們將進行研究,但如果其他人看到6&N的故障,我很樂意聽到任何解決方案。 –

+0

@JakeHall你能分享一個屏幕截圖嗎?如果在獨立的ImageView中使用,InsetDrawable看起來像你期望的那樣嗎?是否有可能您的佔位符在這些版本之間的尺寸不一致(即新版本 - >更高dpi - >不同資產)。我認爲數學和'scaleType = center'只適用於佔位符小於視圖/滿載資源的情況;請注意,padXY可能會變成負值。 – TWiStErRob

13

有一個known Glide issue of placeholders distorting loaded images and vice versa。不過,我認爲你並未受此影響。

這聽起來像你想要的是顯示佔位符可繪製scaleType="center",你想加載的圖像是scaleType="fitCenter"。這是你在Glide中表達的方式。在XML添加android:scaleType="center"並使用下面的滑翔負載線:

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

的訣竅是佔位符通過setImageDrawable()設置這樣的ImageView只會顯示它像往常一樣,但你告訴滑翔使用FitCenter明確哪些將通過轉換將已加載的圖像很好地適配在ImageView的佈局大小內,然後通過setImageDrawable()進行設置。由於擬合的圖像非常合適,因此center只會繪製覆蓋視圖整個區域的圖像。

你也可以用同樣的方法使用.centerCrop()

如果事情是錯的,你可以嘗試.asBitmap().dontAnimate(),他們幫助大部分時間都在這樣或那樣的。

+0

問題與此解決方案(如果使用的是靜態圖像不是必需的):當最初顯示它的工作,通知在Glide淡入淡出佔位符到真實圖像的過渡期間,佔位符圖像被放大以適應Center。這是一個很大的問題,因爲這是我試圖在這裏保留的淡入淡出過渡。所以dontAnimate()打敗了試圖做到這一點的目的。有任何想法嗎? –

+0

@GregEnnis查看新答案:http://stackoverflow.com/a/36944010/253468 – TWiStErRob

+0

非常感謝您的回答。這是一個非常簡單的解決方法! – artman

2

我不喜歡它提到如下:

的想法是規模型設定所要求的佔位最初&連接監聽器來改變秤的類型再次作爲圖像後,需要通過下載的圖像來被下載。

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

你的解決方案幫了我 –

+0

感覺就像你可以達到相同的行爲,如果你只是做'.animate(android.R.anim.fade_in)'沒有任何'scaleType '黑客,但我沒有測試這個理論。我認爲這個簡單的動畫可以工作,因爲'setImageResource'基本上清除了'ImageView',所以'.crossFade()'已經被禁用了,並且它回退到淡入(參見'DrawableCrossFadeFactory.DefaultAnimationFactory'和'DrawableCrossFadeViewAnimation。 animate')。 – TWiStErRob