原文地址

本文演示在你的 Android 应用程序中显示交错 GridView(Staggered GridView )。

下载 Demo

交错 GridView


交错 GridView 只是具有不等大小行、多个列的 GridView。你可能已经使用过 Pinterest,Expedia 或 Etsy Android app。

目前,已经有 2、3 个很不错的开源库。

交错 GridView 库

下面说明最流行使用最广泛的 Etsy 的交错 gridview。

Etsy 交错 GridView


自定义的交错 GridView 是根据 AbsListView 类扩展的,它当然也就支持 AbsListView.OnScrollListener

功能

  • 可以配置横向和纵向的列数量。
  • 跨方向变化的异步行位置。
  • 可配置项的边距(margin)
  • 支持页眉(header)和页脚(footer)。
  • 内部填充(Internal padding ),不影响页眉和页脚。

Etsy 的交错 gridview 不支持项的长按事件和选择器 drawables,而 Maurycy 的交错 gridview 则支持长按事件。

环境

  • Windows 2008 R2 64 位
  • Eclipse ADT V22.6.2,Android 4.4.2(API 19)
  • SAMSUNG GT-8618,Android OS 4.1.2

项目结构

图 1 项目结构

  • StaggeredGrid 项目是 com.etsy.android.grid 库。
  • StaggeredGridDemo 项目是示例。

示例:Etsy 交错 GridView

图 2 演示交错 GridView

  • 下载/包含库 com.etsy.android.grid

com.etsy.android.grid 库目前配置为只能通过 Gradle 生成,因此,如果您使用 Android Studio,那么你可以直接的方式包括这个库,作为 gradle 依赖来生成。如果你使用 Eclipse/ Ant,那么你必须执行额外的步骤。

对 Android Studio 环境:

repositories {
    mavenCentral()
}
 
dependencies {
    compile 'com.etsy.android.grid:library:x.x.x' // read below comment
}

对 Eclipse/Ant build:

下载 com.etsy.android.grid,并导入到项目。

  • 把 StaggeredGridView 放到你的布局——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" />
  • 为 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>

自定义行应该包含 DynamicHeightImageView 或 DynamicHeightTextView

  • 自定义 adapter
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
    }
}

自定义 adapter 类用来在交错 GridView 中显示动态高度的图片。另外,还使用了 Universal image loader 库用来异步加载图片。

  • 把自定义 adapter 设置给 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();
    }
}

表 1 交错 GridView 可配置的属性

属性

说明

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).

参考资料


下载 Demo

Android 交错 GridView的更多相关文章

  1. Android中GridView通过自定义适配器(未优化)实现图文视图排列

    Android中GridView组件用来以网格方式排列视图,与矩阵类似,当屏幕上有很多元素(文字.图片或其他元素)需要显示时,可以使用该组件.下面我们通过代码实现如下图例(为了方便截图,将事件处理(土 ...

  2. Android中GridView拖拽的效果【android进化三十六】

      最 近看到联想,摩托罗拉等,手机launcher中有个效果,进入mainmenu后,里面的应用程序的图标可以拖来拖去,所以我也参照网上给的代码,写了 一个例子.还是很有趣的,实现的流畅度没有人家的 ...

  3. Android中GridView的实现实例

    实现效果: activity文件代码: package com.tmacsky; import android.app.Activity; import android.os.Bundle; impo ...

  4. Android中GridView拖拽的效果

    最 近看到联想,摩托罗拉等,手机launcher中有个效果,进入mainmenu后,里面的应用程序的图标可以拖来拖去,所以我也参照网上给的代码,写了 一个例子.还是很有趣的,实现的流畅度没有人家的那么 ...

  5. android 31 GridView

    GridView:网格列表,也支持适配器. package com.sxt.day05_01; import java.util.ArrayList; import java.util.List; i ...

  6. Android的GridView和Gallery结合Demo

    Android的GridView和Gallery结合Demo Demo介绍:首页是一个GridView加载图片,竖屏时显示3列图片,横屏时显示4列图片;并且对图片进行大小限制和加灰色边框处理. 点击某 ...

  7. Android中GridView的使用——使用自带的SimpleAdapter(简单适配器)

    GridView一直是一个系统登录后以九宫格方式展现功能子模块的最佳选择,经过试验和网上资料的查阅,现把实现方式总结一下: 一直是通过自定义Adapter方式,在getView()方法中设置图片的显示 ...

  8. 从头学起android&lt;GridView网格视图.二十八.&gt;

    GridView基于组件的网络格所有的形式的组分的,例如:当制作专辑,所有的图片将在相同的尺寸在不同的显示格在孩子,是否能够依靠这个组件完成.此组件的继承结构参见例如下面: java.lang.Obj ...

  9. Android中用GridView实现九宫格的两种方法(转)

    Android中用GridView实现九宫格的两种方法http://blog.csdn.net/shakespeare001/article/details/7768455 1.传统办法:实现一个继承 ...

随机推荐

  1. JS字符串常用方法

      // 来自 http://www.runoob.com/js/js-strings.html   var str01 = "odd open xboxone" , str02 ...

  2. Android单位度量

    px(像素):屏幕上的点. in(英寸):长度单位.mm(毫米):长度单位.pt(磅):1/72英寸.dp(与密度无关的像素):一种基于屏幕密度的抽象单位.在每英寸160点的显示器上,1dp = 1p ...

  3. 安装vs2013 Sqlserver 无法连接远程服务器的解决方法

    以“管理员身份”启动cmd,执行“netsh winsock reset”命令.

  4. 001.为什么选择用AngularJs开发?

    网上关于AngularJs(https://angularjs.org/)的介绍与好处已经相当多了,大家可以自己去搜索看看,很多很多. 1.疯狂的原生的App开发 在这里我主要谈一下我自己为什么要使用 ...

  5. linux 命令——PS命令

    首先要明白什么是进程进程是一个正在运行的程序.也就是说在Linux系统上运行的所有东西都是进程.和进程相比较,作业是一系列按一定顺序执行的命令.一条简单的命令可能会涉及多个进程,尤其是当使用管道和重定 ...

  6. 【PRO ASP.NE MVC4 学习札记】使用Moq辅助进行单元测试

    清楚问题所在: 先开个头,当我们对A进行单元测试时,可能会发现A的实现必须要依赖B.这时,我们在写单元测试时,就必须先创建B的实例,然后把B传给A再建立A的实例进行测试. 这样就会出现一些问题: 1. ...

  7. Egret 矢量绘图、遮罩、碰撞检测

    矢量绘图: 1. 为矢量绘图绘制外边 - graphics.lineStype() private createGameScene():void { console.log("Runtime ...

  8. Android4.2增加新键值

    这里添加新的键值,不是毫无凭据凭空创造的一个键值, 而是根据kernel中检测到的按键值,然后转化为android所需要的数值: 以添加一个linux键值为217,把它映射为android的键值Bro ...

  9. 转:如何查看linux版本 如何查看LINUX是多少位

    原文来自于:http://blog.csdn.net/hongweigg/article/details/7192471 一.如何得知自己正在使用的linux是什么版本呢,下面的几种方法将给你带来答案 ...

  10. centos7 install mongodb

    $vi /etc/yum.repos.d/mongodb-org-3.0.repo [mongodb-org-3.0] name=MongoDB Repository baseurl=http://r ...