由于使用系统自带的GridView 不够灵活,不能允许拖拉控件,故自己结合LinearLayout 封装的一个GridView ,通过本篇文章的阅读你可以学会如何自定义控件,如何使用组合控件,如何为自己的组合控件添加数据源和如何为自定义控件添加属性。
首先,我们要实现的效果是这样的:
上面1 2也是一个封装控件,用来为应用程序分页,具体如何实现下篇文章会提到,本篇先讲GridView。如图,这是一个标准的800*480大小的屏幕,所以设置了一页GridView 显示的应用程序数据为 三行五列,不足五列则按需显示。
按照上面的图例需求,大致上可以把GridView 画成如下的方式:
思路如下:
默认将我们的组合控件设置为Orientation 是VERTICAL。 首先一行五个,那么一行以一个Orientation 为HORIZONTAL 的线性布局包起来。然后在一行结束后,将Orientation 的线性布局添加进组合控件里面来,不足五个则按需添加进来。
实现这一效果我们需要两个类,一个类用来表示GridView 的行,这里我们起名为TableRow,代码如下:
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() { return cell.length; } 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() { @Override 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 ) { lastRowCount = j; 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, 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(); }
当然,你必须在res 创建属性xml ,这里不多讲,可以去我博客看看如何为 View 添加属性 。
还有,还必须实现它的支持键盘的上下左右的焦点,下面的代码将会提供该功能,但还必须配合Activity 的操作,等下文再讲述。效果是这样的:
该 类的全部源码为:
GridViewExt 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 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(); } public void setOnItemClickListener(onItemClickListener click) { this .onItemClickEvent = click; } public void setOnLongPressListener(onLongPressExt longPress) { this .onLongPress = longPress; } public void NotifyDataChange() { removeAllViews(); } 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() { @Override 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 ) { lastRowCount = j; 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, j, tr); } } } 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 setAdapter(AppsAdapter appsAdapter) { this .adapter = appsAdapter; this .setOrientation(LinearLayout.VERTICAL); bindView(); } 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); } if (name[ 1 ].toString().equals( " 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 ); HashMap < String, Object > map = new HashMap < String, Object > (); 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 ); } } 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() { return cell.length; } public int getLastCellCount() { return lastRowCount; } } static public class TableCell { private Object value; public TableCell(Object value) { this .value = value; } public Object getValue() { return value; } }}
每行显示的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 出来,但注意要设置它每列显示的个数。
下篇将讲述如何实现手势切屏,如何实现分页显示数据,如何实现封装分页控件。
转载于:https://www.cnblogs.com/TerryBlog/archive/2011/01/18/1938637.html
相关资源:数据结构—成绩单生成器