2015-04-07 45 views
0

概述: 我有不同类型的行的列表视图,包括不同高度的图像和文本。在运行时,我试图根据行的宽度动态设置包含图像的布局的高度。所以行的宽度设置为match_parent(因为我们希望它填充设备的宽度),但高度必须在运行时计算以获得帧的特定长宽比。动态调整列表视图行的大小

下面是来自适配器的代码片段,我使用:

@Override 
public View getView(View convertView) { 
    if (convertView == null) { 
     convertView = LayoutInflater.from(mContext).inflate(
       R.layout.chat_row_image, null); 
     holder = new ViewHolder(convertView); 

     convertView.setTag(holder); 
    } else { 
     holder = (ViewHolder) convertView.getTag(); 
    } 

    ViewTreeObserver observer = holder.videoFrame.getViewTreeObserver(); 
    observer.addOnGlobalLayoutListener(new ViewTreeObserver.OnGlobalLayoutListener() { 

     @Override 
     public void onGlobalLayout() { 
      // TODO Auto-generated method stub 
      frameWidth = holder.container.getWidth(); 
      int width = frameWidth; 
      int height = (int) (frameWidth/Utilities.MEDIA_CELL_ASPECT_RATIO); 

      Log.d(TAG, "Calculated : " + width + "," + height); 

      FrameLayout.LayoutParams params = new FrameLayout.LayoutParams(width, height); 
      holder.messageImage.setLayoutParams(params); 
      holder.videoFrame.getViewTreeObserver().removeGlobalOnLayoutListener(
        this); 
      Log.d(TAG, "Imageview : " + holder.messageImage.getWidth() + "," + holder.messageImage.getHeight()); 
     } 
    }); 
    return convertView; 
} 

问题:此代码的工作很好,但通过滚动的ListView中,但是也有一些容易察觉UI毛刺。主要的UI错误是行从XML文件中有一个预先定义的高​​度,并且在图像加载完成后立即过渡到我们计算出的新高度。这会导致该行下方的整个内容在该行出现在屏幕上时突然移位。此外,我们从底部滚动到顶部(这是一个聊天线程)。

事情我已经尝试:

  1. 我们试图通过“为setSelection”的方法(从ListView中)到用户看到他们“预加载”内容之前通过整个ListView的滚动。这不起作用,它似乎不像图像在我们滚过它们的短暂时间内加载。

  2. 我们已经尝试设置静态XML文件的宽度和高度,并解决了问题,但没有考虑到不同的屏幕尺寸。

我需要什么帮助:我们要保持滚动平滑甚至在动态调整布局。最后的办法是为每个屏幕尺寸类别创建不同的XML文件,并对高度进行硬编码,但这并不能保证我们的帧长宽比符合我们的要求。

请让我知道是否有任何澄清你想要的。提前致谢!

+0

它看起来像你可以直接设置你的布局参数,没有你的全局布局侦听器,并调用convertView.requestLayout() –

+0

谢谢!这当然激发了我一个想法,即不使用全局布局侦听器,并在膨胀视图之后立即设置值。我将在下面的答案中对此进行扩展 –

回答

3

答案是设置帧的尺寸的构造适配器而不是getView()方法。根据Nannuo Lei的建议,我们没有使用ViewTreeObserver.OnGlobalLayoutListener(),而是根据显示器的宽度和其他布局元素的填充/边距来计算帧的尺寸。

public ImageChatRow(Context context) { 
     this.mContext = context; 
     WindowManager wm = (WindowManager) context.getSystemService(Context.WINDOW_SERVICE); 
     Display display = wm.getDefaultDisplay(); 
     Point size = new Point(); 
     display.getSize(size); 
     displayWidth = size.x - 40; //padding is 40 in our case 
     displayHeight = (int) (displayWidth/Utilities.MEDIA_CELL_ASPECT_RATIO); 
    } 

然后在getView()方法,我们只是在充气后视图直接设置在框架的尺寸。

public View getView(View convertView) { 
     if (convertView == null) { 
      convertView = LayoutInflater.from(mContext).inflate(
        R.layout.chat_row, null); 
      holder = new ViewHolder(convertView); 

      LinearLayout.LayoutParams layoutParams = new LinearLayout.LayoutParams(displayWidth, displayHeight); 
      layoutParams.gravity = Gravity.CENTER; 
      holder.frame.setLayoutParams(layoutParams); 

      convertView.setTag(holder); 
     } else 
      holder = (ViewHolder) convertView.getTag(); 

这样可以解决加载行和动态设置高度时的毛刺问题。自实施此代码以来,我们没有在ScrollView中观察到任何跳动!

0

您可以外面添加的LinearLayout在chat_row_image.xml,这样

<RelativeLayout 
    android:layout_width="wrap_content" 
    android:layout_height="wrap_content"> 
    <LinearLayout 
     android:id="@+id/layout_ll 
     android:layout_width="wrap_content" 
     android:layout_height="wrap_content"> 
     [...] 
    </LinearLayout> 
</RelativeLayout> 

在Adapter.java

@Override 
public View getView(View convertView) { 
    if (convertView == null) { 
     convertView = LayoutInflater.from(mContext).inflate(
      R.layout.chat_row_image, null); 
     holder = new ViewHolder(convertView); 
     LinearLayout ll = (LinearLayout) view.findViewById(R.id.layout_ll); 
     LayoutParams linearParams = (LayoutParams) ll.getLayoutParams(); 
     linearParams.width = width; 
     linearParams.height = height; 
     ll.setLayoutParams(linearParams); 

     convertView.setTag(holder); 
    } else { 
     holder = (ViewHolder) convertView.getTag(); 
    } 

    return convertView; 
}