Warning: file_get_contents(/data/phpspider/zhask/data//catemap/3/android/214.json): failed to open stream: No such file or directory in /data/phpspider/zhask/libs/function.php on line 167

Warning: Invalid argument supplied for foreach() in /data/phpspider/zhask/libs/tag.function.php on line 1116

Notice: Undefined index: in /data/phpspider/zhask/libs/function.php on line 180

Warning: array_chunk() expects parameter 1 to be array, null given in /data/phpspider/zhask/libs/function.php on line 181
Android GridView行重叠:如何使行高度适合最高的项目?_Android_Android Layout_Android Gridview - Fatal编程技术网

Android GridView行重叠:如何使行高度适合最高的项目?

Android GridView行重叠:如何使行高度适合最高的项目?,android,android-layout,android-gridview,Android,Android Layout,Android Gridview,例如,我在GridView项目之间有不需要的重叠: 请注意,除了最右边的一列之外,每列中都有文本 我与前一个问题的不同之处在于,我不想要恒定的行高。我希望行高有所不同,以容纳每行中最高的内容,从而有效利用屏幕空间 查看(不是权威副本,但kernel.org仍处于关闭状态),我们可以在fillDown()和makeRow()中看到最后一个视图是“参考视图”:行的高度是从该视图的高度设置的,而不是从最高的视图设置的这解释了为什么最右边的列是可以的。不幸的是,GridView没有很好的设置,我无法通

例如,我在GridView项目之间有不需要的重叠:

请注意,除了最右边的一列之外,每列中都有文本

我与前一个问题的不同之处在于,我不想要恒定的行高。我希望行高有所不同,以容纳每行中最高的内容,从而有效利用屏幕空间

查看(不是权威副本,但kernel.org仍处于关闭状态),我们可以在fillDown()和makeRow()中看到最后一个视图是“参考视图”:行的高度是从该视图的高度设置的,而不是从最高的视图设置的这解释了为什么最右边的列是可以的。不幸的是,GridView没有很好的设置,我无法通过继承来解决这个问题。所有相关字段和方法都是私有的

所以,在我走上“克隆并拥有”这条老掉牙的老路之前,我有没有遗漏一个技巧?我可以使用一个表格布局,但这需要我自己实现
numColumns=“auto_-fit”
(因为我只想在手机屏幕上显示一个长列),而且它也不是AdapterView,这感觉应该是这样的


编辑:事实上,克隆和拥有在这里并不实用。GridView依赖于其父类和同级类的不可访问部分,将导致导入至少6000行代码(AblistView、AdapterView等)。

我使用静态数组来驱动行的最大高度。这并不完美,因为在重新显示单元格之前,不会调整先前列的大小。下面是可重用内容视图的代码

编辑:我正确地完成了这项工作,但在渲染之前我已经预先测量了所有单元格。为此,我将GridView子类化,并在onLayout方法中添加一个测量挂钩

/**
 * Custom view group that shares a common max height
 * @author Chase Colburn
 */
public class GridViewItemLayout extends LinearLayout {

    // Array of max cell heights for each row
    private static int[] mMaxRowHeight;

    // The number of columns in the grid view
    private static int mNumColumns;

    // The position of the view cell
    private int mPosition;

    // Public constructor
    public GridViewItemLayout(Context context) {
        super(context);
    }

    // Public constructor
    public GridViewItemLayout(Context context, AttributeSet attrs) {
        super(context, attrs);
    }

    /**
     * Set the position of the view cell
     * @param position
     */
    public void setPosition(int position) {
        mPosition = position;
    }

    /**
     * Set the number of columns and item count in order to accurately store the
     * max height for each row. This must be called whenever there is a change to the layout
     * or content data.
     * 
     * @param numColumns
     * @param itemCount
     */
    public static void initItemLayout(int numColumns, int itemCount) {
        mNumColumns = numColumns;
        mMaxRowHeight = new int[itemCount];
    }

    @Override
    protected void onMeasure(int widthMeasureSpec, int heightMeasureSpec) {
        super.onMeasure(widthMeasureSpec, heightMeasureSpec);
        // Do not calculate max height if column count is only one
        if(mNumColumns <= 1 || mMaxRowHeight == null) {
            return;
        }

        // Get the current view cell index for the grid row
        int rowIndex = mPosition / mNumColumns;
        // Get the measured height for this layout
        int measuredHeight = getMeasuredHeight();
        // If the current height is larger than previous measurements, update the array
        if(measuredHeight > mMaxRowHeight[rowIndex]) {
            mMaxRowHeight[rowIndex] = measuredHeight;
        }
        // Update the dimensions of the layout to reflect the max height
        setMeasuredDimension(getMeasuredWidth(), mMaxRowHeight[rowIndex]);
    }
}
最后,这里是GridView子类,用于在布局期间测量视图单元:

/**
 * Custom subclass of grid view to measure all view cells
 * in order to determine the max height of the row
 * 
 * @author Chase Colburn
 */
public class AutoMeasureGridView extends GridView {

    public AutoMeasureGridView(Context context) {
        super(context);
    }

    public AutoMeasureGridView(Context context, AttributeSet attrs) {
        super(context, attrs);
    }

    public AutoMeasureGridView(Context context, AttributeSet attrs, int defStyle) {
        super(context, attrs, defStyle);
    }

    @Override
    protected void onLayout(boolean changed, int l, int t, int r, int b) {
        if(changed) {
            CustomAdapter adapter = (CustomAdapter)getAdapter();

            int numColumns = getContext().getResources().getInteger(R.integer.list_num_columns);
            GridViewItemLayout.initItemLayout(numColumns, adapter.getCount());

            if(numColumns > 1) {
                int columnWidth = getMeasuredWidth() / numColumns;
                adapter.measureItems(columnWidth);
            }
        }
        super.onLayout(changed, l, t, r, b);
    }
}

我将列数作为资源的原因是,我可以根据方向等使用不同的列数。

根据Chris提供的信息,我在确定其他GridView项的高度时,使用了本机GridView使用的参考视图,使用了此解决方法

我创建了这个GridViewItemContainer自定义类:

/**
 * This class makes sure that all items in a GridView row are of the same height.
 * (Could extend FrameLayout, LinearLayout etc as well, RelativeLayout was just my choice here)
 * @author Anton Spaans
 *
*/
public class GridViewItemContainer extends RelativeLayout {
private View[] viewsInRow;

public GridViewItemContainer(Context context) {
    super(context);
}

public GridViewItemContainer(Context context, AttributeSet attrs, int defStyle) {
    super(context, attrs, defStyle);
}

public GridViewItemContainer(Context context, AttributeSet attrs) {
    super(context, attrs);
}

public void setViewsInRow(View[] viewsInRow) {
    if  (viewsInRow != null) {
        if (this.viewsInRow == null) {
            this.viewsInRow = Arrays.copyOf(viewsInRow, viewsInRow.length);
        }
        else {
            System.arraycopy(viewsInRow, 0, this.viewsInRow, 0, viewsInRow.length);
        }
    }
    else if (this.viewsInRow != null){
        Arrays.fill(this.viewsInRow, null);
    }
}

@Override
protected LayoutParams generateDefaultLayoutParams() {
    return new LayoutParams(LayoutParams.MATCH_PARENT, LayoutParams.MATCH_PARENT);
}

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

    if (viewsInRow == null) {
        return;
    }

    int measuredHeight = getMeasuredHeight();
    int maxHeight      = measuredHeight;
    for (View siblingInRow : viewsInRow) {
        if  (siblingInRow != null) {
            maxHeight = Math.max(maxHeight, siblingInRow.getMeasuredHeight());
        }
    }

    if (maxHeight == measuredHeight) {
        return;
    }

    int heightMode = MeasureSpec.getMode(heightMeasureSpec);
    int heightSize = MeasureSpec.getSize(heightMeasureSpec);
    switch(heightMode) {
    case MeasureSpec.AT_MOST:
        heightMeasureSpec = MeasureSpec.makeMeasureSpec(Math.min(maxHeight, heightSize), MeasureSpec.EXACTLY);
        super.onMeasure(widthMeasureSpec, heightMeasureSpec);
        break;

    case MeasureSpec.EXACTLY:
        // No debate here. Final measuring already took place. That's it.
        break;

    case MeasureSpec.UNSPECIFIED:
        heightMeasureSpec = MeasureSpec.makeMeasureSpec(maxHeight, MeasureSpec.EXACTLY);
        super.onMeasure(widthMeasureSpec, heightMeasureSpec);
        break;

    }
}
在适配器的getView方法中,将convertView作为子级包装到新的GridViewItemContainer中,或者将其作为项布局的顶部XML元素:

        // convertView has been just been inflated or came from getView parameter.
        if (!(convertView instanceof GridViewItemContainer)) {
            ViewGroup container = new GridViewItemContainer(inflater.getContext());

            // If you have tags, move them to the new top element. E.g.:
            container.setTag(convertView.getTag());
            convertView.setTag(null);

            container.addView(convertView);
            convertView = container;
        }
        ...
        ...
        viewsInRow[position % numColumns] = convertView;
        GridViewItemContainer referenceView = (GridViewItemContainer)convertView;
        if ((position % numColumns == (numColumns-1)) || (position == getCount()-1)) {
            referenceView.setViewsInRow(viewsInRow);
        }
        else {
            referenceView.setViewsInRow(null);
        }

其中numColumns是GridView中的列数,“viewsInRow”是“position”所在的当前行上的视图列表。

赋予GridView权重也可以作为子视图应用于LinearLayouts中的GridView。通过这种方式,GridView会用其子对象填充视口,以便您可以查看其项目,只要它们适合屏幕(然后滚动)

但始终避免在ScrollView中使用GridView。否则,您将需要计算每个孩子的身高,并按照上面的回答重新指定他们

<GridView
    android:id="@+id/gvFriends"
    android:layout_width="match_parent"
    android:layout_height="wrap_content"
    android:layout_weight="1"
    android:verticalSpacing="5dp"
    android:horizontalSpacing="5dp"
    android:clipChildren="false"
    android:listSelector="@android:color/transparent"
    android:scrollbarAlwaysDrawHorizontalTrack="false"
    android:scrollbarAlwaysDrawVerticalTrack="false"
    android:stretchMode="columnWidth"
    android:scrollbars="none"
    android:numColumns="4"/>

我做了很多研究,但发现了不完整的答案,或者很难理解解决方案的内容,但最终找到了一个完全符合正确解释的答案

我的问题是将gridview项适当地调整到高度。当所有视图的高度相同时,此
网格视图
非常有效。但是,当视图具有不同高度时,栅格的行为与预期不符。视图将相互重叠,形成美观的网格

在这里,我在XML布局中使用了这个类


我使用了这个解决方案,效果非常好,非常感谢。-Abhishek Mittal

如果将GridView或ListView转换为a,则不会发生此问题。而且您不需要定制GridView类。

这不是我在下面提到的正确解决方案,但可以根据您的要求进行变通

只需从gridview的子布局中设置视图固定点的高度(在某些dp中,即-50dp),即可对其进行包装

        <TextView
            android:layout_width="match_parent"
            android:layout_height="50dp"
            android:ellipsize="end"
            android:textColor="@color/text_color"
            android:textSize="13dp"
            android:textStyle="normal" />


您可以在此处包含GridView子类代码,还是其中的相关部分?给您!我希望能有帮助。谢谢!我会在某个时候切换到这个,它看起来应该比TableLayout好一些。:-)我喜欢你的想法,但在测试或使用之前,我有很多疑问。首先,将所有行高度存储在静态变量中。我认为当在同一个视图中使用多个GridView时,它会搞砸。第二,如果“numColumns”是“auto_fit”呢。第三,在“AutoMeasureGridView”的“onLayout”内测量“columnWidth”时。您正在使用“getMeasuredWidth()/numColumns”。但是水平间距呢?它不应该是“getMeasuredWidth()/(numColumns+((numColumns-1)*水平间距))”吗?谢谢:)请上传你的itemView.updateItemDisplay(item,mLanguage);方法,这让我很困惑,这个答案对我很有帮助,但我对updateItemDisplay()方法感到困惑。对于固定高度,这个链接可以是一个解决方案:最好使用循环视图。它将正确地处理这类事情。工作正常,直到两个后续行暴露出相同的问题:然后它们在最初太高的第一行上再次重叠。另一方面,固定高度会发生变化的物体的高度总是有效的。请参见:)我有一个gridView,其中包含不同高度的项目。到目前为止,我找到的唯一解决办法是设置项目的固定高度。我很确定你的解决方案是错误的。首先,布局权重不是由子元素继承的(如果是的话会很奇怪),即使是,它仍然不能解决问题。如问题中所述,问题在于GridView将行的最后一个元素作为引用视图,而不是最高的元素。如果你的解决方案确实有效,那就太好了,但是请在本例中提供一个更全面的例子来说明它是有效的。问题
        <TextView
            android:layout_width="match_parent"
            android:layout_height="50dp"
            android:ellipsize="end"
            android:textColor="@color/text_color"
            android:textSize="13dp"
            android:textStyle="normal" />