Android 11 (Image credit: Shutterstock / TechRadar)
在安卓小列表展示的情况下,我们应该使用什么样的UI结构?使用写死的xml?很容易缺乏灵活性,如果列表变动就会需要更改多个模块。使用recycleview?虽然拥有灵活性但是太重,有杀鸡用牛刀之感。在实习的过程中我就碰到了这样的问题,通过同事的指点学习了为视图动态添加view的方式。在学习的过程中,我发现相关的文章相对较少,而且很多文章是在kotlin/java文件中添加布局,而不是xml文件,灵活性相对较差。所以在此与大家分享这个问题上我的实践方式。
布局文件
在动态生成布局的时候,我们应当使用一个诸如LinearLayout或是ConstraintLayout作为我们动态视图的容器。这样能够很方便定位动态view的位置。同时,这给我们kotlin代码中确定父视图提供了方便。注意不要使用EditText或是TextView,当然我觉得大部分人不会无聊到想测试安卓代码的鲁棒性。
1 | <!--activity_main.xml--> |
在上述的布局文件中,test_container就是我们的父容器。接下来就是动态view的布局。
1 | <!--view_item.xml--> |
上述的很多地方都可以根据需求灵活地改变,但是有两点是确定的:我们需要有一个父容器,以及一个子容器的xml布局。
在Kotlin文件中结合父子布局
既然布局文件很简单,那么很多的工作就是在Kotlin中完成了。下面首先是完整代码:
1 | class MainActivity : AppCompatActivity() { |
这里的核心部分就是两句话:inflate和addview。获取父容器非常简单我们就不再赘述了。在获取到父容器后,我们使用inflater动态加载子项布局。inflate的三个参数分配代表子项布局id,要挂载的父布局,是否立刻挂载。如果第三个参数我们选择false,我们就需要使用container.addview手动添加子项的view。这里有一个小坑,细心的同学可能发现,这个addview,似乎就能确定父子容器的关系啊?那inflate的第二个参数我们可以传null吗?这是可以的,但是这样会导致子项根节点(这里是view_item.xml中的LinearLayout)属性失效。通过下图我们能够发现,如果设定为null则view_item的宽高margin全部失效了,这是非常不符合预期的。
另外一个值得一提的点是如果你需要绑定点击事件,那么最好在添加子视图的时候直接添加。实际上我们在父容器中添加了很多个带有相同id的view,如果添加完动态view后再修改我们就不能使用id获取到控件了,处理起来会比较麻烦。
感受
在感受了Vue的美好之后,安卓麻烦的布局文件确实震惊到我。为什么不能够像vue的v-for一样动态添加节点,动态设定id?查阅了资料后我发现这个问题在安卓最大的阻碍是xml文件的编译。因为xml的编译占了大量的CPU处理时间,我们不能够在运行时动态修改xml。导致动态布局的实现及其麻烦。能否开发一种新的布局方式优化布局的问题?我认为这或许会是一个非常有趣的研究方向。
参考资料
Android两种方式实现动态添加View 因为他将root设定为null了,导致我第一次调试样式一直不对