yarkey0 2014-10-22
Android开发中偶尔会遇到ScrollView嵌套GridView情景,但是谷歌官网是不推荐这种方式的,因为他们都有滚动条,嵌套使用会有冲突,无奈只能另谋他路,自定义个仿GridView的控件
1.定义attrs.xml文件
<declare-styleable name="GridLinearLayout"> <attr name="verticalSpace" format="dimension"/> <attr name="horizontalSpace" format="dimension"/> <attr name="rows" format="integer"/> <attr name="columns" format="integer"/> </declare-styleable>
2.定义GridLinearLayout文件
/** * 一个没有滚动条的LinearLayout,但是却很像GridView。 * 实际上,就是为了解决当GridView被包含在一个SrcollView中而却拥有两个滚动条相互排斥而做。 */ public class GridLinearLayout extends LinearLayout{ /**仿GridView单元格适配器*/ private BaseAdapter adapter; /**仿GridView列数*/ private int columns=1; /**仿GridView行数*/ private int rows=1; /**仿GridView填充的单元格总数*/ private int count; /**仿GridView单元格单击事件*/ private OnCellClickListener onCellClickListener; /**布局水平分割线宽度*/ private int horizontalSpace =1; /**布局垂直分割线宽度*/ private int verticalSpace =1; /** * 仿GridView构造方法 * @param context */ public GridLinearLayout(Context context) { super(context); } /** * 仿GridV构造方法 * @param context * @param attrs */ public GridLinearLayout(Context context, AttributeSet attrs) { super(context, attrs); initAttrs(context, attrs); } /*** * 加载xml文件设置的属性值 * @param context * @param attrs */ private void initAttrs(Context context ,AttributeSet attrs){ TypedArray typedArray = context.obtainStyledAttributes(attrs, R.styleable.GridLinearLayout); columns = typedArray.getInteger(R.styleable.GridLinearLayout_columns, 1); rows = typedArray.getInteger(R.styleable.GridLinearLayout_rows, 1); horizontalSpace = typedArray.getDimensionPixelSize(R.styleable.GridLinearLayout_horizontalSpace, 0); verticalSpace = typedArray.getDimensionPixelSize(R.styleable.GridLinearLayout_verticalSpace, 0); typedArray.recycle(); } /** * 构造水平显示LinearLayout用于填充cell * @return */ private LinearLayout rowLinearLayout(){ LinearLayout itemLinearLayout = new LinearLayout(getContext()); itemLinearLayout.setOrientation(LinearLayout.HORIZONTAL); itemLinearLayout.setLayoutParams(new LayoutParams(LayoutParams.MATCH_PARENT, LayoutParams.WRAP_CONTENT)); itemLinearLayout.setGravity(Gravity.LEFT); return itemLinearLayout; } /** * 仿GridView将适配器单元格绑定到当前LinearLayout中 * @return */ public void bindLinearLayout() { removeAllViews(); rows = getSpecialRows(true); if(rows==-1){ return; } for(int r=0;r<rows;r++){ LinearLayout itemRow = rowLinearLayout(); for(int c=0;c<columns;c++){ final int index = r*columns+c; View cellView = adapter.getView(index, null, null); cellView.setLayoutParams(cellLayoutParams(index)); if(index<count||index==(count-1)){ itemRow.addView(cellView,c); cellView.setOnClickListener(new OnClickListener() { @Override public void onClick(View v) { if(onCellClickListener!=null){ onCellClickListener.onCellClick(index); } } }); if(index==(count-1)){ addView(itemRow, r); return; } }else{ return; } } addView(itemRow, r); } } /** * 获取屏幕宽度用于均分一行LinearLayout各个Cell * @return */ @SuppressWarnings("deprecation") private int screenWidth(){ /*Point outSize = new Point(); WindowManager windowManager = (WindowManager) getContext().getSystemService(Service.WINDOW_SERVICE); Display display = windowManager.getDefaultDisplay(); display.getSize(outSize); return outSize.x;*/ int screenWidth; WindowManager windowManager = (WindowManager) getContext().getSystemService(Service.WINDOW_SERVICE); Display display = windowManager.getDefaultDisplay(); screenWidth = display.getWidth(); return screenWidth; } /** * 设置当前单元格边距, * 每一行第一个左边距为0底边距为horizontalSpace, * 其他单元格左边距为verticalSpace底边距为horizontalSpace * @param index 单元格序数 * @return */ private LayoutParams cellLayoutParams(int index){ LinearLayout.LayoutParams params = new LinearLayout.LayoutParams(cellWidth(),LayoutParams.WRAP_CONTENT); if(index%columns==0){ params.setMargins(0, 0, 0, horizontalSpace); return params; }else{ params.setMargins(verticalSpace, 0, 0, horizontalSpace); return params; } } /*** * 计算单元格宽度 * @return */ private int cellWidth(){ int cellScreenWidth = screenWidth()-(columns-1)*verticalSpace; return cellScreenWidth/columns; } /*** * 是否按列的倍数返回行数 * @param isSpecial TRUE:返回列的倍数行数,FALSE:有多少行显示多少行 * @return 返回-1时表示列数为0 */ private int getSpecialRows(boolean isSpecial){ try { if(isSpecial){ return count/columns; }else{ return (int) Math.ceil((double)count/columns); } } catch (Exception e) { e.printStackTrace(); return -1; } } /*** * 返回该控件的适配器 * @return */ public BaseAdapter getAdapter() { return adapter; } /** * 设置该控件的适配器 * @param adapter 自定义适配器 */ public void setAdapter(BaseAdapter adapter) { this.adapter = adapter; this.count = adapter.getCount(); } /** * 返回该控件的列数 * @return */ public int getColumns() { return columns; } /** * 设置该控件的列数 * @param columns 列数 */ public void setColumns(int columns) { this.columns = columns; } /** * 返回该控件的行数 * @return */ public int getRows() { return rows; } /** * 设置该控件的行数 * @param rows 行数 */ public void setRows(int rows) { this.rows = rows; } /** * 返回该控件各单元格水平间距 * @return */ public int getHorizontalSpace() { return horizontalSpace; } /** * 设置该控件各单元格水平间距 * @param horizontalSpace 间距 */ public void setHorizontalSpace(int horizontalSpace) { this.horizontalSpace = horizontalSpace; } /** * 返回该控件各单元格垂直间距 * @return */ public int getVerticalSpace() { return verticalSpace; } /** * 设置该控件各单元格垂直间距 * @param verticalSpace 间距 */ public void setVerticalSpace(int verticalSpace) { this.verticalSpace = verticalSpace; } public interface OnCellClickListener{ public void onCellClick(int index); } /** * 监听响应单元格单击事件 * @param onCellClickListener 单元格单击事件接口 */ public void setOnCellClickListener(OnCellClickListener onCellClickListener){ this.onCellClickListener = onCellClickListener; } }
3.可以将此控件嵌套在ScrollView中,然后调用方式如下
//获取控件 glFriendRecommendTask = (GridLinearLayout) view.findViewById(R.id.glFriendRecommendTask); //设置控件适配器,适配器按正常方式定义即可 glFriendRecommendTask.setAdapter(friendRecommendTaskAdapter); //如果需要监听适配器中的单击事件可在此处触发 glFriendRecommendTask.setOnCellClickListener(new OnCellClickListener() { @Override public void onCellClick(int index) { } }); //设置该控件显示的列数 glFriendRecommendTask.setColumns(3); //最后调用绑定方法即可 glFriendRecommendTask.bindLinearLayout();