ScrollView自动布局技巧

本文详细介绍了如何实现UIScrollView的自动布局,包括设置代理方法、ScrollView的属性、新特性视图规则等。讲解了如何处理滚动、缩放、拖拽相关的方法,以及隐藏状态栏、传递数据和设置页面控制器等技巧。

摘要生成于 C知道 ,由 DeepSeek-R1 满血版支持, 前往体验 >

scrollView自动布局技巧

  • 步骤:
1. sb中拖scrollView
2. 设置scrollView上下左右为0
4. 拖一个UIView"yellowView"到scrollView中(不是imageView)
5. 设置yellowView的自动布局上下左右为0(此时报错,实际缺少尺寸"无法算出contentSize")
6. 设置yellowView和scrollView等宽等高
7. 更新frame,并运行
  • 此时无法滚动,因为contentSize和scrollView的size一样大

8.设置yellowView宽约束的是scrollView宽的2倍,并运行
  • 此时 可以滚动了,因为yellowView的宽大于scrollView自身的宽

9. 设置yellowView顶部约束为64,并运行,会影响它的contentSize
10. 给yellowView上的添加按钮,并设置约束,演示分页属性,并运行
  • 实验小结:
1. 设置scrollView中内容的距离scrollView四边边距值,会影响contentSize即滚动范围,上下间距
   会影响contentSize的Hieght"垂直滚动范围",左右间距会影响水平滚动范围(不常用,了解装逼使用)
2. 如果用AutoLayout约束scrollView中的内容时只设置四边间距约束是不够的,还要设置view宽高
3. 除了UIImageView可以不用直接设置宽高,因为它里面如果设置了图片,imageView的size会根据图片               
   自适应,对应设置 scrollView的contentSize
4. 切记scrollView在实用自动布局时比较特殊
5. 建议:如果一个scrollView中有很多小控件可以把小控件添加一个容器视图 view,设置容器view的尺
   寸为contentSize

scrollView-代理方法

  • scrollViewDidScroll: 滚动视图滚动时使用
  • scrollViewDidEndDecelerating: 滚动视图停止滚动时使用
  • viewForZoomingInScrollView: 缩放视图时使用

  • 滚动相关方法
- (void)scrollViewDidScroll:(UIScrollView *)scrollView {
    NSLog(@"%@", @"scrollview视图开始滚动");
}

- (void)scrollViewWillBeginDecelerating:(UIScrollView *)scrollView {
    NSLog(@"%@", @"将要减速 - 在释放开手之后调用");
}

- (void)scrollViewDidEndDecelerating:(UIScrollView *)scrollView {
    NSLog(@"%@", @"完成减速 - 完全静止后调用");
}
  • 缩放相关方法

实现缩放的两个步骤

  1. 需要设置最小缩放比例(minimumZoomScale)和最大缩放比例(maximumZoomScale)都为1时无法缩放
  2. 需要实现 “viewForZoomingInScrollView” 方法 告诉 scrollView 缩放的视图

( 只要缩放就会调用 )

 // 告诉滚动视图缩放的视图
- (nullable UIView *)viewForZoomingInScrollView:(UIScrollView *)scrollView {
    return _imageView;
}


// @param scrollView 滚动视图
// @param view       缩放的视图
- (void)scrollViewWillBeginZooming:(UIScrollView *)scrollView withView:(nullable UIView *)view {

    NSLog(@"%@", @"缩放开始时调用");
}


/// @param scrollView 滚动视图
- (void)scrollViewDidZoom:(UIScrollView *)scrollView {
    NSLog(@"%@",@"正在缩放时调用");
}


/// @param scrollView 滚动视图
/// @param view       缩放的视图
/// @param scale      缩放的比例
- (void)scrollViewDidEndZooming:(UIScrollView *)scrollView withView:(nullable UIView *)view atScale:(CGFloat)scale {

    NSLog(@"%@",@" 缩放结束后调用");
}
  • 拖拽相关方法
/// @param scrollView 滚动视图
- (void)scrollViewWillBeginDragging:(UIScrollView *)scrollView {

    NSLog(@"%@", @"将要开始拖拽");
}


/// @param scrollView          滚动视图
/// @param velocity            速度
/// @param targetContentOffset 目标偏移位置
- (void)scrollViewWillEndDragging:(UIScrollView *)scrollView withVelocity:(CGPoint)velocity targetContentOffset:(inout CGPoint *)targetContentOffset {

    NSLog(@"%@", @"将要结束拖拽");
}


/// @param scrollView 滚动视图
/// @param decelerate 是否减速
- (void)scrollViewDidEndDragging:(UIScrollView *)scrollView willDecelerate:(BOOL)decelerate {

    NSLog(@"%@ %d", @"完成拖拽方法,手指放开后调用", decelerate);
    }
  • 状态栏相关方法
