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