Android staggered GridView and androidgridview
Download Demo staggered GridView
The staggered GridView is only a GridView with unequal rows and multiple columns. You may have used Pinterest, Expedia or Etsy Android app.
Currently, there are two or three good open source libraries.
Staggered GridView Library
- Staggered GridView by Etsy
- Staggered GridView by Maurycy Wojtowicz
The following describes the most popular Etsy staggered gridview.
Etsy staggered GridView
The custom staggered GridView is based onAbsListViewClass extension, of course, it also supportsAbsListView. OnScrollListener.
Function
- You can configure the number of horizontal and vertical columns.
- The position of the asynchronous row that varies in different directions.
- Configurable margin (margin)
- Supports headers and footers ).
- Internal padding does not affect the header and footer.
Etsy's staggered gridview does not support long-pressed events and Selector drawables, while Maurycy's staggered gridview supports long-pressed events.
Environment
- Windows 2008 R2 64-bit
- Eclipse ADT V22.6.2, Android 4.4.2 (API 19)
- SAMSUNG GT-8618, Android OS 4.1.2
Project Structure
Figure 1 Project Structure
- The StaggeredGrid project is the com. etsy. android. grid library.
- The StaggeredGridDemo project is an example.
Example: Etsy staggered GridView
Figure 2 demonstrate staggered GridView
- Download/include the com. etsy. android. grid Library
Currently, the com. etsy. android. grid library is only configured to be generated using Gradle. Therefore, if you use Android Studio, you can directly include this library as the gradle dependency. If you use Eclipse/Ant, you must perform additional steps.
For the Android Studio environment:
repositories {
mavenCentral()
}
dependencies {
compile 'com.etsy.android.grid:library:x.x.x' // read below comment
}
For Eclipse/Ant build:
Download com. etsy. android. grid and import it to the project.
- Put StaggeredGridView in your layout -- activity_sgv.xml
<com.etsy.android.grid.StaggeredGridView xmlns:android="http://schemas.android.com/apk/res/android"
xmlns:app="http://schemas.android.com/apk/res-auto"
android:id="@+id/grid_view"
android:layout_width="match_parent"
android:layout_height="match_parent"
app:column_count="@integer/grid_column_count"
app:item_margin="8dp" />
- Define row layout for StaggeredGridView -- row_grid_item.xml
<?xml version="1.0" encoding="utf-8"?>
<FrameLayout xmlns:android="http://schemas.android.com/apk/res/android"
android:id="@+id/panel_content"
android:layout_width="match_parent"
android:layout_height="wrap_content"
android:descendantFocusability="blocksDescendants"
android:orientation="horizontal" >
<com.etsy.android.grid.util.DynamicHeightImageView
android:id="@+id/imgView"
android:layout_width="match_parent"
android:layout_height="match_parent"
android:scaleType="centerCrop" />
</FrameLayout>
Custom rows should containDynamicHeightImageViewOrDynamicHeightTextView.
public class SampleAdapter extends ArrayAdapter<String> {
private static final String TAG = "SampleAdapter";
private final LayoutInflater mLayoutInflater;
private final Random mRandom;
private static final SparseArray<Double> sPositionHeightRatios = new SparseArray<Double>();
public SampleAdapter(Context context, int textViewResourceId,
ArrayList<String> objects) {
super(context, textViewResourceId, objects);
this.mLayoutInflater = LayoutInflater.from(context);
this.mRandom = new Random();
}
@Override
public View getView(final int position, View convertView,
final ViewGroup parent) {
ViewHolder vh;
if (convertView == null) {
convertView = mLayoutInflater.inflate(R.layout.row_grid_item,
parent, false);
vh = new ViewHolder();
vh.imgView = (DynamicHeightImageView) convertView
.findViewById(R.id.imgView);
convertView.setTag(vh);
} else {
vh = (ViewHolder) convertView.getTag();
}
double positionHeight = getPositionRatio(position);
vh.imgView.setHeightRatio(positionHeight);
ImageLoader.getInstance().displayImage(getItem(position), vh.imgView);
return convertView;
}
static class ViewHolder {
DynamicHeightImageView imgView;
}
private double getPositionRatio(final int position) {
double ratio = sPositionHeightRatios.get(position, 0.0);
// if not yet done generate and stash the columns height
// in our real world scenario this will be determined by
// some match based on the known height and width of the image
// and maybe a helpful way to get the column height!
if (ratio == 0) {
ratio = getRandomHeightRatio();
sPositionHeightRatios.append(position, ratio);
Log.d(TAG, "getPositionRatio:" + position + " ratio:" + ratio);
}
return ratio;
}
private double getRandomHeightRatio() {
return (mRandom.nextDouble() / 2.0) + 1.0; // height will be 1.0 - 1.5
// the width
}
}
The custom adapter class is used to display images with dynamic heights in the staggered GridView. In addition, the Universal image loader library is used to asynchronously load images.
- Set the custom adapter to StaggeredGridView
public class StaggeredGridActivity extends Activity implements
AbsListView.OnScrollListener, AbsListView.OnItemClickListener {
private static final String TAG = "StaggeredGridActivity";
public static final String SAVED_DATA_KEY = "SAVED_DATA";
private StaggeredGridView mGridView;
private boolean mHasRequestedMore;
private SampleAdapter mAdapter;
private ArrayList<String> mData;
@Override
protected void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
setContentView(R.layout.activity_sgv);
setTitle("TechnoTalkative - SGV Demo");
mGridView = (StaggeredGridView) findViewById(R.id.grid_view);
mAdapter = new SampleAdapter(this, android.R.layout.simple_list_item_1,
generateData());
// do we have saved data?
if (savedInstanceState != null) {
mData = savedInstanceState.getStringArrayList(SAVED_DATA_KEY);
}
if (mData == null) {
mData = generateData();
}
for (String data : mData) {
mAdapter.add(data);
}
mGridView.setAdapter(mAdapter);
mGridView.setOnScrollListener(this);
mGridView.setOnItemClickListener(this);
}
@Override
protected void onSaveInstanceState(final Bundle outState) {
super.onSaveInstanceState(outState);
outState.putStringArrayList(SAVED_DATA_KEY, mData);
}
@Override
public void onScrollStateChanged(final AbsListView view,
final int scrollState) {
Log.d(TAG, "onScrollStateChanged:" + scrollState);
}
@Override
public void onScroll(final AbsListView view, final int firstVisibleItem,
final int visibleItemCount, final int totalItemCount) {
Log.d(TAG, "onScroll firstVisibleItem:" + firstVisibleItem
+ " visibleItemCount:" + visibleItemCount + " totalItemCount:"
+ totalItemCount);
// our handling
if (!mHasRequestedMore) {
int lastInScreen = firstVisibleItem + visibleItemCount;
if (lastInScreen >= totalItemCount) {
Log.d(TAG, "onScroll lastInScreen - so load more");
mHasRequestedMore = true;
onLoadMoreItems();
}
}
}
private void onLoadMoreItems() {
final ArrayList<String> sampleData = generateData();
for (String data : sampleData) {
mAdapter.add(data);
}
// stash all the data in our backing store
mData.addAll(sampleData);
// notify the adapter that we can update now
mAdapter.notifyDataSetChanged();
mHasRequestedMore = false;
}
private ArrayList<String> generateData() {
ArrayList<String> listData = new ArrayList<String>();
listData.add("http://images.cnblogs.com/cnblogs_com/liuning8023/610092/o_2iitkhx.jpg");
listData.add("http://images.cnblogs.com/cnblogs_com/liuning8023/610092/o_w0omeb.jpg");
listData.add("http://images.cnblogs.com/cnblogs_com/liuning8023/610092/o_w9iu1d.jpg");
listData.add("http://images.cnblogs.com/cnblogs_com/liuning8023/610092/o_iw6kh2.jpg");
listData.add("http://images.cnblogs.com/cnblogs_com/liuning8023/610092/o_ru08c8.jpg");
listData.add("http://images.cnblogs.com/cnblogs_com/liuning8023/610092/o_k12r10.jpg");
listData.add("http://images.cnblogs.com/cnblogs_com/liuning8023/610092/o_2e3daug.jpg");
listData.add("http://images.cnblogs.com/cnblogs_com/liuning8023/610092/o_2igznfr.jpg");
return listData;
}
@Override
public void onItemClick(AdapterView<?> adapterView, View view,
int position, long id) {
Toast.makeText(this, "Item Clicked: " + position, Toast.LENGTH_SHORT)
.show();
}
}
Table 1 configurable properties of the staggered GridView
Attribute |
Description |
Item_margin |
The margin around each grid item (default 0dp ). |
Column_count |
The number of columns displayed. Will override column_count_portrait and column_count_landscape if present (default 0 ). |
Column_count_portrait |
The number of columns displayed when the grid is in portrait (default 2 ). |
Column_count_landscape |
The number of columns displayed when the grid is in landscape (default 3 ). |
Grid_paddingLeft |
Padding to the left of the grid. Does not apply to headers and footers (default 0 ). |
Grid_paddingRight |
Padding to the right of the grid. Does not apply to headers and footers (default 0 ). |
Grid_paddingTop |
Padding to the top of the grid. Does not apply to headers and footers (default 0 ). |
Grid_paddingBottom |
Padding to the bottom of the grid. Does not apply to headers and footers (default 0 ). |