AASubviews - Automatic arrangement subviews

自动排列子视图

演示图

调用说明:

只需引入 AASubviews.h 后,调用下面的方法即可:

+ (void)superview:(UIView *)superview subviews:(NSArray *)subviews;

使用场景:

如果你使用 frame 来布局,这是一个很方便的工具。场景是这样的,一个页面由多个不同的展示元素组成,考虑到可维护性和扩展性,这些元素可以划分成从上至下排列的多个分组,一个分组就是一个自定义的 subview ,每个 subview 实现各自内部的展示逻辑,并且有以下特点:

  • subview 的高度可能变化;
  • subview 也可能突然隐藏或显示;
  • 由于以上两点,superview 的高度也会跟着变化;
  • subview 的排列顺序可能变化。

演示例子:

例如需求是展示某个商家的详情页,对于酒店(Hotel)类型商家是下面这样展示的,并且,为了方便管理,从上至下划分为以下几个部分:

例子

还有交互上是这样的:点击“关闭”按钮会隐藏 DemoAdView,点击“展开”会使 DemoDescView 变高,点击“重置”会使所有 view 重置一遍。并且对于商店(Shop)类型的商家是有不同的展示方式。

AASubViews 可以很方便的管理这种变化。

DemoHeaderView *headerView = [DemoHeaderView createViewFromXib];
DemoNameView *nameView = [DemoNameView createViewFromXib];
DemoAdView *adView = [DemoAdView createViewFromXib];
DemoDescView *descView = [DemoDescView createViewFromXib];
DemoCommentView *commentView = [DemoCommentView createViewFromXib];

NSArray *subviews = nil;
if (self.type == DemoTypeHotel) {
    subviews = @[headerView, nameView, adView, descView, commentView];
} else {
    subviews = @[adView, nameView, descView, commentView];
}

[AASubviews superview:self.scrollView subviews:subviews];

要查看更详细的代码请打开工程。

原理分析:

从上至下排列 subviews,使用 KVO 原理检测 subviewframehidden 变化,从而自动调整布局。

难点是,如果只是简单利用 KVOsuperview 来观察 subview 的变化,会有很多问题,例如:

  1. 如果重复 addObserver 会多次触发 observeValueForKeyPath:ofObject:change:context 方法;
  2. 如果重复 removeObserver 会导致闪退;
  3. 如果被观察者释放了而还没有 removeObserver 的话,也会导致闪退,模拟器不会发生,但是真机会发生;
  4. superview 观察 subview ,实现 observeValueForKeyPath:ofObject:change:context 方法,最初想到有两种方式,第一种是自定义一个 UIView 的子类,所有的 superview 继承于这个类,这种方式改动太大了,不可取;第二种是用 category 的方式实现这个方法,这种方式会影响到整个工程所有的 view ,这种方式也不太好。

为了解决问题 1 和 2,可以每个 subview 做一个标记是否被观察了。为了解决问题 3 和 4,可以引入一个专门观察 subview 的类 AAObserver,然后 superview 持有这个类的实例。

以下是对象的引用关系,实线代表强引用,虚线代表弱引用:

引用关系

addSubview 的时候 addObserver,当 removeFromSuperview 的时候 removeObserver。但是当 controller 退出时 superview 自动释放时,导致 subviews 也会自动 removeFromSuperview, 因为我们无法获取 removeFromSuperview 的回调,这时候我们怎么 removeObserver 呢?看上面的引用关系图,因为 observer 是对 subviews 强引用的,所以 observer 的释放肯定在 subviews 的释放之前, superview 释放会导致 observer 释放,我们可以在 observiewdealloc 方法里做 removeObserver。 这就巧妙地解决了没移除观察者的问题。

github地址:https://github.com/qhd/AASubviews

最后编辑于
©著作权归作者所有,转载或内容合作请联系作者
平台声明:文章内容(如有图片或视频亦包括在内)由作者上传并发布,文章内容仅代表作者本人观点,简书系信息发布平台,仅提供信息存储服务。

推荐阅读更多精彩内容

  • 概述 UIView或者它的子类知道怎样将自己绘制在一个矩形区域中。我们app所有可视的的界面来自于视图。创建和配置...
    smalldu阅读 887评论 0 6
  • iOS9 - UIView 子视图 & 父视图 今天主要研究了一下关于UIView章节的内容,发现以前对UIVie...
    Jeavil_Tang阅读 380评论 0 5
  • View简介 一个view可以从nib生成,也可以在代码中创建。View hierarchy 是主要的view组织...
    Felix_Smile阅读 603评论 0 0
  • 你可以下载the project source from the end of part 1与我们共同来探索 这是...
    木易林1阅读 438评论 0 0
  • 今天要分享的是我读NVC的一点点心得,从最初刚刚走出校园追张德芬每一本心灵成长的书,具体到一个个心理学分...
    静禾530阅读 375评论 0 2