17

I know it is not possible in Android to scroll grid view horizontally. But what I am doing is adding image buttons dynamically inside horizontal scroll view like this:

public class HorizontalScroller extends Activity {
    static int l=0;
     private Rect mTempRect = new Rect();

    static int r1=0;
    static int t=0;
    static int b=0;
    static int x=0;
    static int y=0;
 //Button[]  b1 = new Button[100];
    ImageButton btn[][] = new ImageButton[10][10];

 //ImageButton b1 = new ImageButton(this);
    /** Called when the activity is first created. */
    @Override
    public void onCreate(Bundle savedInstanceState) {
        super.onCreate(savedInstanceState);
        setContentView(R.layout.main);
        LinearLayout rl = (LinearLayout)findViewById(R.id.widget92);

        LinearLayout.LayoutParams params1 = new LinearLayout.LayoutParams(LayoutParams.WRAP_CONTENT,LayoutParams.WRAP_CONTENT);

        for(int i=0;i<4;i++)
        {
            for(int j=0;j<10;j++)
            {System.out.println("helo");
        /*      l=l+100;
                r1=r1+100;
                t=t+100;
                b=b+100;*/
            //button();
       //ImageButton btn=new ImageButton(this);
   /*    Rect r = mTempRect;
           r.left=10;
           r.top=10;
           r.right=10;
           r.bottom=10;
       btn[i][j].getDrawingRect(r);*/

            //btn[i][j].setId(j);

              Rect r = mTempRect;
              r.set(0,0,0,0);
              Rect r2 = mTempRect;
              r2.set(0,20,0,20);

                btn[i][j]=new ImageButton(this);
                btn[i][j]. setBackgroundResource(R.drawable.icon);
                btn[i][j].setMinimumWidth(20);
                btn[i][j].setMinimumHeight(20);
                params1.setMargins(5, 5, 5,5); 
                rl.addView(btn[i][j],params1); 

               System.out.println("1="+btn[i][j].getTop());
               System.out.println("2="+btn[i][j].getLeft());
               System.out.println("3="+btn[i][j].getRight());
               System.out.println("4="+btn[i][j].getBottom());
            }
        }
    }
}

but I am getting all image buttons in a single line. How can I implement them in a grid like structure?

Jonathan Leffler
  • 730,956
  • 141
  • 904
  • 1,278
Piyush
  • 548
  • 2
  • 7
  • 19

6 Answers6

31

Implementing a horizontally scrolling GridView involves copying a few of the Android source code classes into your codebase (AdapterView, AbsListView, GridView, ScrollBarDrawable) and adding in code to handle the horizontal code. This is mainly copying some of the code and changing top to left, bottom to right, etc. The main reason for having to copy instead of extending is the final nature of those classes.

I implemented a horizontally scrolling GridView a while ago and finally got around to pushing to github: https://github.com/jess-anders/two-way-gridview

Jess Anders
  • 968
  • 1
  • 8
  • 11
  • Thanks! This worked great. Apart from thanks, I also wanted to give you a heads-up that whoever you were talking to appears to have deleted their comments making for a very one-sided conversation. Sorry also for the poor reception this answer and similar got, it definitely *is* a good answer to a lot of questions here. – blahdiblah Nov 03 '12 at 03:21
  • Really Cool. But image Quality is poor. Any way i can work on it... Thanks a lot... :) – ram Mar 11 '13 at 10:33
  • 3
    The image quality is whatever image you put in the gridview. The gridview doesn't change it. – Jess Anders Mar 11 '13 at 19:58
  • Jess, do you know how to animate cell arrangement changes when switching scrolling directions? My app has two modes, a full screen vertical grid mode, and a master/detail view with a large image detail on top and a single line horizontal grid view bar at the bottom. I've achieved this in iOS, the animation is pretty easy handled by system... As the full screen grid view slides down also scrolling direction changes to become a edge bar, I expect the arrangement of the cells will also animate. Any idea? Really appreciated. – X.Y. Jun 20 '13 at 23:43
  • This is the proper way to do it. Thumbs up. – AngraX Jul 15 '13 at 14:37
  • Not sure, you could look at animating them all yourself, but probably not worth the effort. – Jess Anders Aug 05 '13 at 20:06
  • 1
    Works really good, is there a way to use both horizontal and vertical scrolling? I need to use it as a large grid of images that can scroll in both directions. – Asaf Sep 21 '13 at 22:17
  • No, sorry, it's not built for that. – Jess Anders Sep 24 '13 at 04:26
  • its Work for me.But i want a gridview with single row.I could get it ,but the background color filles the whole area of parent,is it anyway to force wrap_content – anshad Apr 29 '14 at 13:10
13

You can

  • use a TableLayout inside a HorizontalScrollView, or
  • stay with your approach with an horizontal LinearLayout but adding vertical LinearLayouts instead of directly the images. E.g., adding three to four images per vertical LinearLayout in portrait, and redrawing to add only two in landscape.

