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 {
Integer[] imageIDs = {
R.drawable.pic1,
R.drawable.pic2,
R.drawable.pic3,
R.drawable.pic4,
R.drawable.pic5,
R.drawable.pic6,
R.drawable.pic7
};
@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;
TypedArray a = obtainStyledAttributes(R.styleable.Gallery1);
itemBackground = a.getResourceId(
R.styleable.Gallery1_android_galleryItemBackground, 0);
a.recycle();
}
public int getCount() {
return imageIDs.length;
}
public Object getItem(int position) {
return position;
}
public long getItemId(int position) {
return position;
}
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.
="1.0"="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;
}
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 {
private VerticalAdapter verListAdapter;
@Override
public void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
setContentView(R.layout.main);
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();
}
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;
}
}
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.