【问题标题】:Resizing ListView Rows Dynamically动态调整 ListView 行的大小
【发布时间】:2015-04-07 00:20:00
【问题描述】:

概述: 我有一个不同类型行的 ListView,包括不同高度的图像和文本。在运行时,我试图根据行的宽度动态设置包含图像的布局的高度。因此行的宽度设置为 match_parent(因为我们希望它填充设备的宽度),但高度必须在运行时计算才能获得帧的特定纵横比。

这是我正在使用的适配器中的代码 sn-p:

@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 文件并对高度进行硬编码,但这不会使我们的框架的纵横比保持我们想要的。

如果您需要任何澄清,请告诉我。提前致谢!

【问题讨论】:

  • 看起来您可以直接设置布局参数,无需全局布局侦听器,然后调用 convertView.requestLayout()
  • 谢谢!这无疑启发了我一个想法,即不使用全局布局侦听器并在膨胀视图后立即设置值。我将在下面的答案中对此进行扩展

标签: android android-layout listview resize android-adapter


【解决方案1】:

答案是在 Adapter 的构造函数中设置框架的尺寸,而不是 getView() 方法。根据 Nannuo Lei 的建议,我们没有使用ViewTreeObserver.OnGlobalLayoutListener(),而是根据显示器的宽度和其他布局元素的 padding/margin 计算框架的尺寸。

 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 中有任何跳跃!

【讨论】:

    【解决方案2】:

    你可以在chat_row_image.xml外面添加一个LinearLayout,像这样

    <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;
    }
    

    【讨论】:

      猜你喜欢
      • 2021-10-12
      • 2011-02-19
      • 2013-10-08
      • 2019-04-07
      • 1970-01-01
      • 2014-03-04
      • 2018-03-17
      • 2012-10-24
      • 2014-03-19
      相关资源
      最近更新 更多