Click here to Skip to main content
Click here to Skip to main content

Create a Dynamic Shelfview in Android?

By , 16 Sep 2012
 

Introduction

As you know, Android doesn’t support ListView with horizontal view feature. There is a way to make it as a gallery or TableLayout (you can see my tip in here). Of course, I'll describe them.

Background

Notice, in this application I use two classes:

  • HorizontalListView class that extends the AdapterView. It has been downloaded from GitHub.
  • Quaere library used almost the same as Linq2Object in .NET. You can download it here.

Other Approaches

In here, I want to describe other ways for showing a shelf view (I mean a listview that can show multi items in every row and every row can scroll horizontal).

First Way - Gallery

In "main.xml" file, we code only LinearLayout with an ID. Then, in Java class, try to create a multi gallery and insert in LinearLayout every gallery that plays the role of row:

public class MainActivity extends Activity {	
	//---the images to display---
    Integer[] imageIDs = {
            R.drawable.pic1,
            R.drawable.pic2,
            R.drawable.pic3,
            R.drawable.pic4,
            R.drawable.pic5,
            R.drawable.pic6,
            R.drawable.pic7                    
    };
    
    /** Called when the activity is first created. */
    @Override
    public void onCreate(Bundle savedInstanceState) {
        super.onCreate(savedInstanceState);
        setContentView(R.layout.main);
        
        for(int i = 0; i < 5 ; i++){
		Gallery gallery = (Gallery) findViewById(R.id.gallery1);
		gallery.setAdapter(new ImageAdapter(this));
        }        
    }
    
    public class ImageAdapter extends BaseAdapter 
    {
        private Context context;
        private int itemBackground;
 
        public ImageAdapter(Context c) 
        {
            context = c;
            //---setting the style---
            TypedArray a = obtainStyledAttributes(R.styleable.Gallery1);
            itemBackground = a.getResourceId(
                R.styleable.Gallery1_android_galleryItemBackground, 0);
            a.recycle();                    
        }
 
        //---returns the number of images---
        public int getCount() {
            return imageIDs.length;
        } 
        
        //---returns the ID of an item--- 
        public Object getItem(int position) {
            return position;
        }            
        
        //---returns the ID of an item---         
        public long getItemId(int position) {
            return position;
        }
  
        //---returns an ImageView view---
        public View getView(int position, View convertView, ViewGroup parent) {
            ImageView imageView = new ImageView(context);
            imageView.setImageResource(imageIDs[position]);
            imageView.setScaleType(ImageView.ScaleType.FIT_XY);
            imageView.setLayoutParams(new Gallery.LayoutParams(150, 120));
            imageView.setBackgroundResource(itemBackground);
 
            return imageView;
        }
    }    
}

There is some problem in this way, one problem related to view position about items is that it appears in the center of display and I can't resolve it.

Second Way - TableLayout

It has already been fully described in this tip. Of course, it has some problems too such as it is unsupported for virtualization as AdapterView.

The Beginning

Now, we want to introduce a new way that consists of the following advantages vs. the above ways:

  • Support virtualization
  • Use Array Adapter instead of loop statements for creating a list of items
  • Every row can make separate other rows

Before doing anything else, please add Quaere library.

In our example, you will define your layout for the items, rows and a layout for base scheme and use it in your adapter or another place. We want to plan two list views - the first list view (we call it child ListView) acts horizontal and the second list view (we call it parent ListView) includes multi child ListView and scrolling as vertical.

Create the "item.xml" layout file in the "res/layout" folder of the project.