I would try the TableLayout approach first.

PS1: for next time, try to remove all the non-relevant code (the less code is there, the easier is to understand what you did).

PS2: Remember that System.out is usually redirected to /dev/null and thus lost, so I strongly suggest you to use Log.d instead.

Complete example

Adapt this to the onCreate() method or wherever you need it:

public void horizontalScrollGalleryLayout () {
    HorizontalScrollView sv = new HorizontalScrollView(this);
    LinearLayout llh = new LinearLayout(this);
    llh.setOrientation(LinearLayout.HORIZONTAL);
    LinearLayout.LayoutParams layoutParamsTV = new LinearLayout.LayoutParams(40, 40);
    LinearLayout.LayoutParams layoutParamsLL = new LinearLayout.LayoutParams(
            LinearLayout.LayoutParams.WRAP_CONTENT, LinearLayout.LayoutParams.WRAP_CONTENT);
    for (int i=0; i<20; i++) {
        LinearLayout llv = new LinearLayout(this);
        llv.setOrientation(LinearLayout.VERTICAL);
        TestView testView1 = new TestView(this, Color.rgb(i*12, 0, 0));
        TestView testView2 = new TestView(this, true, Color.rgb(i*12, i*12, 0));
        TestView testView3 = new TestView(this, true, Color.rgb(0, i*12, 0));
        llv.addView(testView1, layoutParamsTV);
        llv.addView(testView2, layoutParamsTV);
        llv.addView(testView3, layoutParamsTV);
        llh.addView(llv, layoutParamsLL);
    }
    sv.addView(llh, layoutParamsLL);
    setContentView(sv);
}

I'm using a very simple View as an example:

public class TestView extends View {
Context context;
int color;

public TestView(Context context, int color) {
    super(context);
    this.context = context;
    this.color = color;
}

@Override
public void onDraw (Canvas canvas) {
    super.onDraw(canvas);
    this.setBackgroundColor(Color.LTGRAY);
    Paint paint = new Paint (Paint.ANTI_ALIAS_FLAG);
    paint.setColor(color);
    canvas.drawCircle(20, 20, 20, paint);
}
}
Aleadam
  • 40,203
  • 9
  • 86
  • 108
  • using table layout didn't solved my problem. Then i tried using linear layout concept but no success in taht also, still getting the same. – Piyush Apr 20 '11 at 05:42
  • what do you mean the same? A single row or no scrolling? – Aleadam Apr 20 '11 at 05:45
  • a single row with horizontal scrolling – Piyush Apr 20 '11 at 05:50
  • Dude you're impatient! I just tested this on the emulator, you get three rows of scrollable, colorful circles. Replace them with the images you want. – Aleadam Apr 20 '11 at 06:56
  • Thanx dude it is of real help...thanx alot – Piyush Apr 20 '11 at 07:15
  • Good. Please consider marking the answer as accepted then. If you feel like it was very helpful, you can always upvote it also. I see in your profile that you have no votes yet. Cheers :) – Aleadam Apr 20 '11 at 07:28
  • can u help me in one more thing, actually i have not used canvas before. So to set images do i have to create a bitmap? Or use image view. What approach i should follow? – Piyush Apr 20 '11 at 09:27
  • i got it, i can set images now. But is there any possible way to set click event on the bit map images? – Piyush Apr 20 '11 at 09:57
  • Sure. Make your `class TestView extends View implement onClickListener` and add an `onClick()` method in it. – Aleadam Apr 20 '11 at 13:30
  • To add an image, put them in the `drawable` folder in Eclipse. You can refer it as R.drawable.IMAGEFILE (without the extension). Use it to add ImageView objects. http://developer.android.com/reference/android/widget/ImageView.html – Aleadam Apr 20 '11 at 13:37
  • Hey, Thanx for your billion dollar help...Bt i am in a little fix. In this grid i am able to load array of images on a single button dynamically, bt how can i give different click events on each button. I mean that on click of particular button how can i access that paricular image id of that button? – Piyush Apr 21 '11 at 06:54
  • Hey, Aleadam, today while working on my project i encountered a problem in the grid view, we made,......, I have given buttons background images. When i navigate from one screen to other and when we again come back then,,the images from the background disappears, only buttons sre seen, with no background source. How to retain my background resources....... – Piyush Apr 22 '11 at 07:14
  • Make a snippet for the non-working code (including how you add the images) and post it as another question, as it is most probably unrelated to the grid layout. Let's keep things clean :) – Aleadam Apr 22 '11 at 14:48
  • 2
    Be wary when using this approach. Layouts do not handle recycling of views. Put to many items in the layout and you may face out of memory errors. You should look for a properly implemented horizontal list/grid view instead (one which uses the adapter classes). – AngraX Jul 15 '13 at 14:33
11

There is a very easy trick.

  1. Rotate the grid view by 270 degree and set number of columns as 2.
  2. Rotate each item to 90 degree (so that the items are displayed as original orientation).

