【问题标题】:grid view inside a list view or 2 list views is better?列表视图或 2 个列表视图中的网格视图更好?
【发布时间】:2015-08-01 03:07:28
【问题描述】:

我尝试在我的活动中使用带有列表视图的网格视图,但出现错误。

还有其他方法可以得到以下结果吗?

在我的主要活动中,我想让一个列表视图显示大图像视图,然后将它们显示为每行 2 个图像,我应该使用网格视图还是第二个列表视图就足够了?

这是我的代码

<ScrollView xmlns:android="http://schemas.android.com/apk/res/android"
    android:layout_width="wrap_content"
    android:layout_height="wrap_content"
    android:fillViewport="true" >

    <LinearLayout
        android:layout_width="match_parent"
        android:layout_height="wrap_content"
        android:orientation="vertical">

        <TextView
            android:layout_width="match_parent"
            android:layout_height="wrap_content"
            android:gravity="center"
          android:text="sssss"
            android:textSize="16sp"
            android:padding="10dp"
            android:background="#ffe474" />

        <ListView
            android:id="@+id/list3"
            android:layout_width="wrap_content"
            android:layout_height="1500dp"
            android:background="#eeeeee" >
        </ListView>

         <TextView
            android:layout_width="match_parent"
            android:layout_height="wrap_content"
            android:gravity="center_vertical"
            android:text="Recommanded"
            android:textSize="18sp"
            android:padding="10dp"
            android:background="#ffe474" />


        <ListView
            android:id="@+id/list1"
            android:layout_width="wrap_content"
            android:layout_height="1500dp"
            android:background="#eeeeee" >
        </ListView>

    </LinearLayout>


</ScrollView>

【问题讨论】:

  • 您可以尝试使用网格布局。它已根据您的要求自定义行规范
  • @RamBabuPudari 你是什么意思可以解释一下
  • @Moudiz ,尝试以编程方式提及固定的网格视图高度或列表视图高度,将网格视图本身用于第二个视图
  • stackoverflow.com/questions/11863329/… 看到这个链接它对你很有帮助。不需要列表视图和网格视图。
  • @RamBabuPudari 这不是我想要的,我正在同时搜索列表视图和网格视图

标签: android android-listview


【解决方案1】:

更合适和直接的解决方案是将 RecyclerView 与 GridLayoutManager 一起使用。 GridLayoutManager 采用 SpanSizeLookup 对象,该对象允许您指定每个项目将占用多少跨度。

这个问题的完整解决方案包括以下几部分:

带有 RecyclerView、GridLayoutManager 和自定义 SpanSizeLookup 的 Activity

public class MainActivity extends Activity {
    @Override
    protected void onCreate(Bundle savedInstanceState) {
        super.onCreate(savedInstanceState);
        setContentView(R.layout.activity_main);

        RecyclerView recyclerView = (RecyclerView) findViewById(R.id.recycler_view);
        // specify that grid will consist of 2 columns
        GridLayoutManager gridLayoutManager = new GridLayoutManager(getApplicationContext(), 2);
        // provide our CustomSpanSizeLookup which determines how many spans each item in grid will occupy
        gridLayoutManager.setSpanSizeLookup(new CustomSpanSizeLookup());
        // provide our GridLayoutManager to the view
        recyclerView.setLayoutManager(gridLayoutManager);
        // this is fake list of images
        List<Integer> imageResList = getMockedImageList();
        // finally, provide adapter to the recycler view
        Adapter adapter = new Adapter(imageResList);
        recyclerView.setAdapter(adapter);
    }


    private List<Integer> getMockedImageList() {
        // fake images list, you'd need to upload your own image resources
        List<Integer> imageResList = new ArrayList<Integer>();

        imageResList.add(R.drawable.img1);
        imageResList.add(R.drawable.img2);
        imageResList.add(R.drawable.img3);
        imageResList.add(R.drawable.img4);
        imageResList.add(R.drawable.img5);
        imageResList.add(R.drawable.img6);

        return imageResList;
    }


    private static class CustomSpanSizeLookup extends GridLayoutManager.SpanSizeLookup {
        @Override
        public int getSpanSize(int i) {
            if(i == 0 || i == 1) {
                // grid items on positions 0 and 1 will occupy 2 spans of the grid
                return 2;
            } else {
                // the rest of the items will behave normally and occupy only 1 span
                return 1;
            }
        }
    }
}

RecyclerView 的适配器

