2016-03-15 91 views
3

我有一個listivew顯示一堆圖像。我正在使用Universal Image Loader將這些圖像從文件加載到圖像瀏覽。如何避免圖像在列表視圖中閃爍

這個圖像有不同的尺寸,我希望他們所有人都有相同的寬度,但相對於每個圖像寬高比不同的高度。

要做到這一點,我已經嘗試設置下面以我的ImageView

<ImageView 
    android:layout_width = "400dp" 
    android:layout_height="wrap_content" 
    android:scaleType="centerCrop" 
    android:adjustViewBounds="true"/> 

這種方法的問題是,有很多閃爍的,當一個滾動,因爲imageview的高度列表視圖中是不知道先進和圖像必須首先使用我的寬度來計算每個圖像高度的寬高比

如何預先計算每個圖像高度而不是讓imageview處理它?

如果我有一個400×700的圖像,並且我希望imageview的寬度是300px,那麼我如何使用圖像尺寸計算imageview的高度並保持圖像寬高比?這可以幫助避免一個滾動列表視圖閃爍。

+0

你爲什麼不設定一個固定的高度呢?並使用像一個相當淡入的動畫,使其更smoth?配給由scaleType參數保存:) –

+0

@ An-droid我不想設置固定的高度。我正試圖實現imageview在後臺執行的操作。如果您將固定寬度和高度設置爲**包裝內容**,則會縮放圖像並計算高度。但我想提前計算高度,以便用戶在滾動瀏覽圖像時不會看到圖像視圖的醜陋調整大小 –

+0

在像Spotify這樣衆所周知的應用程序中,大多數imageView只是設置了固定大小或匹配以及scaleType設置爲centerCrop。它有什麼作用 ?圖像將填充您提供給它的所有空間,並將根據她的身高按比例調整大小。這是很好的,因爲你不知道哪些設備用戶將使用你的應用程序,密度...使用固定寬度,非常髒和危險我認爲 –

回答

1

後的研究時間,我能知道的方法我可以使用它來計算新的圖像視圖高度,同時保持圖像寬高比。

BitmapFactory.Options options = new BitmapFactory.Options(); 
    options.inJustDecodeBounds = true; 

//Returns null, sizes are in the options variable 
BitmapFactory.decodeFile("/sdcard/image.png", options); 
int width = options.outWidth; 
int height = options.outHeight; 

//calculating image aspect ratio 
float ratio =(float) height/(float) width; 

//calculating my image height since i want it to be 360px wide 
int newHeight = Math.round(ratio*360); 

//setting the new dimentions 
imageview.getLayoutParams().width = 360; 
imageview.getLayoutParams().height = newHeight; 

//i'm using universal image loader to display image 
imaheview.post(new Runnable(){ 
    ImageLoader.getInstance().displayImage(imageuri,imageview,displayoptions); 
}); 
3

這種閃爍的原因是,在列表視圖列表項中被重用。重新使用時,列表項目中的圖像會保留先顯示的舊圖像參考。稍後一旦新圖像下載,它就開始顯示。這會導致閃爍的行爲。 爲避免此閃爍問題,請務必在重新使用時從imageview中清除舊圖像引用。

在你的情況下,添加holder.image.setImageBitmap(null);holder =(ViewHolder)convertView.getTag();

所以,你的getView()方法如下所示:

@Override 
public View getView(final int position, View convertView, ViewGroup parent) { 

    ... 

    if (convertView == null) { 
     LayoutInflater inflater = getLayoutInflater(); 
     convertView = inflater.inflate(viewResourceId, null); 

     holder = new ViewHolder(convertView); 
     convertView.setTag(holder); 
    } else { 
     holder = (ViewHolder) convertView.getTag(); 
     holder.image.setImageBitmap(null) 
    } 

    ... 

    return convertView; 
} 
+0

這也是問題**之一,但我的意思是**,當我向下滾動時,imageview出現寬度爲400px,高度爲0.然後計算高度後,**它突然出現。**我想提前計算高度並將其設置爲圖像視圖以避免**重新調整圖像查看** –

+0

您是否理解我的擔憂? –

+0

