3

I tried to have a grid view with a listview in my activity but I got an error.

Are there any another way to have the below result ?

In my main activity I want to have one a list view display larg imageview and second display them as 2 image per row , should I use grid view or second list view is enough?

enter image description here

this is my code

<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>
Moudiz
  • 7,211
  • 22
  • 78
  • 156
  • you can try with gird layout.it has customized row specification like your requirment – RamBabu Pudari Jul 31 '15 at 06:09
  • @RamBabuPudari what do you mean can you explain please – Moudiz Jul 31 '15 at 06:10
  • 1
    @Moudiz , try mentioning fixed gridview height or listview height programatically, use gridview itself for second View – ManishSB Jul 31 '15 at 06:11
  • 1
    http://stackoverflow.com/questions/11863329/gridlayout-and-row-column-span-woe see this link its very help to you.no need to listview and grid view. – RamBabu Pudari Jul 31 '15 at 06:13
  • @RamBabuPudari its not exactly what I want , I am searching list view and gridview at the same time – Moudiz Jul 31 '15 at 06:20
  • you can specify column span and row span what ever you like pragmatically like your requirements. defiantly you can achieve if try with your own logic pro-grammatically for grid layout. – RamBabu Pudari Jul 31 '15 at 06:31

4 Answers4

2

A more suitable and straightforward solution would be to use RecyclerView with GridLayoutManager. GridLayoutManager takes SpanSizeLookup object which allows you to specify how many spans will each of the items occupy.

A complete solution to this problem includes the following pieces:

Activity with RecyclerView, GridLayoutManager and custom SpanSizeLookup

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

Adapter for 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 layout

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

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

And the last piece would be to make sure to add dependency in build.gradle file for RecyclerView:

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

And here is the result:

enter image description here

Advantages of this solution are:

  1. it's scalable, lightweight, and very customizable
  2. it's efficient as it recycles the views when you scroll up and down
  3. it does not require messing with touch events which can easily become very tricky to handle once you add any additional touch functionality

I hope this is helpful.

dkarmazi
  • 3,199
  • 1
  • 13
  • 25
  • sorry for the late reply I was bit busy but I like your answer , I will try it and then ill tell you my result , btw I work on eclipse so no need to use gradle right ? – Moudiz Aug 01 '15 at 16:40
  • no, you won't have gradle scripts in Eclipse project, but you do have to make sure that you properly include RecyclerView in you project. – dkarmazi Aug 02 '15 at 18:35
  • I tried to include recycleview but now I am facing a weird problem manifest is missing , dunno those libraries did – Moudiz Aug 02 '15 at 18:54
  • It's hard to tell what exactly went wrong with the way you included these libs, but the best I can recommend would be checking something like this: http://stackoverflow.com/questions/26492345/importing-cardview-and-recyclerview-android-5-0-in-my-existing-project-eclips – dkarmazi Aug 03 '15 at 00:51
1

This is little tricky thing, Whenever we get requirement like this, we have to do a workaround like keeping a LinearLayout with orientation as vertical and keep that LinearLayout inside a ScrollView. I have created a sample for your issue.. I hope this will help you.

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>

main.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();
                }
            });
        }
    }
}

Screenshot :

Screenshot of your issue

SureshCS50
  • 3,608
  • 1
  • 20
  • 27
  • Bte is it good practice because they mentioned recycle view is better .. what do you think – Moudiz Jul 31 '15 at 15:28
  • Sorry, I haven't try RecyclerView yet.. but, whenever I get requirements like multiple listview or gridview in same layout I will use like this.. coz, using multiple listviews in layout is not a good practice.. In some sites they will ask you to use MultipleListViewUtility.java file.. that will give you NullPointerException in some Samsung mobiles.. So, It's better to workaround like this.. – SureshCS50 Jul 31 '15 at 16:08
1

There is quite easy way to implement this:- AsymmetricGridView

Hope this will help you !!

Adarsh Yadav
  • 3,752
  • 3
  • 24
  • 46
0

You cannot simply place a scrollable View inside another scrollable View and expect them to work out of the box, especially if they both scroll in the same direction. The best way to make this possible is by extending those Views and intercepting touch-events that get sent to them. Here you can determine the direction of scroll being made by the user and route the touch event accordingly.

Read this: Intercept Touch Events in a ViewGroup

Saket
  • 2,945
  • 1
  • 29
  • 31
  • Oh and multiple scrollable Views in the same layout won't work as expected either :) – Saket Jul 31 '15 at 07:12
  • I guess a list view and grid view will work right ?( removing the scrolll view ) what is your sugestion to acomplish the above image ? (I still didnt read your link yet) – Moudiz Jul 31 '15 at 07:15
  • Are you trying to customize the number of items shown per row in your list? For instance, 1 item in the some of the rows and 2 items in others? – Saket Jul 31 '15 at 07:19
  • yes you are right 1 item in the first list view and 2 item in second view , I am thiking to display them in 2 list view . the first list view displays 1 item and the second display 2 item . but still I didnt achive that yet – Moudiz Jul 31 '15 at 07:24
  • And you'll never be able to achieve that because placing multiple `ListViews.` Thankfully, `RecyclerView` can do what you're to achieve. Relevant answer: http://stackoverflow.com/questions/28640233/recyclerview-gridlayoutmanager-and-dynamic-spans-count – Saket Jul 31 '15 at 07:35