This might be useful for some!!

abhi
  • 1,412
  • 19
  • 25
8

I have done this way:

activity_main.xml:

<HorizontalScrollView
   android:layout_width="match_parent"
   android:layout_height="wrap_content">

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

          <GridView
             android:id="@+id/gridView"
             android:layout_width="match_parent"
             android:layout_height="wrap_content">
          </GridView>

      </LinearLayout>

</HorizontalScrollView>

MainActivity.java:

GridView gridView = (GridView) findViewById(R.id.gridView);

gridView.setNumColumns(arrayList.size());

GridViewAdapter gridViewAdapter = new GridViewAdapter(mContext, arrayList);
gridView.setAdapter(gridViewAdapter); 

// Set dynamic width of Gridview
setDynamicWidth(gridView);

Add below method:

private void setDynamicWidth(GridView gridView) {
        ListAdapter gridViewAdapter = gridView.getAdapter();
        if (gridViewAdapter == null) {
            return;
        }
        int totalWidth;
        int items = gridViewAdapter.getCount();
        View listItem = gridViewAdapter.getView(0, null, gridView);
        listItem.measure(0, 0);
        totalWidth = listItem.getMeasuredWidth();
        totalWidth = totalWidth*items;
        ViewGroup.LayoutParams params = gridView.getLayoutParams();
        params.width = totalWidth;
        gridView.setLayoutParams(params);
 }

Hope this will help you.

Hiren Patel
  • 52,124
  • 21
  • 173
  • 151
  • 1
    Thanks, really helped me! Btw, I need to change layout_width of LinearLayout to wrap_content, and also getMeasuredWidth() in setDynamicWidth() gives me wrong result, so I just used hardcoded value for one item width inside this method. – Anton Malmygin Jun 24 '16 at 10:18
3

I have already posted this answer here, but both questions are identical...


There is a nice solution in Android from now on : HorizontalGridView.

1. Gradle dependency

dependencies {
    compile 'com.android.support:leanback-v17:23.1.0'
}

2. Add it in your layout

your_activity.xml

<!-- your stuff before... -->
        <android.support.v17.leanback.widget.HorizontalGridView
            android:layout_width="wrap_content"
            android:layout_height="80dp"
            android:id="@+id/gridView"
            />
<!-- your stuff after... -->

3. Layout grid element

Create a layout for your grid element ( grid_element.xml ). I have created a simple one with only one button in it.

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

    <Button
        android:layout_width="wrap_content"
        android:layout_height="wrap_content"
        android:text="New Button"
        android:id="@+id/button" />
</LinearLayout>

4. Create an adapter

Highly inspired by this link : https://gist.github.com/gabrielemariotti/4c189fb1124df4556058

public class GridElementAdapter extends RecyclerView.Adapter<GridElementAdapter.SimpleViewHolder>{

    private Context context;
    private List<String> elements;

    public GridElementAdapter(Context context){
        this.context = context;
        this.elements = new ArrayList<String>();
        // Fill dummy list
        for(int i = 0; i < 40 ; i++){
            this.elements.add(i, "Position : " + i);
        }
    }

    public static class SimpleViewHolder extends RecyclerView.ViewHolder {
        public final Button button;

        public SimpleViewHolder(View view) {
            super(view);
            button = (Button) view.findViewById(R.id.button);
        }
    }

    @Override
    public SimpleViewHolder onCreateViewHolder(ViewGroup parent, int viewType) {
        final View view = LayoutInflater.from(this.context).inflate(R.layout.grid_element, parent, false);
        return new SimpleViewHolder(view);
    }

    @Override
    public void onBindViewHolder(SimpleViewHolder holder, final int position) {
        holder.button.setText(elements.get(position));
        holder.button.setOnClickListener(new View.OnClickListener() {
            @Override
            public void onClick(View view) {
                Toast.makeText(context, "Position =" + position, Toast.LENGTH_SHORT).show();
            }
        });
    }

    @Override
    public long getItemId(int position) {
        return position;
    }

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

5. Initialize it in your activity :

private HorizontalGridView horizontalGridView;

@Override
protected void onCreate(Bundle savedInstanceState) {
    super.onCreate(savedInstanceState);
    setContentView(R.layout.your_activity);
    horizontalGridView = (HorizontalGridView) findViewById(R.id.gridView);
    GridElementAdapter adapter = new GridElementAdapter(this);

    horizontalGridView.setAdapter(adapter);
}
Community
  • 1
  • 1
kmas
  • 6,401
  • 13
  • 40
  • 62
3

Use recyclerview with setting its gridlayout as layout manager and set it to horizontal scroll

your recycle view.setLayoutManager(new GridLayoutManager(getActivity(),2, LinearLayoutManager.HORIZONTAL, false))

here 2 is the column span for grid

charan ghumman
  • 469
  • 6
  • 10