一. UIScrollView内容的自动偏移

当A控制器是UINavigationController的子控制器时,并且A控制器的view的第一个子控件是UIScrollView(包括继承自UIScrollView的子类,如:UITableView,UICollectionView,或者是自定义继承自UIScrollView的类),内容会有自动偏移的现象,有如下两种情况。

  1. 竖屏的情况下,ScrollView会偏移64个像素;横屏的情况下,ScrollView会偏移32个像素。
  2. 当隐藏导航控制器的导航栏时,竖屏的情况下,ScrollView会偏移20个像素;横屏的情况下,ScrollView不偏移。

二. 关闭系统的自动偏移

当控制器的view有多个ScrollView时,Apple建议关闭系统的自动调整功能。

  1. 方法一
    选中要关闭的控制器 —> 属性栏 —> View Controller —> Layout —> Adjust Scroll View Insets
  2. 方法二
    在要关闭的控制器中代码关闭:self.automaticallyAdjustsScrollViewInsets = NO;

三. 在storyboard或XIB中布局UIScrollView

  1. 当ScrollView没有子控件的情况下,和其他控件的布局一样,布局位置和宽高就完成约束,添加子控件可以在代码中进行,并且用代码设置contentSize就可以滚动。
  2. 当ScrollView有子控件的情况下,UIScrollView本身布局位置和宽高和其他控件的布局还是一样,但其子控件的布局和一般情况下的布局就不太一样了,因为UIScrollView不仅要布局位置和宽高,而且还要通过子控件的位置和尺寸来自动计算出contentSize,换句话说子控件的位置尺寸必须明确。

要点:
(1). 子控件的上下左右约束必须设置
注意:这里设置了上下约束,不等于高就确定了。例如:在只有一个子控件情况下,这个子控件的上下左右约束都为50,只表示这个子控件的上下左右边框距离ScrollView的边框都是50。

(2). 子控件的宽高约束也必须设置
注意: 子控件的宽高只能等于已经确定了宽高的控件的宽高的倍数,或者是用具体的数值设置宽高的约束。例如:
ScrollView有一个子控件,这个子控件的高约束为800,宽的约束等于父控件ScrollView的宽;也可以是高约束为控制器view的2倍,宽为父控件ScrollView宽的3倍等。

  1. 举一个完整约束的例子:控制器的view有一个填充的UIScrollView,UIScrollView有两个子控件UIView,两个子控件上下排列,这里把上面的比作A控件,下面的比作B控件,添加完整的约束使UIScrollView可以滚动。

(1). 设置UIScrollView的约束
设置UIScrollView的上下左右与控制器的view的上下左右距离约束都为0。这样UIScrollView的位置和宽高已经确定。

(2). 设置A控件的约束
A控件的顶部左边右边距离UIScrollView顶部左边右边为50,底部距离B控件为100,再设置宽的约束为400,高的约束为500。这里的A控件宽高已经确定。

(3). 设置B控件的约束
B控件的左边右边底部距离UIScrollView左边右边底部为50,宽等于A控件的宽,高等于控制器的view的高。这里就完成了所有的约束。

(4). UIScrollView的contentSize可以通过计算得知(设控制器的高为667)
横向:50 + 400 + 50 = 500
纵向:50 + 500 + 100 + 667 + 50 = 1367

三. 自动布局后的contentSize的获取和修改

在storyboard或XIB中布局UIScrollView,UIScrollView会在viewDidAppear之前根据其子控件的约束计算UIScrollView的contentSize。当在控制器的view的生命周期viewDidAppear之前获取contentSize时,获取的值是0;可以在viewDidAppear方法中获取contentSize的值,也可以在它的父控件的layoutSubviews方法中获取。同样的,可以在viewDidAppear方法或layoutSubviews方法中修改contentSize的值。

四. UIScrollView布局的使用

例子:UIScrollView的子控件悬浮于屏幕顶部

(一). 界面自动布局

  1. 添加一个UIScrollView,设置上下左右约束与控制器view的距离为0。
  2. 给UIScrollView添加第一个子控件UIView,这里称为控件A,设置顶部左边右边距离UIScrollView边框为0;宽等于UIScrollView的宽,高约束设置为150。
  3. 给UIScrollView添加第二个子控件UIView,这里称为控件B,设置底部左边右边距离边框为0;顶部距离控件A的底部为50,宽等于UIScrollView的宽,高约束设置为700。
  4. 给UIScrollView添加第三个子控件UIView,这里称为控件C,设置左边右边距离UIScrollView边框为0;宽等于UIScrollView的宽,高约束设置为50。
  5. 上面的布局已经完成,这里而外的添加控件,用于做参照物,往控件C里添加一个UILabel,设置上下左右约束距离边框为0,文字为“SSIrreplaceable”,文字居中,字体尺寸为36,颜色为黄色;再往控件B中加两个UISwitch控件,第一个UISwitch的左边和顶部距离父控件的左边和顶部都为0,宽高约束分别为49,31;第二个UISwitch的左边距离父控件的左边为0,顶部距离第一个UISwitch为50,宽高约束分别为49,31。

提示:谁悬浮谁最后添加,不然即使悬浮了,也会被最后的添加的控件覆盖。

效果图:

iOS uiscrollview 方向 uiscrollview自动布局_iOS uiscrollview 方向

(二). 拖线设置代理

iOS uiscrollview 方向 uiscrollview自动布局_内容偏移_02

(三). 拖线连接属性

控件A控件C的顶部等于控件A的底部的约束分别脱线到控制器的属性上。

下图为“控件C的顶部=控件A的底部“约束图

iOS uiscrollview 方向 uiscrollview自动布局_uiscrollview_03

(四). 代码实现悬浮

#import "ViewController.h"

@interface ViewController ()

/** 控件A */
@property (weak, nonatomic) IBOutlet UIView *viewA;

/** 控件C的顶部==控件A的底部的约束 */
@property (weak, nonatomic) IBOutlet NSLayoutConstraint *viewCTopConstraint;

@end

@implementation ViewController

#pragma mark - <UIScrollViewDelegate>

- (void)scrollViewDidScroll:(UIScrollView *)scrollView {

    // 获取纵向偏移量
    CGFloat offsetY = scrollView.contentOffset.y;
    // 获取控件A的高
    CGFloat viewAH = self.viewA.bounds.size.height;

    // 偏移量大于或等于控件A的高就悬浮
    if (offsetY >= viewAH) {

        self.viewCTopConstraint.constant = offsetY - viewAH;

    } else {

        self.viewCTopConstraint.constant = 0.0;
    }

}

@end

(五). 子控件悬浮效果图

iOS uiscrollview 方向 uiscrollview自动布局_uiscrollview_04


iOS uiscrollview 方向 uiscrollview自动布局_内容偏移_05


iOS uiscrollview 方向 uiscrollview自动布局_内容偏移_06