结合 self.scrollView.scrollsToTop = YES;使用要告诉它点了状态栏对那个scrollView进行滚动
- (BOOL)scrollViewShouldScrollToTop:(UIScrollView *)scrollView {

    NSLog(@"%@", @"将要滚动到顶部,点击状态栏时调用");
    return YES;
}

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

    NSLog(@"%@", @"已经滚动到状态栏");
}
  • 动画相关方法
/**
 The scroll view calls this method at the end of its implementations of the setContentOffset:animated: and scrollRectToVisible:animated: methods, but only if animations are requested.

 滚动视图会在实现了 setContentOffset:animated: & scrollRectToVisible:animated: 方法之后
 调用此方法

 同时必须在上述两个方法中允许动画
 */
- (void)scrollViewDidEndScrollingAnimation:(UIScrollView *)scrollView {

    NSLog(@"%@", @"调用动画结束");
}

关于代理设计模式

  • 自己想干一件事,但是自己不能主动完成/不能完成,要找一个对象帮自己完成
  • scrollView知道被滚动了,但是不知道被滚动以后将要做什么

  • 手写代理步骤

    • 找人做事情的人
      • 协议
      • 协议中的方法
      • 代理对象属性
      • 在需要做事情的’时候’,通过代理对象,执行协议中的方法
    • 做事情的人
      • 遵守协议
      • 设置代理对象
      • 实现代理方法,在代理方法中做事情

ScrollView-属性

  • contentSize: 内容大小,设置了才可以滚动
  • contentOffset: 内容偏移位置
  • contentInset: 内容间距
  • pagingEnabled: 是否允许分页
  • bounces: 是否允许弹簧效果
  • showsHorizontalScrollIndicator: 是否允许显示水平指示器(滚动条)
  • showsVerticalScrollIndicator: 是否允许显示垂直指示器(滚动条)

  • 滚动内容属性
// 内容偏移位置
@property(nonatomic)         CGPoint                      contentOffset;                  // default CGPointZero
// 内容大小,设置了才可以滚动
@property(nonatomic)         CGSize                       contentSize;                    // default CGSizeZero
// 内容间距
@property(nonatomic)         UIEdgeInsets                 contentInset;
  • 委托属性
@property(nullable,nonatomic,weak) id<UIScrollViewDelegate>   delegate;
要想监听滚动视图的滚动 / 拖拽 / 缩放 / 状态栏交互

需要设置 delegate
实现相关协议方法
  • 弹簧效果属性
// 允许弹簧效果
@property(nonatomic)   BOOL   bounces;                        // default YES. if YES, bounces past edge of content and back again
// 始终允许垂直弹
@property(nonatomic)   BOOL   alwaysBounceVertical;           // default NO. if YES and bounces is YES, even if content is smaller than bounds, allow drag vertically
// 始终允许水平弹
@property(nonatomic)   BOOL   alwaysBounceHorizontal;
  • 分页属性
// 允许分页
@property(nonatomic,getter=isPagingEnabled) BOOL pagingEnabled __TVOS_PROHIBITED;// default NO. if YES, stop on multiples of view bounds
  • 指示器属性
// 显示水平指示器
@property(nonatomic)         BOOL                         showsHorizontalScrollIndicator; // default YES. show indicator while we are tracking. fades out after tracking
// 显示垂直指示器
@property(nonatomic)         BOOL                         showsVerticalScrollIndicator;   // default YES. show indicator while we are tracking. fades out after tracking
// 指示器间距
@property(nonatomic)         UIEdgeInsets                 scrollIndicatorInsets;          // default is UIEdgeInsetsZero. adjust indicators inside of insets
// 指示器样式
@property(nonatomic)         UIScrollViewIndicatorStyle   indicatorStyle;                 // default is UIScrollViewIndicatorStyleDefault
在 scrollView 中指示器本质上就是 UIImageView

通过查看视图层次结构可以看到
  • 缩放属性
// 最小缩放比例
@property(nonatomic) CGFloat minimumZoomScale;     // default is 1.0
// 最大缩放比例
@property(nonatomic) CGFloat maximumZoomScale;     // default is 1.0. must be > minimum zoom scale to enable zooming
要允许缩放

必须设置以上两个属性
同时遵守协议
实现协议方法 -viewForZoomingInScrollView:
  • 状态栏属性
// 点击状态栏滚动到顶部
// default is YES. TVOS上此属性禁用,
@property(nonatomic) BOOL  scrollsToTop __TVOS_PROHIBITED;          
一个视图中,如果有多个 scrollView
只有唯一一个 scrollView 的 scrollsToTop 属性设置为 YES,才支持点击状态栏滚动到顶部
虽然此属性默认值即为YES不过还要要设置,不然不知道点了状态栏要对那个scrollView进行滚动
  • 键盘属性
// 键盘解除模式
@property(nonatomic) UIScrollViewKeyboardDismissMode keyboardDismissMode NS_AVAILABLE_IOS(7_0); // default is UIScrollViewKeyboardDismissModeNone
如果是 UITextView,通常需要将 alwaysBounceVertical 属性设置为 YES

