前往小程序,Get更优阅读体验!
立即前往
首页
学习
活动
专区
工具
TVP
发布
社区首页 >专栏 >Android九宫格控件-可在ListView和RecyclerView中使用

Android九宫格控件-可在ListView和RecyclerView中使用

作者头像
三好码农
发布2018-09-11 10:54:42
1.6K0
发布2018-09-11 10:54:42
举报
文章被收录于专栏:三好码农的三亩自留地

需求场景

熟悉Android App开发的同学,肯定都清楚,如果要显示多张图片,类似九宫格,可以用GridView或者GridLayout来做,但是如果需求要求在ListView或者recyclerView 的每个item中都显示这样一个九宫格,那么GridView就不适用了,GridLayout可以实现,但是不是那么优雅,我们需要在item每次重绘时,加入添加或者删除逻辑。既然框架没有提供满足需求的控件,我们只能自己实现。

思路

我们需要显示多张图片,那么肯定选择ViewGroup无疑,其实也就是一个简单的自定义ViewGroup——SquareGridView。

自定义属性

1.我们需要图片之间的水平间距horizontalSpacing和垂直间距verticalSpacing。 2.我们需要图片的长宽比ratio,默认我们1。 3.我们需要一行显示的列数numColumns。 4.我们需要图片显示的最大总数maxSize,默认为9。

SquareGridView实现

自定义属性初始化

比较简单,纯为了充字数!_

代码语言:javascript
复制
TypedArray typedArray = context.obtainStyledAttributes(attrs, R.styleable.SquareGridView);
numColumns = typedArray.getInteger(R.styleable.SquareGridView_numColumns, DEFAULT_COLUMN_NUM);
maxSize = typedArray.getInteger(R.styleable.SquareGridView_maxSize, DEFAULT_MAX_SIZE);
horizontalSpacing = typedArray.getDimensionPixelSize(R.styleable.SquareGridView_horizontalSpacing, DEFAULT_HORIZONTAL_SPACE);
verticalSpacing = typedArray.getDimensionPixelSize(R.styleable.SquareGridView_verticalSpacing, DEFAULT_VERTICAL_SPACE);
ratio = typedArray.getFloat(R.styleable.SquareGridView_ratio, DEFAULT_RATIO);
if (typedArray != null) {
  typedArray.recycle();
}
onMeasure实现

我们这里并不需要对SpeceMode进行特殊处理,只需要根据image数量计算宽度和高度。

代码语言:javascript
复制
int width, height;
int widthSpecMode = MeasureSpec.getMode(widthMeasureSpec);
int widthSpecSize = MeasureSpec.getSize(widthMeasureSpec);
int heightSpecMode = MeasureSpec.getMode(heightMeasureSpec);
int heightSpecSize = MeasureSpec.getSize(heightMeasureSpec);
width = widthSpecSize;
height = heightSpecSize;
//实际显示的image数量,不大于最大限制
int count = getRealCount();
//计算行数
float rowCount = (count + 0f) / numColumns;
int realRow = (int) Math.ceil(rowCount);
//计算每个image的宽度
childrenWidth = (width - getPaddingLeft() - getPaddingRight()
  - (numColumns - 1) * horizontalSpacing) / numColumns;
//计算每个image的高度
childrenHeight = (int) (childrenWidth * ratio);
height = getPaddingTop() + getPaddingBottom() + realRow *     childrenHeight
  + (realRow - 1) * verticalSpacing;
setMeasuredDimension(width, height);
onLayout实现

依次对image进行layout,也没什么好说的!

代码语言:javascript
复制
int count = getRealCount();
for (int i = 0; i < count; i ++) {
    int row = i / numColumns;
    int column = i % numColumns;
    int left = getPaddingLeft() + column * horizontalSpacing + column * childrenWidth;
    int top = getPaddingTop() + row * verticalSpacing + row * childrenHeight;
    View childView = getChildAt(i);
    childView.layout(left, top, left + childrenWidth, top + childrenHeight);
}
为SquareGridView定义数据源接口

我们可以定义一个接口,控件需要的数据,直接通过接口获取,接口定义如下!

代码语言:javascript
复制
public interface SquareViewAdapter<T> {

    int getCount();

    T getItem(int position);

    String getImageUrl(int position);

    void onItemClick(View view, int index, T t);

}

接口中定义的方法都很好理解,大家有疑问可以看源码,Github地址最后会给出。

设置数据源
代码语言:javascript
复制
public void setAdapter(final SquareViewAdapter adapter) {
this.squareViewAdapter = adapter;
int count = getRealCount();
int childCount = getChildCount();
int shortCount = count - childCount;
//判断现有的subviews,数量是否足够,不足的继续add,足够的话,多余的状态设为Gone即可。
if (shortCount > 0) {
    //we need add new subview.
    for (int i = 0;i < shortCount; i++) {
    SimpleDraweeView simpleDraweeView = new    SimpleDraweeView(getContext());
    GenericDraweeHierarchyBuilder builder =
    new GenericDraweeHierarchyBuilder(getResources());
    builder.setPlaceholderImage(ContextCompat.getDrawable(getContext(),
     R.drawable.default_load_failed_image),
    ScalingUtils.ScaleType.FIT_XY);
    simpleDraweeView.setHierarchy(builder.build());
    simpleDraweeView.setTag(i + childCount);
    ViewGroup.LayoutParams vlp = new ViewGroup.LayoutParams(
    childrenWidth, childrenHeight);
    this.addView(simpleDraweeView, vlp);
    }
}else if(shortCount < 0){
    for (int i = 0;i < Math.abs(shortCount); i ++) {
    SimpleDraweeView simpleDraweeView = (SimpleDraweeView)     getChildAt(i + count);
    simpleDraweeView.setVisibility(View.GONE);
    }
}
for (int i = 0;i < count; i++) {
    final int index = i;
    final SimpleDraweeView simpleDraweeView = (SimpleDraweeView) getChildAt(i);
simpleDraweeView.setVisibility(View.VISIBLE);
    simpleDraweeView.setImageURI(Uri.parse(squareViewAdapter.getImageUrl(i)));
    simpleDraweeView.setOnClickListener(new View.OnClickListener(){
      @Override
      public void onClick(View v) {
        if (adapter != null) {
          adapter.onItemClick(simpleDraweeView, index, adapter.getItem(index));
        }
      }
    });
  }
}

调用setAdapter即可刷新数据,更详细的用法参见我github项目里面的demo,_!最后实现的效果在listview 快速滚动时,非常流畅!!!

最后给出Github地址

https://github.com/aliouswang/SquareGridView

Gradle引用
代码语言:javascript
复制
compile 'com.aliouswang:library:1.0.0'
最后,“Please feel free to use!!!”, 欢迎各位同学Pull request. _!!!
本文参与 腾讯云自媒体同步曝光计划,分享自作者个人站点/博客。
原始发表:2016.01.10 ,如有侵权请联系 cloudcommunity@tencent.com 删除

本文分享自 作者个人站点/博客 前往查看

如有侵权,请联系 cloudcommunity@tencent.com 删除。

本文参与 腾讯云自媒体同步曝光计划  ,欢迎热爱写作的你一起参与!

评论
登录后参与评论
0 条评论
热度
最新
推荐阅读
目录
  • 需求场景
  • 思路
    • 自定义属性
    • SquareGridView实现
    • 最后给出Github地址
    领券
    问题归档专栏文章快讯文章归档关键词归档开发者手册归档开发者手册 Section 归档