8

У меня есть список сообщений, и большинство из них - это картинки (просто поместите его в сообщения, подобные G + или FB-приложениям). Каждая запись имеет соотношение сторон изображения, поэтому я могу установить высоту изображения на основе ее ширины даже до того, как изображение было загружено с сервера, поэтому макет карты не изменился при загрузке.Получить ширину CardView в Adapter.onBindViewHolder

Проблема layout_width="match_parent" комплект как для изображения карточки и сообщения. Когда я получаю ширину карты, она равна нулю. Поэтому я не могу рассчитать высоту.

В настоящее время единственным решением, которое я вижу, является получение ширины родительского контейнера (RecyclerView) и вычитание всех прокладок, но это не похоже на хорошее решение.

Есть ли другой способ сделать это?

Вот пример кода адаптера

@Override 
public void onBindViewHolder(ViewHolder holder, int position) { 
    .... 
    int width = holder.itemView.getWidth(); 
    .... 
    //do some calculations 
} 

раскладок (без неуместных деталей)

<?xml version="1.0" encoding="utf-8"?> 
<android.support.v7.widget.CardView xmlns:android="http://schemas.android.com/apk/res/android" 
    xmlns:card_view="http://schemas.android.com/apk/res-auto" 
    android:id="@+id/card" 
    android:layout_width="match_parent" 
    android:layout_height="match_parent" 
    android:descendantFocusability="blocksDescendants" 
    android:foreground="?android:attr/selectableItemBackground" 
    card_view:cardBackgroundColor="#ffffff" 
    card_view:cardCornerRadius="3dp"> 

    <RelativeLayout xmlns:android="http://schemas.android.com/apk/res/android" 
     android:layout_width="match_parent" 
     android:layout_height="wrap_content"> 

     <include 
      android:id="@+id/includedPost" 
      layout="@layout/post_details" />  
    </RelativeLayout> 
</android.support.v7.widget.CardView> 

includedPost:

<?xml version="1.0" encoding="utf-8"?> 
<RelativeLayout xmlns:android="http://schemas.android.com/apk/res/android" 
    xmlns:app="http://schemas.android.com/apk/res-auto" 
    android:layout_width="match_parent" 
    android:layout_height="wrap_content"> 
    <ImageView 
     android:id="@+id/postImage" 
     android:layout_width="match_parent" 
     android:layout_height="wrap_content" 
     android:layout_below="@+id/commenterImage" 
     android:minHeight="120dp" 
     android:scaleType="centerCrop" /> 

</RelativeLayout> 
+1

Можете ли вы поместить часть кода, где вы вызываете метод getWidth (с результатом 0)? –

+0

Обновлен мой вопрос с образцом кода – Andrew

+1

Возможно, вы могли бы попытаться вызвать метод getWidth() в [onViewAttachedToWindow] (https://developer.android.com/reference/android/support/v7/widget/RecyclerView.Adapter.html#onViewAttachedToWindow (VH)) в соответствии с документом: «Это можно использовать в качестве разумного сигнала, что вид должен быть замечен пользователем» –

ответ

7

когда onBind или onViewAttachedToWindow называется, ребенок еще не измеряется так что вы не может получить ширину. Даже если эти звонки были сделаны после измерения ребенка, то, что вы пытаетесь сделать, не будет хорошей практикой, потому что изменение высоты потребует нового измерения.

Если вы используете LinearLayoutManager, он даст полную ширину ребенку (ожидайте отладку RecyclerView и поля ребенка). Это не здорово, но ОК, чтобы получить оттуда свой рост.

Другой (более гибкий) подход заключается в создании пользовательского ImageView, который поддерживает соотношение сторон. Когда вызывается onBind, вы зададите желаемый формат изображения своего пользовательского ImageView. Когда вызывается измерение, оно будет измеряться в зависимости от вашего соотношения сторон.

class MyImageView extends ImageVIew { 
     .... 
     private float mScale = 1f; 

     public void setScale(int scale) { 
      mScale = scale; 
     } 

     @Override 
     protected void onMeasure(int widthMeasureSpec, int heightMeasureSpec) { 

      super.onMeasure(widthMeasureSpec, heightMeasureSpec); 

      int width = getMeasuredWidth(); 
      setMeasuredDimension(width, width * mScale); 
     } 
} 

Так что в вашем onBind метода вы звоните setScale на ImageView в зависимости от вашего соотношения веса/ч.

Я не тестировал, но этот подход должен работать по своему желанию.

+0

Блестяще! Оно работает. – Andrew

+0

действительно блестящий, но setMeasuredDimension немного запутанный в вашем примере: int width = getMeasuredWidth(); int height = getMeasuredHeight(); setMeasuredDimension ((int) (ширина * mScale), высота); – cinatic

0

Вы можете использовать преобразование Пикассо для достижения этой цели.

FitToTargetViewTransformation класс:

import android.graphics.Bitmap; 
import android.view.View; 

import com.squareup.picasso.Transformation; 

/** 
* Picasso Transformation class to fit image to target View size 
*/ 
public class FitToTargetViewTransformation implements Transformation { 
    private View view; 

    public FitToTargetViewTransformation(View view) { 
    this.view = view; 
    } 

    @Override 
    public Bitmap transform(Bitmap source) { 
    int targetWidth = view.getWidth(); 

    double aspectRatio = (double) source.getHeight()/(double) source.getWidth(); 
    int targetHeight = (int) (targetWidth * aspectRatio); 
    if (source.getHeight() >= source.getWidth()) { 
     return source; 
    } 
    Bitmap result = Bitmap.createScaledBitmap(source, targetWidth, targetHeight, false); 
    if (result != source) { 
     // Same bitmap is returned if sizes are the same 
     source.recycle(); 
    } 
    return result; 
    } 

    @Override 
    public String key() { 
    return "transformation" + " desiredWidth"; 
    } 
} 

И где-то в onBindViewHolder вы делаете что-то вроде этого:

Picasso.with(context) 
    .load(AVATAR_ENDPOINT) 
    .transform(new FitToTargetViewTransformation(feedViewHolder.icAvatar)) 
    .into(feedViewHolder.icAvatar); 
+0

Я не верю, что это решает мою проблему. У меня нет проблем с масштабированием изображений. Моя проблема - размер настроек ImageView перед загрузкой изображения, чтобы предотвратить дальнейшие изменения размеров карточек при загрузке некоторых изображений. – Andrew