public class Adapter extends RecyclerView.Adapter {
    // I assume that you will pass images as list of resources, but this can be easily switched to a list of URLS
    private List<Integer> imageResList = new ArrayList<Integer>();

    public Adapter(List<Integer> imageUrlList) {
        this.imageResList = imageUrlList;
    }


    @Override
    public RecyclerView.ViewHolder onCreateViewHolder(ViewGroup viewGroup, int i) {
        View itemView = LayoutInflater.from(viewGroup.getContext()).inflate(R.layout.recycle_view_item, viewGroup, false);

        return new ItemViewHolder(itemView);
    }

    @Override
    public void onBindViewHolder(RecyclerView.ViewHolder viewHolder, int i) {
        ItemViewHolder itemViewHolder = (ItemViewHolder) viewHolder;
        itemViewHolder.item.setImageResource(imageResList.get(i));
    }

    @Override
    public int getItemCount() {
        return imageResList.size();
    }


    private static class ItemViewHolder extends RecyclerView.ViewHolder {
        private ImageView item;

        public ItemViewHolder(View itemView) {
            super(itemView);

            this.item = (ImageView) itemView.findViewById(R.id.item_image);
        }
    }
}

activity_main.xml 布局

<RelativeLayout 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:paddingLeft="@dimen/activity_horizontal_margin"
    android:paddingRight="@dimen/activity_horizontal_margin"
    android:paddingTop="@dimen/activity_vertical_margin"
    android:paddingBottom="@dimen/activity_vertical_margin" tools:context=".MainActivity">

    <android.support.v7.widget.RecyclerView
        android:id="@+id/recycler_view"
        android:layout_width="match_parent"
        android:layout_height="match_parent"/>

</RelativeLayout>

recycler_view_item.xml 布局

<?xml version="1.0" encoding="utf-8"?>
<LinearLayout xmlns:android="http://schemas.android.com/apk/res/android"
    android:orientation="vertical"
    android:layout_width="match_parent"
    android:layout_height="150dp"
    android:padding="10dp">

    <ImageView
        android:id="@+id/item_image"
        android:layout_width="match_parent"
        android:layout_height="match_parent"
        android:scaleType="centerCrop"/>

</LinearLayout>

最后一点是确保在 build.gradle 文件中为 RecyclerView 添加依赖项:

dependencies {
    compile 'com.android.support:recyclerview-v7:21.0.+'
}

结果如下:

此解决方案的优点是:

  1. 它具有可扩展性、轻量级和高度可定制性
  2. 它非常高效,因为它会在您上下滚动时回收视图
  3. 它不需要弄乱触摸事件,一旦添加任何额外的触摸功能,这些触摸事件很容易变得难以处理

我希望这会有所帮助。

【讨论】:

  • 抱歉回复晚了,我有点忙,但我喜欢你的回答,我会尝试一下,然后告诉你我的结果,顺便说一句,我在 eclipse 上工作,所以不需要使用 gradle 对吗?跨度>
  • 不,Eclipse 项目中不会有 gradle 脚本,但必须确保在项目中正确包含 RecyclerView。
  • 我试图包含 recycleview 但现在我遇到了一个奇怪的问题 manifest is missing ,不知道那些库没有
  • 很难说你包含这些库的方式到底出了什么问题,但我能推荐的最好的方法是检查如下内容:stackoverflow.com/questions/26492345/…
【解决方案2】:

这有点棘手,每当我们有这样的需求时,我们都必须做一个解决方法,比如保持 LinearLayoutorientation 为垂直 并将 LinearLayout 保存在 ScrollView 中。 我已经为您的问题创建了一个示例。希望对您有所帮助。

custom_grid_item.xml:

<LinearLayout xmlns:android="http://schemas.android.com/apk/res/android"
              android:id="@+id/layout_horizontal"
              android:orientation="horizontal"
              android:layout_width="match_parent"
              android:layout_height="wrap_content"
              android:background="@android:color/black">

    <LinearLayout
            android:id="@+id/gridItemLeft"
            android:orientation="horizontal"
            android:layout_width="0dp"
            android:layout_height="wrap_content"
            android:layout_weight="0.5"
            android:layout_margin="4dp"
            android:gravity="left"
            android:visibility="invisible">

        <TextView
                android:id="@+id/itemNameLeft"
                android:layout_width="match_parent"
                android:layout_height="wrap_content"
                android:textAppearance="@android:style/TextAppearance.Medium"
                android:text="@string/app_name"
                android:textColor="@android:color/black"
                android:padding="4dp"
                android:background="@android:color/white"/>

    </LinearLayout>

    <LinearLayout
            android:id="@+id/gridItemRight"
            android:orientation="horizontal"
            android:layout_width="0dp"
            android:layout_height="wrap_content"
            android:layout_weight="0.5"
            android:layout_margin="4dp"
            android:gravity="right"
            android:visibility="invisible">

        <TextView
                android:id="@+id/itemNameRight"
                android:layout_width="match_parent"
                android:layout_height="wrap_content"
                android:padding="4dp"
                android:textAppearance="@android:style/TextAppearance.Medium"
                android:text="@string/app_name"
                android:textColor="@android:color/black"
                android:background="@android:color/white"/>

    </LinearLayout>
