如何将GridView置于ScrollView中

69

我需要设计一个布局,让整个布局可以滚动,而在里面的布局中,我需要以Grid形式显示相关内容,所以我决定使用GridView。但问题在于,我无法在ScrollView中使用GridView。我已经阅读了文档(文档也指出我们不应该在ScrollView中使用GridView),但我必须这样做,请问有什么好的建议吗?谢谢。


2
谢谢@njzk2,但我必须设计成这样的布局,所以你能告诉我其他看起来像这样的方法吗? - Dilip
实际上,你可以这样做,并且有一些很好的应用程序。我会更新一个答案。 - dennisdrew
@SiddharthLele 我的意思是我必须将ImageView、TextView、Button和GridView放在ListView中。在Button上必须放置GridView,因此必须使用ScrollView。 - Dilip
你尝试过用线性布局封装GridView吗? - Charan Pai
这是我认为玩具的确切答案...https://dev59.com/P2855IYBdhLWcg3wHwiH#4536955 - Charan Pai
显示剩余3条评论
11个回答

117

GridView除了内置的滚动功能外,还有许多好处。例如,它可以提供一致的动态布局,根据传递给它的数据而展开或收缩单元格。因此,当有人说不应该渴望这样的功能时,我认为这是错误的,因为你可能希望在可滚动视图中放置包含其他元素的网格视图,但希望整个滚动视图包含的不仅仅是网格单元格。

现在,这里是如何实现这一点的方法。请查看此处的答案。这是一个可扩展高度的GridView,您需要将其导入/创建到项目中。基本上这意味着随着GridView添加更多的项,它将会自动扩展其高度,而不是保持其高度设置并使用滚动条。这正是您所需要的。

一旦您在项目中拥有ExpandableHeightGridView,则可以转到您想要放置GridView的XML布局中。然后您可以像这样操作(简述):

<ScrollView ...>
    <RelativeLayout ...>
        <com.example.ExpandableHeightGridView ... />
        <other view items />
    </RelativeLayout>
</ScrollView>

接着,在你设置GridView适配器的Activity中,你需要确保将其设置为可以扩展。因此:

ExpandableHeightGridView gridView = (ExpandableHeightGridView) findViewById(R.id.myId);
gridView.setAdapter(yourAdapter);
gridView.setExpanded(true);
你需要这个可扩展的GridView,因为标准的GridView不会自动扩展,这就导致它会出现滚动条。它会固定一定的高度,然后当更多的项目填充它的视图范围时,它就会变得可滚动。有了这个可扩展的GridView,它将始终扩展其高度以适应其中的内容,从而永远不会进入滚动模式。这使你可以在ScrollView中使用它,并在ScrollView中使用其他视图元素放置在它上面或下面,这些元素都可以滚动。这应该会给你想要的结果。如果你有任何问题,请告诉我。

1
有一件事,当我使用不同的视图启动应用程序时,布局会自动滚动到底部,如何适应它,请给我建议。 - Dilip
7
这种方法的问题在于你会失去网格视图所提供的性能优化,即网格项的回收利用。 - howettl
9
您在此回答中提出的建议会使GridView失去意义。您的应用可能会耗尽内存,性能也会大受影响。解决方案是使用头部或尾部视图,就像普通的ListView一样。原生的GridView可能不支持头部或尾部视图,但是有像这个的自定义实现。使用其中一个可以获得相同的效果,而且不会损失视图回收功能。您提出的类似hack的解决方法可以解决问题,但日后只会带来更严重的问题。 - Xaver Kapeller
或者你可以在ScrollView中使用GridLayout。虽然仍然没有视图回收,但它至少比使用GridView要好得多。[文档链接](http://developer.android.com/reference/android/widget/GridLayout.html) - Xaver Kapeller
1
想要分享一下在实现这个功能时发生的一个行为,就是扩展的GridView会将ScrollView滚动到底部,所以只需要做以下操作: //将ScrollLayout移回顶部,因为扩展GridView会将ScrollView滚动到底部 ScrollView mainScrollView = (ScrollView) rootView.findViewById (R.id.scrollView); mainScrollView.smoothScrollTo(0,0);就可以把所有东西放在正确的位置。希望能对某些人有所帮助! - PayToPwn
显示剩余9条评论

36

我知道我来晚了,但是我有另外一个解决方案必须分享,而且它可以完美地运行。在这里,该方法根据GridView包含的项目数量计算GridView高度,并在运行时将高度设置为GridView。

public void setGridViewHeightBasedOnChildren(GridView gridView, int columns) {
        ListAdapter listAdapter = gridView.getAdapter(); 
        if (listAdapter == null) {
            // pre-condition
            return;
        }

        int totalHeight = 0;
        int items = listAdapter.getCount();
        int rows = 0;

        View listItem = listAdapter.getView(0, null, gridView);
        listItem.measure(0, 0);
        totalHeight = listItem.getMeasuredHeight();

        float x = 1;
        if( items > columns ){
            x = items/columns;
            rows = (int) (x + 1);
            totalHeight *= rows;
        }

        ViewGroup.LayoutParams params = gridView.getLayoutParams();
        params.height = totalHeight;
        gridView.setLayoutParams(params);

}

在你的GridView上调用了setAdapter之后,只需调用

setGridViewHeightBasedOnChildren( <yourGridView> , <no of grid view columns> )

然后它就会工作。

您可以像往常一样在xml中定义gridview

让代码来处理它。 :)


