自定义gradview

简介: <p>http://blog.csdn.net/jdsjlzx/article/details/7525724</p> <p><br></p> <p><br></p> <p></p> <p style="margin-top:0px; margin-bottom:0px; padding-top:0px; padding-bottom:0px; font-family:Arial;

http://blog.csdn.net/jdsjlzx/article/details/7525724



虽然Android已自带了GridView,但是,却不够灵活,同时也不能自由添加控件,因此,本人通过需要进一步封装,来实现Android自定义GridView控件,达到自己需要的效果。

我们看一下最终所需要的效果图:

说明:

上图:这里先省去分页,只讲:Android GridView 控件实现自定义。

按照上面的图例需求,大致上可以把Android GridView 画成如下的方式:

思路如下:

   默认将我们的组合控件设置为Orientation 是VERTICAL。 首先一行五个,那么一行以一个Orientation 为HORIZONTAL 的线性布局包起来。然后在一行结束后,将Orientation 的线性布局添加进组合控件里面来,不足五个则按需添加进来。

  实现这一效果我们需要两个类,一个类用来表示Android 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 的操作,等下文再讲述。效果是这样的:

全部源码为:

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

如何,看到这里,是不是觉得自定义的GridView很强大呢?大也自己DIY一下Android GridView控件自定义吧


目录
相关文章
|
4月前
|
人工智能 监控 安全
管理和调度Dify工作流
Dify是一款开源的大模型应用开发平台,支持通过可视化界面快速构建AI Agent和工作流。然而,Dify本身缺乏定时调度与监控报警功能,且执行记录过多可能影响性能。为解决这些问题,可采用Dify Schedule或XXL-JOB集成Dify工作流。Dify Schedule基于GitHub Actions实现定时调度,但仅支持公网部署、调度延时较大且配置复杂。相比之下,XXL-JOB提供秒级调度、内网安全防护、限流控制及企业级报警等优势,更适合大规模、高精度的调度需求。两者对比显示,XXL-JOB在功能性和易用性上更具竞争力。
1533 63
管理和调度Dify工作流
|
前端开发 数据可视化 JavaScript
基于React的简易数据可视化图表库集成与应用
基于React的简易数据可视化图表库集成与应用
220 1
|
机器学习/深度学习 缓存 PyTorch
异步数据加载技巧:实现 DataLoader 的最佳实践
【8月更文第29天】在深度学习中,数据加载是整个训练流程中的一个关键步骤。为了最大化硬件资源的利用率并提高训练效率,使用高效的数据加载策略变得尤为重要。本文将探讨如何通过异步加载和多线程/多进程技术来优化 DataLoader 的性能。
1849 1
|
11月前
|
传感器 物联网 定位技术
物联网卡:物联网卡不能使用,几招帮您解决!
物联网卡(IoT SIM卡)是为物联网设备(如智能家居设备、智能城市传感器、车载终端等)提供网络连接的重要组件。然而,在使用过程中,用户可能会遇到物联网卡无法使用的情况。以下是一些物联网卡不能使用的常见原因及其解决方法:
|
7月前
|
计算机视觉
RT-DETR改进策略【Neck】| GFPN 超越BiFPN 通过跳层连接和跨尺度连接改进RT-DETR颈部网络
RT-DETR改进策略【Neck】| GFPN 超越BiFPN 通过跳层连接和跨尺度连接改进RT-DETR颈部网络
186 12
RT-DETR改进策略【Neck】| GFPN 超越BiFPN 通过跳层连接和跨尺度连接改进RT-DETR颈部网络
|
7月前
|
存储 安全 数据安全/隐私保护
4S店、分公司远程访问总部DMS系统,贝锐花生壳提供高性价比方案
在汽车销售与服务行业,DMS(经销商管理系统)是日常运营的重要工具,涵盖销售、库存、售后等模块。传统远程访问方案如专线或VPN成本高且复杂,而贝锐花生壳内网穿透提供了一种高效、安全、低成本的替代方案。无需公网IP和复杂配置,只需三步即可实现DMS系统的远程访问,并支持加密传输和精细访问控制,确保数据安全。
167 16
|
8月前
|
机器学习/深度学习 人工智能 编解码
Inf-DiT:清华联合智谱AI推出超高分辨率图像生成模型,生成的空间复杂度从 O(N^2) 降低到 O(N)
Inf-DiT 是清华大学与智谱AI联合推出的基于扩散模型的图像上采样方法,能够生成超高分辨率图像,突破传统扩散模型的内存限制,适用于多种实际应用场景。
224 21
Inf-DiT:清华联合智谱AI推出超高分辨率图像生成模型,生成的空间复杂度从 O(N^2) 降低到 O(N)
|
9月前
|
SEO
CMS建站系统是什么?如何选择CMS建站系统?
本文对CMS建站系统进行了介绍,包括其类型、核心功能以及建站业务流程,希望帮助读者了解和选择适合自家企业的产品。
586 7
|
9月前
|
机器学习/深度学习 人工智能 编解码
【AI系统】轻量级CNN模型新进展
本文继续探讨CNN模型的小型化,涵盖ESPNet、FBNet、EfficientNet和GhostNet系列。ESPNet系列通过高效空间金字塔卷积减少运算量;FBNet系列采用基于NAS的轻量化网络设计;EfficientNet系列通过复合缩放方法平衡网络深度、宽度和分辨率;GhostNet系列则通过Ghost模块生成更多特征图,减少计算成本。各系列均旨在提升模型效率和性能,适用于移动和边缘设备。
408 6
|
10月前
|
编译器 Python
递归下降解析器
递归下降解析器是一种自顶向下的解析技术,常用于编译器和解释器中,通过递归函数处理语法规则,构建语法树。适用于上下文无关文法(CFG),特别是LL(1)文法。其特点是实现简单、易于理解和调试,但可能面临性能问题和不支持回溯的限制。
168 3