UIScrollView详解

UIScrollView基本使用:

1.设置可以滚动的范围 contentSize 

self.scrollView.contentSize = XXX.size;

2.设置内容的偏移量 contentOffset

作用1:控制内容滚动的位置    
作用2:得知内容滚动的位置
self.scrollView.contentOffset = CGPointMake(0, -100);

3.设置滚动区域四周的滚动范围 contentInset

self.scrollView.contentInset = UIEdgeInsetsMake(10, 10, 10, 10);

4.指定控件是否只能在一个方向上滚动(默认NO)

self.scrollView.directionalLockEnabled = YES;

5.是否有弹簧效果

self.scrollView.bounces = NO;
不管有没有设置contentSize,总是有弹簧效果(下拉刷新)
self.scrollView.alwaysBounceHorizontal = YES;
self.scrollView.alwaysBounceVertical = YES;

6.当值是 YES 会自动滚动到 subview 的边界(默认NO

self.scrollView.pagingEnabled = YES;

7.控制控件是否能滚动(默认YES

self.scrollView.scrollEnabled = NO; 

8.点击状态栏回到顶部(默认YES

self.scrollView.scrollsToTop = YES;

9.是否显示滚动条

水平方向
self.scrollView.showsHorizontalScrollIndicator = NO;
垂直方向
self.scrollView.showsVerticalScrollIndicator = NO;

10.指定滚动条在scrollerView中的位置

self.scrollView.scrollIndicatorInsets=UIEdgeInsetsMake(64.0, 0.0, 44.0, 0.0);

11.设置滚动条样式

默认:灰色线包围黑色条
self.scrollView.indicatorStyle = UIScrollViewIndicatorStyleDefault; 

12.内边距

self.scrollView.contentInset = UIEdgeInsetsMake(100, 0, 50, 0);

13.自动调整宽高

self.scrollView.autoresizingMask = UIViewAutoresizingFlexibleHeight | UIViewAutoresizingFlexibleWidth;  

14.设置子控件不能滚动:

//UIScrollView设置子控件不跟随自己滚动
-(void)layoutSubviews {
    [super layoutSubviews];
    for (UIView*view in self.subviews) {
        if ([view isKindOfClass:[UIImageView class]]) {
            CGRect rect = view.frame;
            rect.origin.y = self.contentOffset.y;
            view.frame = rect;
        }
    }
}

15.手势冲突

//返回YES,则可以多个手势一起触发方法,返回NO则为互斥(比如外层UIScrollView名为mainScroll内嵌的UIScrollView名为subScroll,当我们拖动subScroll时,mainScroll是不会响应手势的(多个手势默认是互斥的),当下面这个代理返回YES时,subScroll和mainScroll就能同时响应手势,同时滚动,这符合我们这里的需求)
- (BOOL)gestureRecognizer:(UIGestureRecognizer *)gestureRecognizer shouldRecognizeSimultaneouslyWithGestureRecognizer:(UIGestureRecognizer *)otherGestureRecognizer {
    return YES;
}

16.UIScrollView点击状态栏返回顶部

在iOS开发中,UIScrollView自带点击状态栏自动返回顶部的效果: BOOL scrollsToTop.

这个手势只能作用在一个scrollView上,当发现多个时,手势将会失效

在实际应用中,我们可能会有多个scrollView,这时,系统默认的点击状态栏返回顶部效果就会失效,我们就得自己自定义控件来实现此功能了。

思路:①自定义一个Window②监听顶部窗口点击③找到参数View中所有的UIScrollView④让UIScrollView滚到最前面。

自定义一个Window

#import <UIKit/UIKit.h>

NS_ASSUME_NONNULL_BEGIN

@interface HKWindow : UIWindow
+ (void)show;
+ (void)hide;
@end

NS_ASSUME_NONNULL_END


#import "HKWindow.h"
#import "HKTopViewController.h"
@implementation HKWindow
// 全局对象
static UIWindow *topWindow_;
+ (void)initialize {
    
    topWindow_ = [[UIWindow alloc] init];
    topWindow_.frame = [UIApplication sharedApplication].statusBarFrame;
    topWindow_.windowLevel = UIWindowLevelAlert;
    topWindow_.backgroundColor = [UIColor clearColor];
    
    HKTopViewController *rootVc = [HKTopViewController sharedInstance];
    topWindow_.rootViewController = rootVc;
}
+ (void)show
{
    topWindow_.hidden = NO;
}

+ (void)hide
{
    topWindow_.hidden = YES;
}

@end

HKTopViewController

#import <UIKit/UIKit.h>

NS_ASSUME_NONNULL_BEGIN

@interface HKTopViewController : UIViewController
+ (HKTopViewController *)sharedInstance;
@end

NS_ASSUME_NONNULL_END

#import "HKTopViewController.h"

@interface HKTopViewController ()

@end

@implementation HKTopViewController
+ (HKTopViewController *)sharedInstance
{
    static dispatch_once_t  onceToken;
    static HKTopViewController * _sharedInstance;
    dispatch_once(&onceToken, ^{
        _sharedInstance = [[self alloc] init];
    });
    return _sharedInstance;
}
-(void)touchesBegan:(NSSet<UITouch *> *)touches withEvent:(UIEvent *)event {
    UIWindow *window = [UIApplication sharedApplication].keyWindow;
    [self searchScrollViewInView:window];
}

// 递归搜索所有view查找当前位置合适的scrollView
- (void)searchScrollViewInView:(UIView *)view
{
    for (UIScrollView *subView in view.subviews) {
        if ([subView isKindOfClass:[UIScrollView class]] && [self isShowingInKeyWindow:subView]) {
            //开始进行滚动
            CGPoint offset = subView.contentOffset;
            offset.y = -subView.contentInset.top;
            [subView setContentOffset:offset animated:YES];
        }
        //寻找子视图的子视图
        [self searchScrollViewInView:subView];
    }
}

// 根据位置判断是否合适
- (BOOL)isShowingInKeyWindow:(UIView *)view
{
    UIWindow *keyWindow = [UIApplication sharedApplication].keyWindow;
    CGRect currentFrame = [keyWindow convertRect:view.frame fromView:view.superview];
    CGRect winBounds = keyWindow.bounds;
    BOOL intersects = CGRectIntersectsRect(currentFrame, winBounds);
    return !view.isHidden && view.alpha > 0.01 && view.window == keyWindow && intersects;
}

- (void)viewDidLoad {
    [super viewDidLoad];
    // Do any additional setup after loading the view.
}

@end

17.ScrollView固定滚动方向

- (void)scrollViewDidScroll:(UIScrollView *)scrollView
{
    CGPoint point = scrollView.contentOffset;
    // 限制y轴不动
    point.y = 0.f;//Y轴不动(不能左右滑动)
    //point.x = 0.f;//X轴不动(不能上下滑动)
    scrollView.contentOffset = point;
}

 17.UIScrollView自动布局

//scrollView.autoresizingMask = UIViewAutoresizingFlexibleWidth | UIViewAutoresizingFlexibleHeight;
//UIScrollView做自动布局: 首先确定scrollView滚动范围 => 如何在stroboard对scrollView确定滚动范围 => 搞一个专门view去确定scrollView的滚动范围 => 如何确定:水平 和 垂直方向 => scrollView水平能否滚动: view的宽度 + 左右两边间距 才能确定scrollView水平滚动区域 => 垂直 = view的高度 + 上下两边间距
UIScrollView底层实现:
@interface ViewController ()<UIScrollViewDelegate>
@property (nonatomic, weak) UIView *scrollView;
@end
@implementation ViewController
- (void)viewDidLoad {
    [super viewDidLoad];
    // Do any additional setup after loading the view, typically from a nib.
    // 模仿系统控件 => 怎么去使用 => 滚动scrollView,其实本质滚动内容 => 改bounds => 验证
    // => 手指往上拖动,bounds y++ ,内容才会往上走
    UIView *scrollView = [[UIView alloc] initWithFrame:self.view.bounds];
    [self.view addSubview:scrollView];
    _scrollView = scrollView;
    // 添加Pan手势
    UIPanGestureRecognizer *pan = [[UIPanGestureRecognizer alloc] initWithTarget:self action:@selector(pan:)];
    [scrollView addGestureRecognizer:pan];
    UISwitch *switchView = [[UISwitch alloc] init];
    [scrollView addSubview:switchView];
}

- (void)pan:(UIPanGestureRecognizer *)pan
{
    // 获取手指的偏移量
    CGPoint transP = [pan translationInView:pan.view];
    // 修改bounds
    CGRect bounds = _scrollView.bounds;
    bounds.origin.y -= transP.y;
    _scrollView.bounds = bounds;
    // 复位
    [pan setTranslation:CGPointZero inView:pan.view];
}

#pragma mark - UIScrollViewDelegate
- (void)scrollViewDidScroll:(UIScrollView *)scrollView{
    NSLog(@"%@",NSStringFromCGRect(scrollView.bounds));
    NSLog(@"%@",NSStringFromCGPoint(scrollView.contentOffset));
} 

 18.UIScrollView当方向禁止向上或者向下滑动

//我们有时候可能会需要单方向的禁止滑动,但是官方直接提供的方法只能禁止滑动,在这里我们用UITableView 或者 UIScrollView 的代理方法
- (void)scrollViewDidScroll:(UIScrollView *)scrollView{

   //到顶部后不再向上滑动
   if (scrollView.contentOffset.y < 0) {
      [self.tableView setContentOffset:CGPointZero animated:NO];
   }

   //到底部后不再向下滑动
   if (scrollView.contentOffset.y + CGRectGetHeight(self.udView.tableView.frame) >scrollView.contentSize.height){
      [self.tableView setContentOffset:CGPointMake(selftableView.contentOffset.x,self.tableView.contentSize.height - CGRectGetHeight(self.tableView.frame)) animated:NO];
   }

}

Swift-版

func scrollViewDidScroll(scrollView: UIScrollView) {
    // 禁止下拉
    if scrollView.contentOffset.y <= 0 {
        scrollView.contentOffset.y = 0
    }
    // 禁止上拉
    if scrollView.contentOffset.y >= scrollView.contentSize.height - scrollView.bounds.size.height {
        scrollView.contentOffset.y = scrollView.contentSize.height - scrollView.bounds.size.height
    }
}

 

 

 

 

 

 

 

原文地址:https://www.cnblogs.com/StevenHuSir/p/10040194.html