你在调用setGridViewHeightBasedOnChildren方法之前是否在你的GridView上调用了setAdapter方法?如果GridView有项目,那么它应该可以工作。 - Vikram Gupta
2
@vickey 如果项目数量完全填满了行数,那么你计算的高度会多出1行。 - andrei
1
如果您的GridView有垂直间距,则必须将其添加到totalHeight中。 - ElYeante
这段代码中有一个错误。请将if块替换为:if( items > columns ){ double x = ((double) items ) /columns; rows =(int) Math.ceil(x); totalHeight *= rows; }并将x变量声明为double而不是float。 - aligur
如果您不想使用自定义网格视图与此代码一起工作,则它将正常工作。 - Manju
如果GridView设置为android:numColumns="auto_fit",我该如何获取列数? - Daniele Muscetta

10

我还尝试在NestedScrollView内部使GridView可滚动。

这个问题的另一个答案对我有所帮助:https://stackoverflow.com/a/38612612

Enable your GridView Property as

android:nestedScrollingEnabled="true"

Original poster: Droid_Dev


非常有用,谢谢! - aida

10

我找到了一种方法来使GridViewScrollView内部有固定的大小,同时启用滚动。这样可以让您查看整个ScrollView,而不必滚动所有GridView的元素,对我来说这比使用ExpandableHeightGridView更有意义。

为此,您需要实现一个新类来扩展GridView,并覆盖onTouchEvent()以调用requestDisallowInterceptTouchEvent(true)。因此,父视图将离开Grid拦截触摸事件。

GridViewScrollable.java:

package com.example;
import android.content.Context;
import android.util.AttributeSet;
import android.view.MotionEvent;
import android.widget.GridView;

public class GridViewScrollable extends GridView {

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

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

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

    @Override
    public boolean onTouchEvent(MotionEvent ev){
        // Called when a child does not want this parent and its ancestors to intercept touch events.
        requestDisallowInterceptTouchEvent(true);
        return super.onTouchEvent(ev);
    }
}
在ScrollView中添加具有您想要的特性和边距的布局:
```html

将其添加到ScrollView中,具有您想要的特性和边距的布局:

```
<ScrollView xmlns:android="http://schemas.android.com/apk/res/android"
xmlns:tools="http://schemas.android.com/tools"
android:layout_width="match_parent"
android:layout_height="match_parent"
android:isScrollContainer="true" >

    <com.example.GridViewScrollable
    android:id="@+id/myGVS"
    android:layout_width="wrap_content"
    android:layout_height="wrap_content"
    android:gravity="center"
    android:numColumns="auto_fit"
    android:stretchMode="columnWidth" />

</ScrollView>

只需要在您的活动中获取它:

GridViewScrollable myGridView = (GridViewScrollable) findViewById(R.id.myGVS);

希望能帮到你 =)

在 Kotlin 中:

class GridViewScrollable @JvmOverloads constructor(
    context: Context,
    attrs: AttributeSet? = null,
    defStyleAttr: Int = 0
) : GridView(context, attrs, defStyleAttr) {

    override fun onTouchEvent(ev: MotionEvent?): Boolean {
        // Called when a child does not want this parent and its ancestors to intercept touch events.
        requestDisallowInterceptTouchEvent(true)
        return super.onTouchEvent(ev)
    }
}

有一个令人讨厌的警告:“Custom view GridViewScrollable覆盖了onTouchEvent但没有performClick”。如果你想的话,请自己解决。


这已经很晚了,但是这个GridView可以滚动吗? - lazy lord
它对我来说确实有效,但问题是fling不起作用。 - ievgen
@ievgen 你在ScrollView中添加了android:isScrollContainer="true"吗? - Lionel T.
1
这是我能够让GridView与可变大小的单选按钮列表一起工作的唯一方法。我真的不想要滚动条,但是如果最后一行太大,GridView似乎会变得混乱并截断它。 - Stephen McCormick
什么是GridViewAdjuntos - Ivan
显示剩余2条评论

5
要在滚动视图中使用网格视图,请设置滚动视图android:fillViewport="true"。我知道这个回答有点晚,但对于一些新开发者可能有用。

2

如果您使用了dennisdrew的答案,并且在网格上方有内容,在打开视图时会被隐藏,只需添加以下最后一行即可

ExpandableHeightGridView gridView = (ExpandableHeightGridView) findViewById(R.id.myId);
gridView.setAdapter(yourAdapter);
gridView.setExpanded(true);
gridView.setFocusable(false);

1

最好在scrollview内使用ExpandableHeightlistViewExpandableHeightGridView

逻辑

通过提供非常大的高度提示来计算整个高度。但不要使用该整数的最高2位;它们保留用于MeasureSpec模式。

int expandSpec = MeasureSpec.makeMeasureSpec(
 Integer.MAX_VALUE >> 2, MeasureSpec.AT_MOST);
 super.onMeasure(widthMeasureSpec, expandSpec);

 ViewGroup.LayoutParams params = getLayoutParams();
 params.height = getMeasuredHeight();

如需更多信息,请查看下面的示例和演示

http://www.londatiga.net/it/programming/android/make-android-listview-gridview-expandable-inside-scrollview/


2
请问您能否描述一些背景信息,解释为什么一个比另一个更好? - Bas Peeters

1

相信这个解决方案对我有用!

gridview中的上述代码使gridview可以滚动,并设置宽度和高度 android:nestedScrollingEnabled="true" android:layout_width="match_parent" android:layout_height="200sp"

即使在scrollview中也可以使用此方法。感谢之前的答案,我从中找到了这个方法。感谢他们。


1
我不会强制执行此问题。GridView在scrollView中效果不佳。相反,将您的GridView转换为RecyclerView,并使用GridLayoutManager解决该问题。

0

网页内容由stack overflow 提供, 点击上面的
可以查看英文原文,
原文链接