<?xml version="1.0" encoding="utf-8"?>
<LinearLayout xmlns:android="http://schemas.android.com/apk/res/android"
    android:layout_width="fill_parent"
    android:layout_height="fill_parent"
    android:orientation="vertical" >
 
    <ImageView
        android:id="@+id/icon"
        android:layout_width="80dip"
        android:layout_height="100dip"
        android:paddingLeft="10dip"
        android:src="@drawable/book" />
 
    <TextView
        android:id="@+id/title"
        android:layout_width="fill_parent"
        android:layout_height="wrap_content"
        android:gravity="center_horizontal"
        android:text="Simple"
        android:textColor="#000"
        android:textSize="15px" />
 
    <TextView
        android:id="@+id/author"
        android:layout_width="fill_parent"
        android:layout_height="wrap_content"
        android:gravity="center_horizontal"
        android:text="Simple"
        android:textColor="#000"
        android:textSize="15px" />
</LinearLayout> 

"item.xml" layout file is used in child ListView. Now create the "row.xml" layout file in the "res/layout" folder of project. "row.xml" defines a new listview from HorizontalListView class instead of a common ListView.

 <LinearLayout xmlns:android="http://schemas.android.com/apk/res/android"
    android:layout_width="fill_parent"
    android:layout_height="fill_parent"
    android:orientation="vertical" >
 
    <com.onazifi.shelf.HorizontalListView
        android:id="@+id/subListview"
        android:layout_width="fill_parent"
        android:layout_height="130dip"
        android:background="@drawable/shelf1" />
</LinearLayout> 

Notice, I've written "com.onazifi.shelf. ", it is related to my project folders and if you use it, change its address.

Ok, create "main.xml" file:

<LinearLayout xmlns:android="http://schemas.android.com/apk/res/android"
    android:layout_width="fill_parent"
    android:layout_height="fill_parent"
    android:orientation="vertical" 
    android:id="@+id/lineLayout">
 
    <ListView
        android:id="@+id/android:list"
        android:layout_width="fill_parent"
        android:layout_height="fill_parent" />
</LinearLayout>

Create BookItem class for map components of item and Library class for making list of BookItem. In this class, there is a "groupbyArrayBookItem" method for grouping a list of items. This method uses the quaere library for grouping. This library acts as LINQ in .NET.

 public class Library {
 
	private ArrayList<BookItem> arrayBookItem;
	public static final int AUTHOR = 1;
	public static final int TITLE = 2;
	public static final int RATE = 3;
	public static final int DOWNLOAD_DATE = 4;
 
	public Library() {
		arrayBookItem = new ArrayList<BookItem>();
	}
 
	public void setColectionBookItem(ArrayList<BookItem> _array) {
		this.arrayBookItem = _array;
	}
 
	public void addBookItem(BookItem _bi) {
		this.arrayBookItem.add(_bi);
	}
 
	public ArrayList<ArrayList<BookItem>> groupbyArrayBookItem(int type) {
 
		BookItem[] books = BookItem.ALL_BOOKS;
		ArrayList<ArrayList<BookItem>> groupList = 
				new ArrayList<ArrayList<BookItem>>();
		String getType = "";
		
		switch (type) {
		case AUTHOR:
			getType = "bookitem.getAuthor()";
			break;
		case TITLE:
			getType = "bookitem.getTitle()";
			break;
		case DOWNLOAD_DATE:
			getType = "bookitem.getDownloadDate()";
			break;
		case RATE:
			getType = "bookitem.getRate()";
			break;
		default:
			return groupList;
		}
 
		/*
		 * books is a object of BookItem
		 * bookitem is item for point to list
		 * getType is a string value for set type of grouping
		 * groupbyArrayBookItem return back array of array of items
		 */
		Iterable<Group> groups = 
				from("bookitem").in(books).group("bookitem")
				.by(getType).into("g").select("g");
 
		for (Group group : groups) {
			ArrayList<BookItem> obj = new ArrayList<BookItem>();
			for (Object Item : group.getGroup()) {
				obj.add((BookItem) Item);
			}
			groupList.add(obj);
		}
		return groupList;
	}
}

