http://blog.csdn.net/jdsjlzx/article/details/7525724
我們看一下最終所需要的效果圖:
說明:
思路如下:
預設将我們的組合控件設定為orientation 是vertical。 首先一行五個,那麼一行以一個orientation 為horizontal 的線性布局包起來。然後在一行結束後,将orientation 的線性布局添加進組合控件裡面來,不足五個則按需添加進來。
public class tablerow {
private tablecell[] cell;
public tablerow(tablecell[] cell) {
this.cell = cell;
}
public int getsize() {
return cell.length;
public tablecell getcellvalue(int index) {
if (index >= getsize()) {
return null;
return cell[index];
public int getcellcount() {
public int getlastcellcount() {
return lastrowcount;
另外一個類用來表示gridview 每行的列個,這裡我們取名為tablecell,代碼如下:
static public class tablecell {
private object value;
public tablecell(object value) {
this.value = value;
public object getvalue() {
return value;
并且我們還需要為gridview 設定一個外部可添加資料的方法,代碼如下:
public void setadapter(appsadapter appsadapter) {
this.adapter = appsadapter;
this.setorientation(linearlayout.vertical);
bindview();
其中,appsadapter 是一個自定義的baseadapter ,代碼很簡單,這裡就不列出來了。關鍵的還是要看bindview ,這個方法是本篇gridview 顯示資料的核心方法,代碼如下:
void bindview() {
removeallviews();
int count = adapter.getcount();
tablecell[] cell = null;
int j = 0;
linearlayout layout;
tablerowslist = new arraylist<hashmap<string, object>>();
for (int i = 0; i < count; i++) {
j++;
final int position = i;
if (j > getcolumncount() || i == 0) {
cell = new tablecell[getcolumncount()];
final view view = adapter.getview(i, null, null);
view.setontouchlistener(new ontouchlistener() {
@override
public boolean ontouch(view v, motionevent event) {
// todo auto-generated method stub
uncheckpressed();
checkrowid = -1;
checkcolumnid = -1;
if (onitemclickevent != null) {
onitemclickevent.onitemclick(position, event, view);
return false;
});
view.setonlongclicklistener(new onlongclicklistener() {
public boolean onlongclick(view v) {
if (onlongpress != null) {
onlongpress.onlongpress(v);
return true;
cell[j - 1] = new tablecell(view);
if (j == getcolumncount()) {
lastrowcount = j;
j = 0;
hashmap<string, object> map = new hashmap<string, object>();
tablerow tr = new tablerow(cell);
map.put("tablerow", tr);
tablerowslist.add(map);
layout = new linearlayout(getcontext());
addlayout(layout, cell, tr.getsize(), tr);
} else if (i >= count - 1 && j > 0) {
addlayout(layout, cell, j, tr);
getcolumncount()是一個屬性,表示可以從xml或者從代碼動态改變gridview 每列顯示的個數,屬性點的代碼為如下:
public gridviewext(context context, attributeset attrs) {
super(context, attrs);
int resouceid = -1;
typedarray typedarray = context.obtainstyledattributes(attrs,
r.styleable.gridviewext);
int n = typedarray.getindexcount();
for (int i = 0; i < n; i++) {
int attr = typedarray.getindex(i);
switch (attr) {
case r.styleable.gridviewext_columncount:
resouceid = typedarray.getint(
r.styleable.gridviewext_columncount, 0);
setcolumncount(resouceid);
break;
typedarray.recycle();
還有,還必須實作它的支援鍵盤的上下左右的焦點,下面的代碼将會提供該功能,但還必須配合activity 的操作,等下文再講述。效果是這樣的:
全部源碼為:
package com.yaomei.widget;
import java.util.arraylist;
import java.util.hashmap;
import java.util.list;
import android.content.context;
import android.content.intent;
import android.content.res.typedarray;
import android.util.attributeset;
import android.view.gravity;
import android.view.motionevent;
import android.view.view;
import android.view.viewgroup;
import android.widget.linearlayout;
import android.widget.textview;
import com.yaomei.activity.adapter.appsadapter;
import com.yaomei.activity.info.r;
public class gridviewext extends linearlayout {
public list<hashmap<string, object>> tablerowslist;
private list<hashmap<string, object>> app = new arraylist<hashmap<string, object>>();
private appsadapter adapter;
onitemclicklistener onitemclickevent;
onlongpressext onlongpress;
int checkrowid = -1; // 選中行的下标
int checkcolumnid = -1; // 選中列的下标
int lastrowcount = -1; // 最後一行的總數
private int columncount; // 每列的總數
public void setcolumncount(int count) {
this.columncount = count;
public int getcolumncount() {
return columncount;
public interface onitemclicklistener {
public boolean onitemclick(int position, motionevent event, view view);
public interface onlongpressext {
public boolean onlongpress(view view);
public gridviewext(context context) {
this(context, null);
// todo auto-generated constructor stub
public void setonitemclicklistener(onitemclicklistener click) {
this.onitemclickevent = click;
public void setonlongpresslistener(onlongpressext longpress) {
this.onlongpress = longpress;
public void notifydatachange() {
private void addlayout(linearlayout layout, tablecell[] cell, int size,
tablerow tr) {
linearlayout.layoutparams params = new linearlayout.layoutparams(130,
110);
layout.setgravity(gravity.left);
layout.setorientation(linearlayout.horizontal);
for (int k = 0; k < size; k++) {
view remoteview = (view) tr.getcellvalue(k).getvalue();
layout.addview(remoteview, k, params);
linearlayout.layoutparams firstparams = new linearlayout.layoutparams(
layoutparams.wrap_content, layoutparams.wrap_content);
firstparams.leftmargin = 60;
addview(layout, firstparams);
public void checkpressed(int tablerowid, int tablerowcolumnid) {
viewgroup view = (viewgroup) this.getchildat(tablerowid);
checkcolumnid = tablerowcolumnid;
checkrowid = tablerowid;
changeimagestate(view.getchildat(tablerowcolumnid), app);
public void onclick(int tablerowid, int tablerowcolumnid, context context) {
linearlayout view = (linearlayout) ((viewgroup) this
.getchildat(tablerowid)).getchildat(tablerowcolumnid);
textview tv = (textview) view.findviewbyid(r.id.folder);
final string[] name = tv.gettext().tostring().split("-");
intent intent = null;
if (name[0].tostring().equals("com.android.contacts"))
{
if (name[1].tostring().equals(
"com.android.contacts.dialtactsactivity")) {
intent = new intent(intent.action_dial);
"com.android.contacts.dialtactscontactsentryactivity")) {
intent = new intent(intent.action_call_button);
} else {
intent = getcontext().getpackagemanager()
.getlaunchintentforpackage(name[0].tostring());
context.startactivity(intent);
/**
* 改變圖檔狀态
*
* @param v
* @param list
*/
private void changeimagestate(view v, list<hashmap<string, object>> list) {
int size = list.size();
for (int i = 0; i < size; i++) {
view view = (view) list.get(i).get("touch");
view.setpressed(false);
list.remove(i);
v.setpressed(true);
map.put("touch", v);
list.add(map);
public void uncheckpressed() {
if (checkcolumnid != -1 && checkrowid != -1) {
viewgroup view = (viewgroup) this.getchildat(checkrowid);
view.getchildat(checkcolumnid).setpressed(false);
每行顯示的layout檔案:
<linearlayout android:orientation="vertical"
android:background="@drawable/lessbtn" android:gravity="center"
android:layout_width="fill_parent" android:id="@+id/grid_layout"
android:layout_height="fill_parent" xmlns:android="http://schemas.android.com/apk/res/android">
<imageview android:id="@+id/btn_appicon"
android:layout_width="55dip" android:layout_height="55dip"></imageview>
<textview android:id="@+id/tv_name" android:layout_width="wrap_content"
android:textcolor="#030303" android:layout_height="wrap_content"></textview>
<textview android:id="@+id/folder" android:layout_width="wrap_content"
android:visibility="invisible" android:layout_height="wrap_content"></textview>
</linearlayout>
完成這一系列的編寫後,你就可以在xml直接寫或者在java檔案裡面new 出來,但注意要設定它每列顯示的個數。