博客
关于我
强烈建议你试试无所不能的chatGPT,快点击我
Android 自定义GridView网格布局
阅读量:6571 次
发布时间:2019-06-24

本文共 10531 字,大约阅读时间需要 35 分钟。

hot3.png

一、需求

Android提供了实现网格布局的GridView,还有RecyclerView等,但是在互相嵌套的问题上冲突很多,尤其是GridView焦点状态转移导致体验相当不好。为了能够在RecyclerView上自动实现网格排列,我们提供了如下方案。

 

​​​​​​​public class AutoFixedHeightGridView extends ViewGroup {    private BaseAdapter mAdapter;    private DataSetObserver mDataSetObserver;    private int columnNums;    private int columnPadding;    private int rowPadding;       Map
rowMaxHeight = new HashMap<>(); public AutoFixedHeightGridView(Context context) { this(context,null); } public AutoFixedHeightGridView(Context context, AttributeSet attrs) { this(context, attrs,0); } public AutoFixedHeightGridView(Context context, AttributeSet attrs, int defStyleAttr) { super(context, attrs, defStyleAttr); final TypedArray a = context.obtainStyledAttributes( attrs, R.styleable.AutoFixedHeightGridView, defStyleAttr, 0); columnNums = a.getInt(R.styleable.AutoFixedHeightGridView_numColumns, 1); int hSpacing = a.getDimensionPixelOffset( R.styleable.AutoFixedHeightGridView_horizontalSpacing, 0); columnPadding = hSpacing; int vSpacing = a.getDimensionPixelOffset( R.styleable.AutoFixedHeightGridView_verticalSpacing, 0); rowPadding = vSpacing; a.recycle(); } public void setAdapter(BaseAdapter mAdapter) { if(this.mAdapter!=null && mDataSetObserver != null){ this.mAdapter.unregisterDataSetObserver(mDataSetObserver); } if(mDataSetObserver==null){ mDataSetObserver = new GridDataSetObserver(this); } this.mAdapter = mAdapter; if(this.mAdapter!=null) { this.mAdapter.registerDataSetObserver(mDataSetObserver); this.mAdapter.notifyDataSetChanged(); }else{ datasetChanged(); } } public BaseAdapter getAdapter() { return mAdapter; } @Override protected void onMeasure(int widthMeasureSpec, int heightMeasureSpec) { super.onMeasure(widthMeasureSpec, heightMeasureSpec); int widthMode = MeasureSpec.getMode(widthMeasureSpec); int heightMode = MeasureSpec.getMode(heightMeasureSpec); int widthSize = MeasureSpec.getSize(widthMeasureSpec); int heightSize = MeasureSpec.getSize(heightMeasureSpec); int rowNums = 0; if (widthMode == MeasureSpec.UNSPECIFIED) { widthSize = getPaddingLeft() + getPaddingRight(); if(columnNums>1){ widthSize += (columnNums-1) * columnPadding; } } if (heightMode == MeasureSpec.UNSPECIFIED) { heightSize = getPaddingBottom() + getPaddingTop(); int contentWidth = widthSize - (getPaddingLeft() + getPaddingRight()); if (columnNums > 1) { contentWidth = contentWidth - (columnNums - 1) * columnPadding; } int columnWidth = contentWidth / columnNums; int count = this.getAdapter() != null ? this.getAdapter().getCount() : 0; if (count != getChildCount()) return; for (int i = 0; i < getChildCount(); i++) { final View child = getChildAt(i); LayoutParams params = (LayoutParams) child.getLayoutParams(); params.rightMargin = 0; params.leftMargin = 0; int childHeightSpec = getChildMeasureSpec( MeasureSpec.makeMeasureSpec(MeasureSpec.getSize(heightMeasureSpec), MeasureSpec.UNSPECIFIED), 0, params.height); int childWidthSpec = getChildMeasureSpec( MeasureSpec.makeMeasureSpec(columnWidth, MeasureSpec.EXACTLY), 0, columnWidth); child.measure(childWidthSpec, childHeightSpec); int childHeight = child.getMeasuredHeight(); if (i % columnNums == 0 && i > 1) { rowNums++; } Integer lastMaxHeight = rowMaxHeight.get(rowNums); if (lastMaxHeight == null) { lastMaxHeight = 0; } rowMaxHeight.put(rowNums, Math.max(lastMaxHeight, childHeight)); } int rowCount = (int) Math.ceil(count * 1.0f / columnNums); for (int i = 0; i < rowCount; i++) { heightSize += rowMaxHeight.get(i); } if (rowCount > 1) { heightSize += (rowCount - 1) * rowPadding; } }else{ int contentWidth = widthSize - (getPaddingLeft() + getPaddingRight()); if (columnNums > 1) { contentWidth = contentWidth - (columnNums - 1) * columnPadding; } int columnWidth = contentWidth / columnNums; int count = this.getAdapter() != null ? this.getAdapter().getCount() : 0; if (count != getChildCount()) return; for (int i = 0; i < getChildCount(); i++) { final View child = getChildAt(i); LayoutParams params = (LayoutParams) child.getLayoutParams(); params.rightMargin = 0; params.leftMargin = 0; int childHeightSpec = getChildMeasureSpec( MeasureSpec.makeMeasureSpec(MeasureSpec.getSize(heightMeasureSpec), MeasureSpec.UNSPECIFIED), 0, heightSize); int childWidthSpec = getChildMeasureSpec( MeasureSpec.makeMeasureSpec(columnWidth, MeasureSpec.EXACTLY), 0, columnWidth); child.measure(childWidthSpec, childHeightSpec); } } setMeasuredDimension(widthSize, heightSize); } @Override protected void onLayout(boolean changed, int l, int t, int r, int b) { int count = this.getAdapter()!=null?this.getAdapter().getCount():0; int rowCount = 0; int nextChildLeft = getPaddingLeft(); int nextChildTop = getPaddingTop(); int contentWidth = getMeasuredWidth() - (getPaddingLeft() + getPaddingRight()); if(columnNums>1){ contentWidth = contentWidth - (columnNums-1) * columnPadding; } int columnWidth = contentWidth /columnNums; if(count!=getChildCount()) return; for (int i=0;i
0 && i%columnNums==0){ Integer H = rowMaxHeight.get(rowCount); rowCount++; nextChildLeft = getPaddingLeft(); if(H==null){ H = 0; } nextChildTop = nextChildTop +H + rowPadding; } child.layout(nextChildLeft,nextChildTop,nextChildLeft+columnWidth,nextChildTop+child.getMeasuredHeight()); nextChildLeft = nextChildLeft+child.getMeasuredWidth() + columnPadding ; } } protected void datasetChanged() { if(this.mAdapter==null){ removeAllViews(); return; } final int count = this.mAdapter.getCount(); for (int i=0;i
viewTypeCount) { throw new IllegalArgumentException("viewType is correct"); }  View view = null; if(i
0){ removeViewsInLayout(getChildCount()-delta,delta); }  rquestLayout(); invalidate(); } protected void addViewInLayout(View child){ this.addViewInLayout(child,-1); } /** * * @param child * @param index 位置,如果是-1,则自动添加到末尾 */ protected void addViewInLayout(View child,int index){ if (child == null) { throw new IllegalArgumentException("Cannot add a null child view to a ViewGroup"); } ViewGroup.LayoutParams params = child.getLayoutParams(); if (params == null) { params = generateDefaultLayoutParams(); if (params == null) { throw new IllegalArgumentException("generateDefaultLayoutParams() cannot return null"); } } super.addViewInLayout(child,index,params); } public static class GridDataSetObserver extends DataSetObserver{ private AutoFixedHeightGridView fixedHeightGridView; public GridDataSetObserver(FixedHeightGridView fixedHeightGridView) { this.fixedHeightGridView = fixedHeightGridView; } @Override public void onChanged() { super.onChanged(); fixedHeightGridView.datasetChanged(); } @Override public void onInvalidated() { super.onInvalidated(); fixedHeightGridView.datasetChanged(); } } @Override protected ViewGroup.LayoutParams generateDefaultLayoutParams() { //child默认布局参数 return new LayoutParams(LayoutParams.MATCH_PARENT,LayoutParams.MATCH_PARENT); } @Override protected ViewGroup.LayoutParams generateLayoutParams(ViewGroup.LayoutParams p) { return new LayoutParams(p); } @Override protected boolean checkLayoutParams(ViewGroup.LayoutParams p) { //重写该方法,否则 return (p instanceof LayoutParams) ; } @Override public ViewGroup.LayoutParams generateLayoutParams(AttributeSet attrs) { return new LayoutParams(getContext(), attrs); } public static class LayoutParams extends ViewGroup.MarginLayoutParams{  private int viewType;  private static final int TYPE_UNDEFINED = 0; public LayoutParams(Context c, AttributeSet attrs) { super(c, attrs);  TypedArray a=c.obtainStyledAttributes(attrs, R.styleable.AutoFixedHeightGridView);          this.viewType = a.getInt(R.styleable.AutoFixedHeightGridView_viewType, TYPE_UNDEFINED); //该属性定义给child的  a.recycle(); } public LayoutParams(int width, int height) { super(width, height); this.viewType = TYPE_UNDEFINED; } public LayoutParams(MarginLayoutParams source) { super(source); if(source instanceOf LayoutParams){               this.viewType = ((LayoutParams)source).viewType;  }else{  this.viewType = TYPE_UNDEFINED;  } } public LayoutParams(ViewGroup.LayoutParams source) { super(source);  if(source instanceOf LayoutParams){               this.viewType = ((LayoutParams)source).viewType;  } else{  this.viewType = TYPE_UNDEFINED;  } }  public int getViewType(){  return viewType;  } }}

 

自定义属性部分

 

转载于:https://my.oschina.net/ososchina/blog/3018471

你可能感兴趣的文章
如何在Ubuntu 13.04, 13.10上安装Sublime Text 3
查看>>
C++语言基础 例程 派生类的声明与构成
查看>>
时间都去哪了?BPC电波授时信号的“零成本”伪造
查看>>
大数据workshop:《云数据·大计算:海量日志数据分析与应用》之《社交数据分析:好友推荐》篇...
查看>>
Python的类方法
查看>>
吐槽一下J2Cache
查看>>
PHP的语言构造器
查看>>
mysql5.6.25及以上下载衔接
查看>>
Node+fs+定时器(node-schedule)+MySql
查看>>
Eclipse环境安装Python插件PyDev
查看>>
【IOS-COCOS2D游戏开发之十九】游戏数据存储的四种常用方式NSKEYEDARCHIVER/NSUSERDEFAULTS/WRITE写入/SQLITE3...
查看>>
git 常用命令
查看>>
logging 日志表的设计
查看>>
sed 常见用法
查看>>
很多人很想知道怎么扫一扫二维码就能打开网站,就能添加联系人,就能链接wifi,今天做个demo(续集)...
查看>>
mysql 常用操作(整理)
查看>>
Java 网络教程: ServerSocket
查看>>
解决NSTextContainer分页时文本截断问题
查看>>
Android被逼学习小例子1
查看>>
x265探索与研究(一):x265下载安装与配置
查看>>