资讯专栏INFORMATION COLUMN

Box(视图组件)如何在多个页面不同视觉规范下的复用

Invoker / 1859人阅读

摘要:问题描述中的页面元素,都是由一个个可以理解成一个个自定义组件和同级组成,这些可以在不同的页面不同的模块达到复用的效果。

本文来自 网易云社区 。

 

问题描述

Android App中的页面元素,都是由一个个Box(可以理解成一个个自定义View组件和Widget同级)组成,这些Box可以在不同的页面、不同的模块达到复用的效果。但是,现在遇到了一个对于开发复用棘手的问题,

  • A页面的组件间距和B页面的组件间距可能不同。

 

 

 

  • A页面的Box1与Box1间距,和Box1与Box2的间距不一样。

 

  • Box和Box之间的分割线,有粗有细,有的有左边距。

 

 

等等还有许多需要动态调整的地方。

然后做这些Box组件,就是为了复用它们,但现在又要对于每个Box的外边距,如Padding值,进行修改,以适应不同页面的要求。

方案 方案一

当然首先想到的是每个Box就和View一样,都有自己的属性,可以更改它的边距等属性,每个Box都有自己的视图模型ViewModel,可以在ViewModel中添加配置项,如:

public class ViewModel {
    int leftPadding;
    int topPadding;
    int rightPadding;
    int bottomPadding;

    public void setPadding(int left, int top, int right, int bottom
    {...}    
}

//在Box的update方法,根据配置的ViewModel,更新视图
public void update() {
    if(viewModel != null) {
        setPadding(viewModel.leftPadding, viewModel.topPadding,
        viewModel.rightPadding, viewModel.bottomPadding);
    }
}

这种办法,确实可行,但是会增加了开发的工作量,增加了代码的繁琐程度。毕竟Box的ViewModel应该尽量简单,ViewModel的存在应该只是让内部可以配置,而且主要配置的是Box要显示的数据。

如果每个要复用的Box都要增加这些属性,然后适配ViewModel的时候还要考虑每一个Box的四周边距,有时候还不能统一对待。比如一个List存放着同一种类型的Box,但是恰好最后一个Box它需要底边距不一样,那岂不还要适配ViewModel的时候还要做序数判断?

可想而知,开发代价是多高。

方案二

下面讲个实践中觉得最好的方案: 每个页面其实就是负责组装这些Box,因此负责组装的页面应该知道Box与Box之间的边距,分割线等外置属性。因此这些外置边距就交给RecyclerView.ItemDecoration类。

首先我们需要知道RecyclerView.ItemDecoration类能干什么?

 

假设绿色区域代表的是我们的内容,红色区域代表我们自己绘制的装饰,可以看到:

图1:代表了getItemOffsets(),可以实现类似padding的效果。

图2:代表了onDraw(),可以实现类似绘制背景的效果,内容在上面。

图3:代表了onDrawOver(),可以绘制在内容的上面,覆盖内容。

不过在交给它之前,还需要明确Box的边界。

  • 蓝色框内为可复用的Box
  • 红色外框是RecycleView中的一个ChildView大小

然后就有了如下方案:

约定:要复用的Box内部不应该有距离上下左右的边距,要保证最小边界。

Box与Box之间的边距交给RecyclerView.ItemDecorationgetItemOffset()方法处理。

@Override
public void getItemOffsets(Rect outRect, View view, RecyclerView parent, RecyclerView.State state) {
    DividerDesc dividerDesc = getDividerDesc(view, parent);
    outRect.set(dividerDesc.leftPadding, dividerDesc.topPadding, dividerDesc.rightPadding, dividerDesc.bottomPadding);
}

我们可以通过getDividerDesc()方法,通过当前View及RecycleView里的Adapter里的ItemType。得知当前View需要在四周有怎么样的属性及分割线。

DividerDesc类可以是这样:

private static class DividerDesc {

        final boolean needLeftMargin;    //水平分割线左边距
        final int leftPadding;            //左边距
        final int topPadding;            //上边距
        final int rightPadding;            //右边距
        final int bottomPadding;        //底边距
        final int dividerHeight;        //底部分割线高度

        DividerDesc(boolean needLeftMargin, int leftPadding, int topPadding, int rightPadding, int bottomPadding, int dividerHeight) {
            this.needLeftMargin = needLeftMargin;
            this.leftPadding = leftPadding;
            this.topPadding = topPadding;
            this.rightPadding = rightPadding;
            this.bottomPadding = bottomPadding;
            this.dividerHeight = dividerHeight;
        }