And finally, survey ShelfViewActivity class. In this class, we call library class to get an array of array of items. Then set adapter parent array list to parent ListView and in adapter class, call another adapter class for creating a list of items in child ListView.

 public class ShelfViewActivity extends ListActivity {
	/** Called when the activity is first created. */
	private VerticalAdapter verListAdapter;
 
	@Override
	public void onCreate(Bundle savedInstanceState) {
		super.onCreate(savedInstanceState);
		setContentView(R.layout.main);
 
		/*
		 * Calling Library & BookItem classes for create list of groups
		 *  groupbyArrayBookItem return back array of array of items
		 */
		Library lb = new Library();
		for (BookItem item : BookItem.ALL_BOOKS) {
			lb.addBookItem(item);
		}
		ArrayList<ArrayList<BookItem>> groupList = 
				new ArrayList<ArrayList<BookItem>>();
		groupList = lb.groupbyArrayBookItem(Library.AUTHOR);
 
		verListAdapter = new VerticalAdapter(this, R.layout.row, groupList);
		setListAdapter(verListAdapter);
 
		verListAdapter.notifyDataSetChanged();
	}
 
	/**
	 * This class add a list of ArrayList to ListView that it include multi
	 * items as bookItem.
	 */
	private class VerticalAdapter extends ArrayAdapter<ArrayList<BookItem>> {
 
		private int resource;
 
		public VerticalAdapter(Context _context, int _ResourceId,
				ArrayList<ArrayList<BookItem>> _items) {
			super(_context, _ResourceId, _items);
			this.resource = _ResourceId;
		}
 
		@Override
		public View getView(int position, View convertView, ViewGroup parent) {
			View rowView;
 
			if (convertView == null) {
				rowView = LayoutInflater.from(getContext()).inflate(resource,
						null);
			} else {
				rowView = convertView;
			}
 
			HorizontalListView hListView = (HorizontalListView) rowView
					.findViewById(R.id.subListview);
			HorizontalAdapter horListAdapter = new HorizontalAdapter(
					getContext(), R.layout.item, getItem(position));
			hListView.setAdapter(horListAdapter);
 
			return rowView;
		}
	}
 
	/*
	 * This class add some items to Horizontal ListView this ListView include
	 * several bookItem.
	 */
	private class HorizontalAdapter extends ArrayAdapter<BookItem> {
 
		private int resource;
 
		public HorizontalAdapter(Context _context, int _textViewResourceId,
				ArrayList<BookItem> _items) {
			super(_context, _textViewResourceId, _items);
			this.resource = _textViewResourceId;
		}
 
		@Override
		public View getView(int position, View convertView, ViewGroup parent) {
			View retval = LayoutInflater.from(getContext()).inflate(
					this.resource, null);
 
			TextView topText = (TextView) retval.findViewById(R.id.title);
			TextView bottomText = (TextView) retval
					.findViewById(R.id.author);
 
			topText.setText(getItem(position).getAuthor());
			bottomText.setText(getItem(position).getTitle());
 
			return retval;
		}
	}
}

Summary

If you pay attention to the source code, you'll learn how to create new classes that extend from Android base class.

Notice that there are images for showing in "res/drawable". Also, this project has been coded in Android 4.0 with android:minSdkVersion="14".

I have tried to describe my project completely and I hope the project will be useful for you.

License

This article, along with any associated source code and files, is licensed under The Code Project Open License (CPOL)

About the Author

omid.nazifi
Iran (Islamic Republic Of) Iran (Islamic Republic Of)
Member
No Biography provided

Sign Up to vote   Poor Excellent
Add a reason or comment to your vote: x
Votes of 3 or less require a comment

Comments and Discussions

 
You must Sign In to use this message board.
Search this forum  
    Spacing  Noise  Layout  Per page   
QuestionAddilng image icons [modified]memberZubair KK28 Feb '13 - 18:55 
Thanks for this nice post. But i have a small problem.
How to add different images to image icons after separating images by author.
 
Note:: i can't add images to BookItem class.

modified 1 Mar '13 - 1:24.