'holder.setImageBitmap(null)'與通用圖像加載器中的'.resetViewBeforeLoading(true)'相同DisplayImageOptions() –

0

你可以做這樣的事情:

BitmapFactory.Options options = new BitmapFactory.Options(); 
options.inJustDecodeBounds = true; 

//Returns null, sizes are in the options variable 
BitmapFactory.decodeFile("/sdcard/image.png", options); 
int width = options.outWidth; 
int height = options.outHeight; 
//If you want, the MIME type will also be decoded (if possible) 
String type = options.outMimeType; 
0

我如何解決它是通過創建一個Bitmap[]數組變量存儲圖像,然後在適配器的getView(),我使用時的位置,以檢查是否在Bitmap[]陣列圖像null或具有價值。如果它有價值,那麼我使用該值而不是再次調用new DownloadImageTask()構造。

例如:

YourCustomArrayAdapter.java

public class MyCustomArrayAdapter extends ArrayAdapter { 
    private static Bitmap[] myListViewImageViewsArray = new Bitmap[listViewItemsArray.length]; 
    private String[] myListViewImageURLsArray = new String[listViewItemsArray.length]{ 
     "image_url_1", 
     "image_url_2", 
     ... 
     ... 
    }; 


    @Override 
    public View getView(int position, View view, ViewGroup parent){ 
     CustomViewHolder vHolder; 
     if(view == null){ 
      view = inflater.inflate(R.layout.movies_coming_soon_content_template, null, true); 
      vHolder = new CustomViewHolder(); 
      vHolder.imageView = (AppCompatImageView) view.findViewById(R.id.my_cutom_image); 
      vHolder.imageUrl = ""; 
      view.setTag(vHolder); 
     } 
     else{ 
      vHolder = (CustomViewHolder)view.getTag(); 
      // -- Set imageview src to null or some predefined placeholder (this is not really necessary but it might help just to flush any conflicting data hanging around) 
      vHolder.imageView.setImageResource(null); 
     } 

     // ... 


     // -- THIS IS THE MAIN PART THAT STOPPED THE FLICKERING FOR ME 
     if(myListViewImageViewsArray[position] != null){ 
      vHolder.imageView.setImageBitmap(myListViewImageViewsArray[position]); 
     }else{ 
      new DownloadImageTask(position, vHolder.imageView).execute(vHolder.imageUrl); 
     } 
     // -- END OF THE FLICKERING CONTROL  
    } 
} 

然後,在圖像下載構建體,下載圖像之後,使一個插入Bitmap[]圖像陣列,用於該位置。例如:

YourImageDownloaderClass.java

public class DownloadImageTask extends AsyncTask<String, Void, Bitmap> { 
    AppCompatImageView imageView; 
    int position; 

    public DownloadImageTask(int position, AppCompatImageView imageView){ 
     this.imageView = imageView; 
     this.position = position; 
    } 

    @Override 
    protected Bitmap doInBackground(String...urls) { 

     String urlOfImage = urls[0]; 
     Bitmap logo = null; 
     try{    
      logo = BitmapFactory.decodeStream((InputStream) new URL(urlOfImage).getContent()); 
     }catch(Exception e){ 
      e.printStackTrace();    
     } 
     return logo; 
    } 

    @Override 
    protected void onPostExecute(Bitmap result){ 
     if(result != null) { 
      YourCustomArrayAdapter.myListViewImageViewsArray [position] = result; 
      imageView.setImageBitmap(result);      
     }else{ 
      YourCustomArrayAdapter.myListViewImageViewsArray [position] = null; 
      imageView.setImageResource(null);     
     } 
    } 
} 
+0

感謝編輯@CodyGray。我仍然很新,發佈答案。希望隨着時間的推移,我會變得更好。 –

+0

不用擔心!你的回答已經很有幫助。 [另一個用戶和我](https://stackoverflow.com/posts/45533135/revisions)剛剛清理了一些格式和英語語法。感謝關心這個網站並努力改進! –

0

我的建議是使用網格視圖,以避免圖像的閃爍會在第一次加載如果是相同的URL,它會從緩存中

加載
Glide.with(mContext) 
      .load(item.getImageUrl()) 
      .into(holder.mIVGridPic);