Android 动态调整ListView行的大小

Android 动态调整ListView行的大小,android,android-layout,listview,resize,android-adapter,Android,Android Layout,Listview,Resize,Android Adapter,概述: 我有一个不同类型行的列表视图,包括不同高度的图像和文本。在运行时,我尝试根据行的宽度动态设置包含图像的布局的高度。因此,行的宽度设置为匹配父行,因为我们希望它填充设备的宽度,但必须在运行时计算高度,以获得帧的特定纵横比 下面是我正在使用的适配器的代码片段: @Override public View getView(View convertView) { if (convertView == null) { convertView = LayoutInflater

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

下面是我正在使用的适配器的代码片段:

@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;
}
问题是:这段代码运行得很好,但是在滚动列表视图的过程中,有一些很容易注意到的UI故障。主要的UI错误是,行与XML文件之间有一个预定义的高度,并且在图像加载完成后立即转换到我们计算的新高度。这会导致该行出现在屏幕上时,该行下方的全部内容突然移动。此外,我们正在从下到上滚动这是一个聊天线程

我尝试过的事情:

我们尝试从ListView通过setSelection方法滚动整个ListView,以便在用户看到内容之前预加载内容。这不起作用,而且在我们滚动图像的短暂时间内,图像似乎没有加载

我们尝试设置静态XML文件的宽度和高度,这解决了这个问题,但没有考虑不同的屏幕大小

我需要帮助的是:我们希望在动态调整布局大小的同时保持滚动平滑。最后一种方法是为每个屏幕大小类别创建不同的XML文件,并对高度进行硬编码,但这并不能使框架的纵横比保持在我们所希望的水平


请让我知道,如果有任何澄清,你会想要。提前谢谢

您可以在chat\u row\u image.xml中添加一个LinearLayout outside,如下所示

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

您可以在chat\u row\u image.xml中添加一个LinearLayout outside,如下所示

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

答案是在适配器的构造函数中设置框架的维度,而不是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中观察到任何跳跃

答案是在适配器的构造函数中设置框架的维度,而不是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中观察到任何跳跃

看起来您可以直接设置布局参数,而无需全局布局侦听器,并调用convertView.RequestLayoutHanks!这当然启发了我一个想法,即不使用全局布局侦听器,并在膨胀视图后立即设置值。我将在下面的回答中对此进行详细说明。看起来您可以直接设置布局参数,而无需全局布局侦听器,并调用convertView.RequestLayoutHanks!这当然启发了我一个想法,即不使用全局布局侦听器,并在膨胀视图后立即设置值。我将在下面的回答中对此进行详细说明