2016-03-15 3 views
3

У меня есть список, отображающий кучу изображений. am using Universal Image Loader чтобы загрузить это изображения из файлов в изображение.Как избежать мерцания изображения в списке просмотров

Эти изображения имеют разные размеры, и я хочу, чтобы все они имели одинаковую ширину, но различную высоту относительно каждого пропорции изображения.

Для достижения этой цели, я попытался установить следующее моей ImageView

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

Проблема этого метод состоит в том, что есть много мерцания, когда один прокручивает ListView, поскольку высота ImageView не известно заранее и изображения сначала нужно масштабировать, используя мою ширину, чтобы рассчитать каждую высоту изображения по отношению к ее формату.

Как я могу рассчитать каждую высоту изображения заблаговременно вместо того, чтобы позволить обработать изображение?

Если у меня есть изображение 400 X 700, и я хочу, чтобы изображение было шириной 300 пикселей, как я могу рассчитать высоту изображения с помощью моего измерения изображения и сохранить соотношение сторон изображения? это может помочь избежать мерцания при прокрутке списка.

+0

Почему бы вам не установить фиксированную высоту тоже? и использовать анимации, как довольно угасать, чтобы сделать ее более сильной? Рацион сохраняется параметром scaleType :) –

+0

@ Ан-дроид я не хочу устанавливать фиксированную высоту. Я пытаюсь добиться того, что изображение делает в фоновом режиме. если вы установите фиксированную ширину и установите высоту на ** wrap content **, она масштабирует изображение и вычисляет высоту. но я хочу рассчитать высоту заранее, чтобы пользователь не увидел этого уродливого изменения размера изображения при прокрутке изображений. –

+0

В хорошо известных приложениях, таких как Spotify, большинство изображенийViews просто устанавливаются с фиксированными размерами или симуляцией и 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

Причина этого мерцания в том, что в списке элементов списка используются повторно. При повторном использовании изображения в элементе списка сохраняют прежнюю ссылку на изображение. Позже, когда загружается новый образ, он начинает показывать. это вызывает мерцающее поведение. Чтобы избежать этой проблесковой проблемы, всегда очищайте старую ссылку на изображение из изображения, когда она используется повторно.

В вашем случае добавьте 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

, это также было одной из проблем **, но я имею в виду **, что когда я прокручиваю вниз, изображение появляется с шириной 400 пикселей и высотой 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); 
Смежные вопросы