自定义GridView以解决ScrollView嵌套Android自身GridView出现的疑难问题

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();

相关推荐