typedef NS_ENUM(NSInteger, UIScrollViewKeyboardDismissMode) {
    // 无
    UIScrollViewKeyboardDismissModeNone,
    // 拖拽关闭键盘
    UIScrollViewKeyboardDismissModeOnDrag,      // dismisses the keyboard when a drag begins
    // 必须要拖拽到键盘才可以关闭键盘,很少使用
    UIScrollViewKeyboardDismissModeInteractive, // the keyboard follows the dragging touch off screen, and may be pulled upward again to cancel the dismiss
} NS_ENUM_AVAILABLE_IOS(7_0);
  • 常用方法
// 动画设置偏移位置
- (void)setContentOffset:(CGPoint)contentOffset animated:(BOOL)animated;  // animate at constant velocity to new offset

// 动画设置滚动区域
- (void)scrollRectToVisible:(CGRect)rect animated:(BOOL)animated;         // scroll so rect is just visible (nearest edges). nothing if rect completely visible
  • 三种图像填充模式
- scale的意思是:缩放,在contentMode中出现的话,就是要改变图形的大小了。
- aspect的意思是纵横的比例,在contentMode中的意思是保持图形的纵横比,保持图片不变形。

scale to fill:缩放图片,使图片充满容器。因为没有aspect,所以是不保持纵横比的。图片不是按比例缩放的。
scale aspect fit: 在保持纵横比(aspect)的前提下,缩放图片(scale),使图片在容器内都显示出来(fit)。
    保证图片完整显示,但不保证能充满容器。
scale aspect fill:在保持纵横比(aspect)的前提下,缩放图片(scale),使图片充满容器(fill)。保证图片能
    充满容器,不保证图片能完整显示。

新特性视图规则

新特性视图
  • 自动布局的选择?
    • 如果是全屏的直接bounds,如果不是考虑使用自动布局
  • 并不是每次都需要现实新特性界面,所以留个后路,以后再改
  • 创建控件时调用init或initWithFrame方法最后都会去调用对象父类的initWithFrame方法
隐藏状态栏
  • 隐藏状态来这些不属于显示也不属于数据,所以应该再C中找.
  • -(BOOL)prefersStatusBarHidden
传递数据思路对比
  • View直接写数据?(1)
  • 控制器传递给View?(2)
  • 可能面临到视图移植的问题,也就说,如果我另外一个项目也需要同样的需求,那么:
    • 如果使用第一种方式,需要做的工作.
      • 拷贝文件,更改view内部中的图片名称.
    • 如果使用第二种方式,需要做的工作.
      • 拷贝文件,在控制器重新写数据,传入view.
  • 视图只负责现实,控制器负责调度.
  • 两种方式,没有对不对,只有合不合适.

将新特性数组传递给新特性

  • 新建一个装满imageName的数组传递给视图

设置scrollView的frame

  • 创建scrollView并设置frame
ZFBGuideView *guideView = [[ZFBGuideView alloc] initWithFrame:self.view.bounds];
ZFBGuideView *guideView = [[ZFBGuideView alloc] init];
guideView.frame = self.view.bounds;
  • 两种写法都会调用initWithFrame
  • 重写了initWithFrame并且同时重写了init的方法,第一种形式的方法不会再调用init
  • 设置子控件的frame应该使用layoutSubviews
  • layoutSubviews一定要重写父方法
  • 约束的代码不能写在layoutSubviews方法中,此方法会多次调用

scrollView显示图片并设置属性

  • setImageNames方法中添加imageView到scrollView中
  • 并且设置图像和contentSize
  • 分页
  • 水平和垂直指示器(方便使用subviews)
  • 禁用弹性

设置更多按钮的自动布局

  • 添加到imageView上
  • 开启用户交互
  • userInteractionEnabled(bool)

添加按钮监听/新特性移除动画

  • 通过transform和透明度做动画
  • 移除整个新特性视图

使用代码创建pageControl

  • 应该添加到新特性视图上,如果添加到scrollView上会跟着滚动
  • 禁用分页的用户交互

pageControl位置/设置总页数

  • 自动布局设置pageControl位置
  • 总页数应该根据图片数量来,所以写在setImageNames方法中

设置pageControl当前页数

  • 结束滚动的代理方法中,根据offset和scrollView的宽度进行计算
  • 或者
  • 正在滚动的代理方法中,根据offset和scrollView的宽度进行计算(加0.4999再强转)

拖拽细节/隐藏pageControl

  • 需求的最右可以拖拽,思考怎么样增加?
  • 根据页数进行pageControl的隐藏和现实.
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包

打赏作者

Zok93

你的鼓励将是我创作的最大动力

¥1 ¥2 ¥4 ¥6 ¥10 ¥20
扫码支付:¥1
获取中
扫码支付

您的余额不足,请更换扫码支付或充值

打赏作者

实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值