</LinearLayout>

custom_list_item.xml:

<?xml version="1.0" encoding="utf-8"?>

<LinearLayout
        xmlns:android="http://schemas.android.com/apk/res/android"
        android:orientation="vertical"
        android:layout_width="match_parent"
        android:layout_height="wrap_content"
        android:padding="4dp"
        android:background="@android:color/black">

    <TextView
            android:id="@+id/itemName"
            android:layout_width="match_parent"
            android:layout_height="wrap_content"
            android:textAppearance="@android:style/TextAppearance.Medium"
            android:background="@android:color/white"
            android:padding="8dp"
            android:text="@string/app_name"
            android:textColor="@android:color/black"/>

</LinearLayout>

ma​​in.xml:

<?xml version="1.0" encoding="utf-8"?>
<LinearLayout
        xmlns:android="http://schemas.android.com/apk/res/android"
        android:orientation="vertical"
        android:layout_width="match_parent"
        android:layout_height="match_parent"
        android:background="@android:color/black">

    <ScrollView
            android:layout_width="match_parent"
            android:layout_height="match_parent">

        <LinearLayout
                android:orientation="vertical"
                android:layout_width="match_parent"
                android:layout_height="match_parent">

            <LinearLayout
                    android:orientation="vertical"
                    android:id="@+id/custom_list"
                    android:layout_width="match_parent"
                    android:layout_height="wrap_content"
                    android:background="@android:color/white"/>

            <LinearLayout
                    android:orientation="vertical"
                    android:id="@+id/custom_grid"
                    android:layout_width="match_parent"
                    android:layout_height="wrap_content"
                    android:background="@android:color/white"/>

        </LinearLayout>

    </ScrollView>

</LinearLayout>

MyActivity.java:

public class MyActivity extends Activity {

    private List<String> mItems;
    private LinearLayout mListLayout, mGridLayout;

    @Override
    public void onCreate(Bundle savedInstanceState) {
        super.onCreate(savedInstanceState);
        setContentView(R.layout.main);

        mItems = new ArrayList<String>(Arrays.asList("Item 1", "Item 2", "Item 3", "Item 4", "Item 5", "Item 6", "Item 7", "Item 8", "Item 9", "Item 10"));

        mListLayout = (LinearLayout) findViewById(R.id.custom_list);
        mGridLayout = (LinearLayout) findViewById(R.id.custom_grid);

        loadListView();
        loadGridView();

    }

    private void loadGridView() {
        if (mItems.size() % 2 == 0) {
            loadEvenGridView(true);
        } else {
            loadEvenGridView(false);

            LayoutInflater inflater = getLayoutInflater();
            LinearLayout gridItem = (LinearLayout) inflater.inflate(R.layout.custom_grid_item, null);
            LinearLayout leftItem = (LinearLayout) gridItem.findViewById(R.id.gridItemLeft);
            LinearLayout rightItem = (LinearLayout) gridItem.findViewById(R.id.gridItemRight);
            leftItem.setVisibility(View.VISIBLE);
            rightItem.setVisibility(View.INVISIBLE);
            TextView txtItemName = (TextView) gridItem.findViewById(R.id.itemNameLeft);
            txtItemName.setText(mItems.get(mItems.size() - 1));
            leftItem.setOnClickListener(new View.OnClickListener() {
                @Override
                public void onClick(View view) {
                    Toast.makeText(getApplicationContext(), mItems.get(mItems.size() - 1), Toast.LENGTH_SHORT).show();
                }
            });
            mGridLayout.addView(gridItem);
        }
    }