AnswerRe: Addilng image iconsmemberomid.nazifi16 Mar '13 - 19:27 
Dear Zubair, You can change array of Images with different pictures. If you use a sqlite db, you can add a field for any icon.
 
Why did you can't add images to BookItem class?
QuestionIncreasing Space in TableRowmemberSultan Ahmed Sagor9 Feb '13 - 12:17 
I am following your tutorial of making a selfview using tablelayout . I want to make show only 4 items in a row . What can I do ?
AnswerRe: Increasing Space in TableRowmemberomid.nazifi10 Feb '13 - 22:43 
If you wanna show just four items in every row, you can use GridLayout or use TableLayout(and control item number programmatically).
QuestionThanks.....membersowcom26 Dec '12 - 15:53 
was helpful. Thank you... Smile | :)
QuestionProblem fix for “NoClassDefFoundError” with ADT 17memberAnilkutsa26 Nov '12 - 23:15 
Hi omid,
 
Cant thank much for helping understand the dynamic shelf application.
 
But, I got a “NoClassDefFoundError” on running the code in eclipse.
 
After a elaborate search I found the below link, which helped me fix the issue.
 
http://android.foxykeep.com/dev/how-to-fix-the-classdefnotfounderror-with-adt-17[^]
 
Hope someone in need finds this helpful. Cheers.
QuestionScrolling issuememberMember 801090520 Nov '12 - 0:34 
The scrolling is too slow how to modify it and make it normal
BugThe code does not runmemberimgen24 Sep '12 - 15:55 
When run, it stops immediately. Any idea? I'm using all the latest Eclipse Juno, Latest ADT, Android 4.1 x86 emulator
GeneralRe: The code does not runmemberomid.nazifi26 Sep '12 - 2:57 
What error did you get?
You should add jar files (those are in lib folder) to program with following path:
Right click on App -> properties -> Java Build path -> libraries then add them. OK?
 
If you introduced them, please clean app from Project menu -> Clean...
GeneralRe: The code does not runmemberimgen23 Oct '12 - 13:36 
I already fixed this issue, but exactly how I forget. I'll try to recall or do a diff and if I have any success will let you know.
Imgen Tata
Coding while you can

QuestionQuaere Libraymembervivek18ssb14 Sep '12 - 21:38 
Hello sir as your this post is very useful but there is a problem that i cannot find the quaere library on the link u specified....and i also searched it a lot but couldn't succeed...could u please send me that library or its .Jar file on my mailId(vivek19ssb@gmail.com) or simply tell me where i can get this library.......
 
Thanks in advance
AnswerRe: Quaere Libraymemberomid.nazifi15 Sep '12 - 18:46 
@vivek-singh: You should get it's source with SVN. exact address is "http://quaere.codehaus.org/Get+Involved"
AnswerRe: Quaere Libraymemberomid.nazifi16 Sep '12 - 18:40 
As I mentioned it if you wanna get it, you should use SVN and write this url into SVN software "http://svn.codehaus.org/quaere/trunk/". but you can download my code from code-project, I added Lib into it.
 
Also I'll email code source with libraries to you. Smile | :)
Omid Nazifi

GeneralRe: Quaere Libraymembermuhammadfurqaan6 Nov '12 - 20:56 
i am getting an error on the startup of application
i-e My library has stopped .. i have just imported your code as it is ..
Questionimportant topicmembercarlospenny22 May '12 - 0:32 
That was indeed an important topic that you have shared and discuss about the codes that was really needed and understood and rightly implemented after you have described it in the post thank you for sharing this information with all of us.
 

TCM forklift parts

General General    News News    Suggestion Suggestion    Question Question    Bug Bug    Answer Answer    Joke Joke    Rant Rant    Admin Admin   

Permalink | Advertise | Privacy | Mobile
Web01 | 2.6.130516.1 | Last Updated 17 Sep 2012
Article Copyright 2012 by omid.nazifi
Everything else Copyright © CodeProject, 1999-2013
Terms of Use
Layout: fixed | fluid