Box(视图组件)如何在多个页面不同视觉规范下的复用
本文来自 网易云社区 。
问题描述
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.ItemDecoration
的getItemOffset()
方法处理。
@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.ItemDecoration
的drawOver()
方法中,画出需要分割线的地方。
@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复用而没法处理繁琐的视觉调整问题,或者有更好的方案,欢迎一块讨论 :)
参考文章
本文已由作者陈柏宁授权网易云社区发布,原文链接:Box(视图组件)如何在多个页面不同视觉规范下的复用
Box(视图组件)如何在多个页面不同视觉规范下的复用的更多相关文章
- ASP.NET Core 中文文档 第四章 MVC(3.9)视图组件
作者: Rick Anderson 翻译: 娄宇(Lyrics) 校对: 高嵩 章节: 介绍视图组件 创建视图组件 调用视图组件 演练:创建一个简单的视图组件 附加的资源 查看或下载示例代码 介绍视图 ...
- asp.net core 视图组件(转)
介绍视图组件 视图组件是 ASP.NET Core MVC 中的新特性,与局部视图相似,但是它们更加的强大.视图组件不使用模型绑定,只取决于调用它时所提供的数据.视图组件有以下特点: 渲染一个块,而不 ...
- asp.net core视图组件(ViewComponent)简单使用
一.组成: 一个视图组件包括两个部分,派生自ViewComponent的类及其返回结果.类似控制器. 定义一个视图组件,如控制器一样,必须是公开,非嵌套,非抽象的类.一般,视图组件名称为类名去掉&qu ...
- ASP.NET Core Razor 视图组件
视图组件简介 在新的ASP.NET Core MVC中,视图组件类似于局部视图,但它们更强大.视图组件不使用模型绑定,仅依赖于您在调用时提供的数据. 视图组件特性: 呈现页面响应的某一部分而不是整个响 ...
- [译]ASP.NET Core 2.0 视图组件
问题 如何在ASP.NET Core 2.0中使用视图组件? 答案 新建一个空项目,修改Startup类并添加MVC服务和中间件: public void ConfigureServices(ISer ...
- ASP.NET CORE 自定义视图组件(ViewComponent)注意事项
*红色字体为固定命名,蓝色为一般命名规则,黄色为ASP.NET CORE 默认查找文件名 概要:1.简单ViewComponent的用法 2.ViewComponent控制器返回值 3.注意事项 1 ...
- Asp.Net core 视图组件ViewComponent
视图组件 ViewComponent 最近用了一下视图组件,还挺方便的,如果遇到公共的部分,可以抽出来,写成视图组件,方便调用 先上图看一下效果:比如首页的4个画红框的地方是4个模块,有些地方可能要重 ...
- DjangoRestFramework学习二之序列化组件、视图组件 serializer modelserializer
DjangoRestFramework学习二之序列化组件.视图组件 本节目录 一 序列化组件 二 视图组件 三 xxx 四 xxx 五 xxx 六 xxx 七 xxx 八 xxx 一 序列化组 ...
- .Net Core使用视图组件(ViewComponent)封装表单文本框控件
实例程序的界面效果如下图所示: 在表单中的搜索条件有姓名,学号,成绩.他们在一行中按照水平三等分排列. 在cshtml中用html实现上述表单效果的的代码如下: <form class=&quo ...
随机推荐
- php中各种http报错的状态码分析
HTTP会经常遇见错误,本文主要和大家分享php中各种http报错的状态码,希望能帮助到大家. HTTP 错误 400 400 请求出错 由于语法格式有误,服务器无法理解此请求.不作修改,客户程序就无 ...
- 【实战】JBOSS反序列化Getshell
一.JBOSS4.0.5_GA,5.x,6.x 需要JavaDeserH2HC(https://github.com/joaomatosf/JavaDeserH2HC) 操作起来 javac -cp ...
- winform FormBordStyle=none 及 wpf FormBordStyle=none 的鼠标点击移动问题
winform: //bool formMove = false;//窗体是否移动 //Point formPoint;//记录窗体的位置 private void Login_MouseDown(o ...
- JS框架设计之对象扩展一种子模块
对象扩展 说完了,对象的创建(框架的命名空间的创建)以及如何解决多库之间的命名空间冲突问题之后,接下来,就是要扩展我们的对象,来对框架进行扩展,我们需要一种新功能,将新添加的功能整合到我们定义的对象中 ...
- FX4300超频4.7GHz
先贴出本人计算机配置: (本人cpu为fx4300,默认频率为3.8GHz) 谨记:超频有风险,很可能烧坏主板.cpu.内存等硬件,特别是增加主板电压时一定一次增加0.025V,不要一次增加太多,并且 ...
- Mysql查询今天、昨天、7天、近30天、本月、上一月数据
今天 SELECT * FROM 表名 WHERE TO_DAYS(时间字段名) = TO_DAYS(now()); 昨天 SELECT * FROM 表名 WHERE TO_DAYS( NOW( ) ...
- [MVC]多文件、超大文件上传
话不多说,上代码. <script src="http://code.jquery.com/jquery-2.1.4.min.js"></script> & ...
- SQL SERVER学习1——数据库概念
<SQL Server实例教程>(科学出版社) 数据库的基本概念 数据是载荷信息的物理符号,是数据库中存储的基本对象. 信息可以通过手势,眼神表达,但是表达信息的最佳方式还是数据. 数据有 ...
- 在方法中new关键字的用处
如果在类A中有M1这个方法需方法 public virtual ovid m1() { console.writeline(“我的世界”); } 那么你在类B中继承的时候可以重写这个方法,也可以不重写 ...
- 使用WrapPanel和DockPanel
WrapPanel和DockPanel也是连个比较简单的布局容器,这两个空间将弥补StackPanel的某些不足,该开发人员更多可选择的布局方式,这两个作用如下: WrapPanel控件:该控件根据O ...