        DividerDesc() {
            this(false, 0, 0, 0, 0, 0);
        }
    }

RecyclerView.ItemDecorationdrawOver()方法中,画出需要分割线的地方。

@Override
    public void onDrawOver(Canvas c, RecyclerView parent, RecyclerView.State state) {
        int left,right,top,bottom;

        final int childCount = parent.getChildCount();
        for (int i = 0; i < childCount - 1; i++) {
            left = parent.getPaddingLeft();
            right = parent.getWidth() - parent.getPaddingRight();

            final View child = parent.getChildAt(i);
            final RecyclerView.LayoutParams params = (RecyclerView.LayoutParams) child.getLayoutParams();

            DividerDesc dividerDesc = getDividerDesc(child, parent);
            //带左边距
            if (dividerDesc.needLeftMargin) {
                left += sThinMarginHorizontal;
            }

            bottom = child.getBottom() + dividerDesc.bottomPadding;
            top = bottom - dividerDesc.dividerHeight;

            if (dividerDesc.dividerHeight == sThinHeight) {
                //画细线
                mDividerThin.setBounds(left, top, right, bottom);
                mDividerThin.draw(c);
            } else if (dividerDesc.dividerHeight == sThickHeight){
                //画粗线
                mDividerThick.setBounds(left, top, right, bottom);
                mDividerThick.draw(c);
            }

        }
Demo效果如下:

未加边距:

 

增加边距:

 

如果你也遇到了为Box复用而没法处理繁琐的视觉调整问题,或者有更好的方案,欢迎一块讨论 :)

参考文章
  • RecyclerView之ItemDecoration由浅入深

 

本文已由作者陈柏宁授权网易云社区发布,原文链接:Box(视图组件)如何在多个页面不同视觉规范下的复用

文章版权归作者所有,未经允许请勿转载,若此文章存在违规行为,您可以联系管理员删除。

转载请注明本文地址:https://www.ucloud.cn/yun/3043.html

相关文章

  • 基本功 | Litho的使用及原理剖析

    摘要:,解绑视图,主要用于重置视图的数据相关的属性,防止出现复用问题。的特性及原理剖析官网首页通过个段落重点介绍了的个特性。 1. 什么是Litho? Litho是Facebook推出的一套高效构建Android UI的声明式框架,主要目的是提升RecyclerView复杂列表的滑动性能和降低内存占用。下面是Litho官网的介绍: Litho is a declarative framewo...

    phpmatt 评论0 收藏0
  • 页面搭建工具总结及架构思考

    摘要:在初步完成了在线流程图编辑工具之后又接到了在线搭建页面工具的需求刚开始其实并不想接项目因为从历史以及现实原因来看个性化及动态渲染都是很难解决的痛点各种页面搭建工具的不温不火早已说明了这条路并没有这么好走但从另一个方面来说既然有了这样的需求那 在初步完成了在线流程图编辑工具之后,又接到了在线搭建页面工具的需求,刚开始其实并不想接项目,因为从历史以及现实原因来看,个性化及动态渲染都是很难解决的痛...

    William_Sang 评论0 收藏0
  • 创建可维护的设计规范(Living Style Guide)

    摘要:创建可维护的设计规范为什么需要相信团队工作中,不管是前端还是设计师都有被视觉统一问题折磨过的美好经历。所以在这,我先略过视觉稿,直接来说如何创建一分灵活可维护的设计规范。 创建可维护的设计规范(Living Style Guide) 为什么需要 Style Guide 相信团队工作中,不管是前端还是设计师都有被 视觉统一问题 折磨过的美 (dan) 好 (teng) 经历。特别是在中大...

    sutaking 评论0 收藏0
  • CSS规范 > 9 视觉格式化模型 Visual Formatting Model

    摘要:盒的类型会影响其在视觉格式化模型中的表现。浮动元素绝对定位元素根元素都被称为脱离文档流其他元素被称为文档流内。 视觉格式化模型 Visual Formatting Model URL:http://www.w3.org/TR/CSS2/visuren.html Translator: HaoyCn Date: 14th of Aug, 2015 本文并未全部翻译,译者在原文基础上...

    魏宪会 评论0 收藏0
  • CSS编码规范建议

    摘要:建议尽量不使用声明。示例建议颜色值中的英文字符采用小写。字体单位建议使用作为定义的度量单位。示例建议需要添加时应尽可能考虑是否可以采用其他方式解决。建议尽量使用选择器处理兼容性,而非属性。 CSS 作为网页样式的描述语言。本文档的目标是使 CSS 代码风格保持一致,容易被理解和被维护。 1. 代码风格 1.1 文件 [强制]CSS文件使用UTF-8编码 解释:UTF-8 编码具有更广泛...

    jindong 评论0 收藏0

发表评论

0条评论

最新活动
阅读需要支付1元查看
<