    private void loadEvenGridView(boolean isEvenSize) {
        int len = mItems.size();
        if (!isEvenSize) {
            len = len - 1;
        }
        if (len > 1) {
            for (int index = 1; index < len; index += 2) {
                LayoutInflater inflater = getLayoutInflater();
                LinearLayout gridItem = (LinearLayout) inflater.inflate(R.layout.custom_grid_item, null);
                LinearLayout leftItem = (LinearLayout) gridItem.findViewById(R.id.gridItemLeft);
                LinearLayout rightItem = (LinearLayout) gridItem.findViewById(R.id.gridItemRight);
                TextView txtItemName;
                for (int sIndex = 0; sIndex < 2; sIndex++) {
                    switch (sIndex) {
                        case 0:
                            leftItem.setVisibility(View.VISIBLE);
                            txtItemName = (TextView) gridItem.findViewById(R.id.itemNameLeft);
                            txtItemName.setText(mItems.get(index - 1));
                            final int finalIndex = index;
                            leftItem.setOnClickListener(new View.OnClickListener() {
                                @Override
                                public void onClick(View view) {
                                    Toast.makeText(getApplicationContext(), mItems.get(finalIndex - 1), Toast.LENGTH_SHORT).show();
                                }
                            });
                            continue;
                        case 1:
                            rightItem.setVisibility(View.VISIBLE);
                            txtItemName = (TextView) gridItem.findViewById(R.id.itemNameRight);
                            txtItemName.setText(mItems.get(index));
                            final int finalIndex1 = index;
                            rightItem.setOnClickListener(new View.OnClickListener() {
                                @Override
                                public void onClick(View view) {
                                    Toast.makeText(getApplicationContext(), mItems.get(finalIndex1), Toast.LENGTH_SHORT).show();
                                }
                            });
                            continue;
                    }
                }
                mGridLayout.addView(gridItem);
            }
        }
    }

    private void loadListView() {
        for (int index = 0; index < mItems.size(); index++) {
            LayoutInflater inflater = getLayoutInflater();
            View listItem = inflater.inflate(R.layout.custom_list_item, null);
            TextView txtItemName = (TextView) listItem.findViewById(R.id.itemName);
            txtItemName.setText(mItems.get(index));
            mListLayout.addView(listItem);
            final int finalIndex = index;
            listItem.setOnClickListener(new View.OnClickListener() {
                @Override
                public void onClick(View view) {
                    Toast.makeText(getApplicationContext(), mItems.get(finalIndex), Toast.LENGTH_SHORT).show();
                }
            });
        }
    }
}

截图:

【讨论】:

  • Bte 这是一个好的做法,因为他们提到回收视图更好.. 你觉得呢
  • 对不起,我还没有尝试过 RecyclerView.. 但是,每当我在同一布局中获得多个列表视图或网格视图之类的要求时,我都会像这样使用.. 因为,在布局中使用多个列表视图不是好的做法..在某些站点中,他们会要求您使用 MultipleListViewUtility.java 文件..这会在某些三星手机中为您提供 NullPointerException ..所以,最好像这样解决..
【解决方案3】:

有很简单的方法来实现这个:- AsymmetricGridView

希望对你有帮助!!

【讨论】:

    【解决方案4】:

    您不能简单地将可滚动的View 放在另一个可滚动的View 中,并期望它们开箱即用,尤其是当它们都朝同一方向滚动时。实现这一点的最佳方法是扩展这些视图并拦截发送给它们的触摸事件。在这里,您可以确定用户滚动的方向并相应地路由触摸事件。

    阅读:Intercept Touch Events in a ViewGroup

    【讨论】:

    • 哦,同一布局中的多个可滚动视图也无法按预期工作:)
    • 我猜列表视图和网格视图可以正常工作?(删除滚动视图)您对完成上述图像有何建议? (我还没看你的链接)
    • 您是否尝试自定义列表中每行显示的项目数?例如,某些行中有 1 项,其他行中有 2 项?
    • 是的,您在第一个列表视图中是正确的 1 项,在第二个视图中是 2 项,我想在 2 个列表视图中显示它们。第一个列表视图显示 1 项,第二个显示 2 项。但我仍然没有做到这一点
    • 而您永远无法实现这一目标,因为放置多个 ListViews. 幸运的是,RecyclerView 可以实现您想要实现的目标。相关答案:stackoverflow.com/questions/28640233/…
    猜你喜欢
    • 2014-12-08
    • 1970-01-01
    • 2011-07-26
    • 1970-01-01
    • 1970-01-01
    • 2017-04-27
    • 2010-10-27
    • 1970-01-01
    • 1970-01-01
    相关资源
    最近更新 更多