自定义gradview

虽然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, 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 的操作,等下文再讲述。效果是这样的:

全部源码为:

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

本文参与腾讯云自媒体分享计划,欢迎正在阅读的你也加入,一起分享。

发表于

我来说两句

0 条评论
登录 后参与评论

相关文章

来自专栏向治洪

高仿今日头条(1)

本片博客主要实现今日头条的主题框架。后面我会慢慢完善,欢迎大家持续关注 git下载地址:https://github.com/xiangzhihong/topN...

3657
来自专栏向治洪

Android侧滑删除另一种实现,SwipeListView补充

前不久在在做聊天删除功能的时候使用SwipeListView进行侧滑删除有一点小问题,因为SwipeListView嵌套在Fragment内的时候,会报一个转换...

3345
来自专栏Android小菜鸡

自定义广告图片轮播View——CarouselView

  因为一个广告机的需求,需要做一个广告轮播的效果,不需要什么特别的动画,正常的轮播就可以了。笔者看了网上很多文章,要么不好用,要么就是效果太多,太复杂,用不上...

1502
来自专栏林冠宏的技术文章

一行代码引入 ViewPager 无限循环 + 页码显示

(出处:https://cloud.tencent.com/developer/user/1148436/activities) 前序:   网上的这类 Vie...

5957
来自专栏蜉蝣禅修之道

android获取textview展开渲染后的高度

1784
来自专栏编程之路

羊皮书APP(Android版)开发系列(十)Android开发常用工具类

1161
来自专栏向治洪

RecyclerView 实现横向滚动效果

我相信很久以前,大家在谈横向图片轮播是时候,优先会选择具有HorizontalScrollView效果和ViewPager来做,不过自从Google大会之后,系...

4026
来自专栏Android知识点总结

O3-开源框架使用之Butterknife 8.8.1及源码浅析

cast()方法是Clazz的一个公共方法:由下可见它反会一个由传入值强转成的T类型对象

2014
来自专栏开发之途

Android 解析RecyclerView(2)——带顶部View和底部View的RecyclerView

3165
来自专栏向治洪

仿微信聊天表情发送

如题,这是公司项目的一个功能模块,先上个效果图: ? 其次大致说说原理: 1,首先判断输入的字符,是否包含表情的文字,比如   ?  这个表情对应的文件名为 e...

5537

扫码关注云+社区

领取腾讯云代金券