代码改变世界

Android 分享机顶盒项目的封装类《GridView》

2011-01-18 21:12  Terry_龙  阅读(6343)  评论(11编辑  收藏  举报

  由于使用系统自带的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, nullnull);

            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, nullnull);

            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 出来,但注意要设置它每列显示的个数。

下篇将讲述如何实现手势切屏,如何实现分页显示数据,如何实现封装分页控件。