前言
NS_CLASS_AVAILABLE_IOS(2_0) @interface UIScrollView : UIView <NSCoding>@available(iOS 2.0, *) public class UIScrollView : UIView, NSCoding
移動設備的屏幕大小是極其有限的,因此直接展示在用戶眼前的內容也相當有限。當展示的內容較多,超出一個屏幕時,用戶可通過滾動手勢來查看屏幕以外的內容。普通的 UIView 不具備滾動功能,不適合顯示過多的內容,UIScrollView 是一個能夠滾動的視圖控件,可以用來展示大量的內容,并且可以通過滾動查看所有的內容。
UIScrollView 的用法很簡單,將需要展示的內容添加到 UIScrollView 中,設置 UIScrollView 的 contentSize 屬性,告訴 UIScrollView 所有內容的尺寸,也就是告訴它滾動的范圍。超出 UIScrollView 邊框的內容會被自動隱藏,用戶可以用過手勢拖動來查看超出邊框并被隱藏的內容。
UIScrollView 不僅能滾動顯示大量內容,還能對其內容進行縮放處理,也就是說,要完成縮放功能的話,只需要將需要縮放的內容添加到 UIScrollView 中。
- 如果 UIScrollView 無法滾動,可能是以下原因:
- 沒有設置 contentSize
- scrollEnabled = NO
- 沒有接收到觸摸事件 userInteractionEnabled = NO
UIScrollView 的各種尺寸
1、UIScrollView 的創建
Objective-C
UIScrollView *scrollView = [[UIScrollView alloc] initWithFrame:CGRectMake(30, 60, [[UIScreen mainScreen] bounds].size.width - 60, 490)];// 將 scrollView 添加到屏幕[self.view addSubview:scrollView];// 向滾動視圖中添加顯示內容,將 imageView 添加到 scrollView,所有 UIView 子類都可以添加UIImageView *imageView = [[UIImageView alloc] initWithImage:[UIImage imageNamed:@"13"]];[scrollView addSubview:imageView];// 設置滾動的范圍大小,包含隱藏的部分,contentSize 的大小一般大于 frame 屬性設置的可視區的大小scrollView.contentSize = imageView.bounds.size;
Swift
let scrollView:UIScrollView = UIScrollView(frame: CGRectMake(30, 60, UIScreen.mainScreen().bounds.size.width - 60, 490))// 將 scrollView 添加到屏幕self.view.addSubview(scrollView)// 向滾動視圖中添加顯示內容,將 imageView 添加到 scrollView,所有 UIView 子類都可以添加let imageView:UIImageView = UIImageView(image: UIImage(named: "13"))scrollView.addSubview(imageView)// 設置滾動的范圍大小,包含了隱藏的部分,contentSize 的大小一般大于 frame 屬性設置的可視區的大小scrollView.contentSize = imageView.bounds.size
Storyboard
- 在 Storyboard 上添加 Scroll View 控件,在 Scroll View 控件上添加其它控件,如 ImageView 控件。
- 在 Storyboard 中設置的 Scroll View 控件背景在程序運行時才能顯示出來。
將 Scroll View 控件拖線到 View Controller 代碼中,設置 contentSize 的大小。
@interface ViewController ()@property (nonatomic, weak) IBOutlet UIScrollView *scrollView;@end@implementation ViewController- (void)viewDidLoad {[super viewDidLoad];// 設置滾動的范圍大小self.scrollView.contentSize = CGSizeMake(364, 364);}@end
運行顯示效果
- 在 Storyboard 上添加 Scroll View 控件,在 Scroll View 控件上添加其它控件,如 ImageView 控件。
2、UIScrollView 的設置
Objective-C
// 設置滾動條的風格/*UIScrollViewIndicatorStyleDefault, // 灰色樣式,默認UIScrollViewIndicatorStyleBlack, // 黑色樣式UIScrollViewIndicatorStyleWhite // 白色樣式*/scrollView.indicatorStyle = UIScrollViewIndicatorStyleDefault;// 設置是否顯示滾動條scrollView.showsHorizontalScrollIndicator = YES; // 水平方向scrollView.showsVerticalScrollIndicator = YES; // 垂直方向// 設置滾動的范圍大小/*告訴 UIScrollView 所有內容的尺寸,也就是告訴它滾動的范圍內容的大小包含了隱藏的部分,contentSize 的大小一般大于 frame 屬性設置的可視區的大小某個值等于 0 時,則 UIScrollView 在此方向上不能滾動,如 CGSizeMake(0, 364),在 x 方向上不能滾動*/scrollView.contentSize = CGSizeMake(364, 364);// 設置四周額外的滾動區域/*在 UIScrollView 的 4 周增加額外的滾動區域一般用來避免 scrollView 的內容被其他控件擋住UIEdgeInsets UIEdgeInsetsMake(CGFloat top, CGFloat left, CGFloat bottom, CGFloat right)*/scrollView.contentInset = UIEdgeInsetsMake(64, 20, 30, 10);// 設置偏移量/*用來表示 UIScrollView 滾動的位置其實就是內容左上角與 scrollView 左上角的間距值CGPointZero 相當于 CGPointMake(0, 0)*/scrollView.contentOffset = CGPointMake(100, 200);[scrollView setContentOffset:CGPointZero animated:YES];// 獲取偏移量CGPoint contentOffset = scrollView.contentOffset;// 獲取子視圖/*水平和垂直滾動條也是 scrollView 的子視圖*/NSArray *subviews = scrollView.subviews;// 獲取顯示內容的高度/*CGRectGetMaxY(CGRect rect) 自動計算最大 Y 坐標值注意 水平和垂直滾動條也是 scrollView 的子視圖,會產生計算錯誤*/// 由最后一個控件計算CGFloat contentH = lastView.frame.origin.y + lastView.frame.size.height;// 使用系統方法計算CGFloat contentH = CGRectGetMaxY(lastView.frame);// 設置點擊狀態欄能否滾動到畫面最頂端/*也可以在協議方法中設置*/scrollView.scrollsToTop = YES;// 設置是否允許手動滾動scrollView.scrollEnabled = YES;// 設置是否整頁移動scrollView.pagingEnabled = NO;// 設置是否開啟彈簧效果scrollView.bounces = YES;// 關閉下沉效果/* 如果 viewController 在導航里,這個 viewController 的第一個子視圖是 ScrollView 或其子類,系統會讓 ScrollView 有個下沉的效果,有時這個效果會跟自己的代碼沖突,通常會把它關掉*/// 判斷是否實現了下沉效果if ([self respondsToSelector:@selector(setAutomaticallyAdjustsScrollViewInsets:)]) {// 關閉下沉效果self.automaticallyAdjustsScrollViewInsets = NO;}// 設置縮放倍數/*需要遵守 <UIScrollViewDelegate> 協議,并實現 viewForZoomingInScrollView 協議方法如果是在模擬器中測試,需要按住 option 鍵再拖動內容*/scrollView.maximumZoomScale = 3; // 放大倍數, scrollView.minimumZoomScale = 0.1; // 縮小倍數// 獲取當前縮放倍數CGFloat zoomScale = scrollView.zoomScale;// 設置代理,需要遵守協議 <UIScrollViewDelegate>scrollView.delegate = self;
Swift
// 設置滾動條的風格/*case Default // 灰色樣式,默認case Black // 黑色樣式case White // 白色樣式*/scrollView.indicatorStyle = .Default// 設置是否顯示滾動條scrollView.showsHorizontalScrollIndicator = true // 水平方向scrollView.showsVerticalScrollIndicator = true // 垂直方向// 設置滾動的范圍大小/*告訴 UIScrollView 所有內容的尺寸,也就是告訴它滾動的范圍內容的大小包含了隱藏的部分,contentSize 的大小一般大于 frame 屬性設置的可視區的大小某個值等于 0 時,則 UIScrollView 在此方向上不能滾動,如 CGSizeMake(0, 364),在 x 方向上不能滾動*/scrollView.contentSize = CGSizeMake(364, 364)// 設置四周額外的滾動區域/*在 UIScrollView 的 4 周增加額外的滾動區域一般用來避免 scrollView 的內容被其他控件擋住UIEdgeInsets UIEdgeInsetsMake(CGFloat top, CGFloat left, CGFloat bottom, CGFloat right)*/scrollView.contentInset = UIEdgeInsetsMake(64, 20, 30, 10)// 設置偏移量/*用來表示 UIScrollView 滾動的位置其實就是內容左上角與 scrollView 左上角的間距值CGPointZero 相當于 CGPointMake(0, 0)*/scrollView.contentOffset = CGPointMake(100, 200)scrollView.setContentOffset(CGPointZero, animated: true)// 獲取偏移量let contentOffset:CGPoint = scrollView.contentOffset// 獲取子視圖/*水平和垂直滾動條也是 scrollView 的子視圖*/let subviews:Array = scrollView.subviews// 獲取顯示內容的高度/*CGRectGetMaxY(CGRect rect) 自動計算最大 Y 坐標值注意 水平和垂直滾動條也是 scrollView 的子視圖,會產生計算錯誤*/// 由最后一個控件計算let contentH = lastView.frame.origin.y + lastView.frame.size.height// 使用系統方法計算let contentH = CGRectGetMaxY(lastView.frame)// 設置點擊狀態欄能否滾動到畫面最頂端/*也可以在協議方法中設置*/scrollView.scrollsToTop = true// 設置是否允許手動滾動scrollView.scrollEnabled = true// 設置是否整頁移動scrollView.pagingEnabled = false// 設置是否開啟彈簧效果scrollView.bounces = true// 關閉下沉效果/* 如果 viewController 在導航里,這個 viewController 的第一個子視圖是 ScrollView 或其子類,系統會讓 ScrollView 有個下沉的效果,有時這個效果會跟自己的代碼沖突,通常會把它關掉*/// 判斷是否實現了下沉效果if self.respondsToSelector(Selector("setAutomaticallyAdjustsScrollViewInsets:")) {// 關閉下沉效果self.automaticallyAdjustsScrollViewInsets = true}// 設置縮放倍數/*需要遵守 UIScrollViewDelegate 協議,并實現 viewForZoomingInScrollView 協議方法如果是在模擬器中測試,需要按住 option 鍵再拖動內容*/scrollView.maximumZoomScale = 3 // 放大倍數scrollView.minimumZoomScale = 0.1 // 縮小倍數// 獲取當前縮放倍數let zoomScale:CGFloat = scrollView.zoomScale// 設置代理,需要遵守協議 UIScrollViewDelegatescrollView.delegate = self
3、向 scrollView 添加圖片集
3.1 添加少量圖片
每次添加一張圖片的時候都會創建一個 UIImageView 對象,如果添加的圖片過多或圖片太大會占用大量的內存。
Objective-C
#define WIDTH [UIScreen mainScreen].bounds.size.width#define HEIGHT [UIScreen mainScreen].bounds.size.height// 設置 scrollView 的尺寸CGFloat w = WIDTH - 20;CGFloat h = HEIGHT - 40;// 設置圖片數量int count = 5;UIScrollView *scrollView = [[UIScrollView alloc] initWithFrame:CGRectMake(10, 30, w, h)];scrollView.pagingEnabled = YES;[self.view addSubview:scrollView];// 設置 contentSize,水平方向能滾動scrollView.contentSize = CGSizeMake(count * w, 0);// 添加少量圖片for (int i = 0; i < count; i++) {UIImageView *imageView = [[UIImageView alloc] initWithFrame:CGRectMake(i * w, 0, w, h)];imageView.image = [UIImage imageNamed:[NSString stringWithFormat:@"%d.jpg", i]];// 將 imageView 添加到 scrollView 上[scrollView addSubview:imageView];}
Swift
let WIDTH = UIScreen.mainScreen().bounds.size.widthlet HEIGHT = UIScreen.mainScreen().bounds.size.height// 設置 scrollView 的尺寸let w = WIDTH - 20let h = HEIGHT - 40// 設置圖片數量let count:Int = 5let scrollView:UIScrollView = UIScrollView(frame: CGRectMake(10, 30, w, h))scrollView.pagingEnabled = trueself.view.addSubview(scrollView)// 設置 contentSize,水平方向能滾動scrollView.contentSize = CGSizeMake(count * w, 0)// 添加少量圖片for i in 0 ..< count {let imageView:UIImageView = UIImageView(frame: CGRectMake(CGFloat(i) * w, 0, w, h))imageView.image = UIImage(named: String(format: "%d.jpg", i))// 將 imageView 添加到 scrollView 上scrollView.addSubview(imageView)}
3.2 添加大量圖片
只創建 3 個 UIImageView 對象,向 scrollView 添加圖片時復用這 3 個 UIImageView 對象。
Objective-C
4、UIScrollView 的協議方法
需遵守協議 UIScrollViewDelegate,并設置代理
設置代理方法:
通過代碼
// self 就是控制器self.scrollView.delegate = self;
通過 storyboard 拖線
Objective-C
拖拽
// 將要開始拖拽- (void)scrollViewWillBeginDragging:(UIScrollView *)scrollView {}// 將要結束拖拽- (void)scrollViewWillEndDragging:(UIScrollView *)scrollView withVelocity:(CGPoint)velocity targetContentOffset:(inout CGPoint *)targetContentOffset {}// 已經結束拖拽,decelerate 松手后 是否有慣性滾動 0:沒有,1:有- (void)scrollViewDidEndDragging:(UIScrollView *)scrollView willDecelerate:(BOOL)decelerate {}
滾動
// 滾動過程中,只要滾動就會觸發- (void)scrollViewDidScroll:(UIScrollView *)scrollView { }// 已經結束滾動,滾動動畫停止時執行,代碼改變時觸發,也就是 setContentOffset 改變時- (void)scrollViewDidEndScrollingAnimation:(UIScrollView *)scrollView {}
慣性滾動
// 將要開始慣性滾動- (void)scrollViewWillBeginDecelerating:(UIScrollView *)scrollView {}// 已經結束慣性滾動- (void)scrollViewDidEndDecelerating:(UIScrollView *)scrollView {}
滾到頂端
// 設置點擊狀態欄時是否滾到頂端- (BOOL)scrollViewShouldScrollToTop:(UIScrollView *)scrollView {return YES;}// 已經滾到頂端,點擊狀態欄時調用- (void)scrollViewDidScrollToTop:(UIScrollView *)scrollView {}
縮放
// 設置被縮放的空間,一個 scrollView 中只能有一個子控件被縮放,如果有很多個子控件縮放時會引起錯亂- (UIView *)viewForZoomingInScrollView:(UIScrollView *)scrollView {return [scrollView.subviews[0] viewWithTag:100];}// 將要開始縮放- (void)scrollViewWillBeginZooming:(UIScrollView *)scrollView withView:(UIView *)view {}// 已經結束縮放- (void)scrollViewDidEndZooming:(UIScrollView *)scrollView withView:(UIView *)view atScale:(CGFloat)scale {}// 縮放過程中,只要縮放就會觸發- (void)scrollViewDidZoom:(UIScrollView *)scrollView {}
Swift
拖拽
// 將要開始拖拽func scrollViewWillBeginDragging(scrollView: UIScrollView) {}// 將要結束拖拽func scrollViewWillEndDragging(scrollView: UIScrollView, withVelocity velocity: CGPoint, targetContentOffset: UnsafeMutablePointer<CGPoint>) {}// 已經結束拖拽,decelerate 松手后 是否有慣性滾動 0:沒有,1:有func scrollViewDidEndDragging(scrollView: UIScrollView, willDecelerate decelerate: Bool) {}
滾動
// 滾動過程中,只要滾動就會觸發,只要滾動就會觸發func scrollViewDidScroll(scrollView: UIScrollView) {}// 已經結束滾動,滾動動畫停止時執行,代碼改變時觸發,也就是 setContentOffset 改變時func scrollViewDidEndScrollingAnimation(scrollView: UIScrollView) {}
慣性滾動
// 將要開始慣性滾動func scrollViewWillBeginDecelerating(scrollView: UIScrollView) {}// 已經結束慣性滾動func scrollViewDidEndDecelerating(scrollView: UIScrollView) {}
滾到頂端
// 設置點擊狀態欄時是否滾到頂端func scrollViewShouldScrollToTop(scrollView: UIScrollView) -> Bool {return true}// 已經滾到頂端,點擊狀態欄時調用func scrollViewDidScrollToTop(scrollView: UIScrollView) {}
縮放
// 設置被縮放的空間,一個 scrollView 中只能有一個子控件被縮放,如果有很多個子控件縮放時會引起錯亂func viewForZoomingInScrollView(scrollView: UIScrollView) -> UIView? {return scrollView.subviews[0].viewWithTag(100)}// 將要開始縮放func scrollViewWillBeginZooming(scrollView: UIScrollView, withView view: UIView?) {}// 已經結束縮放func scrollViewDidEndZooming(scrollView: UIScrollView, withView view: UIView?, atScale scale: CGFloat) {}// 縮放過程中,只要縮放就會觸發func scrollViewDidZoom(scrollView: UIScrollView) {}
5、Storyboard 中設置
在 Storyboard 場景中設置
Scroll View
Style 滾動條顏色類型 Scroll Indicators -- Shows Horizontal Indicator 顯示水平滾動條 -- Shows Vertical Indicator 顯示垂直滾動條 Scrolling -- Scolling Enabled 可以滾動 -- Paging Enabled 按頁面滾動 -- Direction Lock Enabled 滾動方向固定 Bounce -- Bounces 啟動彈簧效果 -- Bounce Horizontal 水平彈簧效果 -- Bounce Vertical 垂直彈簧效果 Zoom 最小/最大縮放值 Touch -- Bounces Zoom -- Delays Content Touches -- Cancellable Content Touches Keyboard 鍵盤設置
在 Storyboard 場景綁定的 Controller 中設置
在 Storyboard 添加的 ScrollView 上需在其上添加子視圖作為 ContentView,并添加子視圖的約束,ScrollView 才能夠計算 contentSize 的大小,子視圖才能夠滾動。
若要在 Storyboard 的 ScrollView 上添加一個不隨 ContentView 滾動的視圖,需在 ViewController 上添加一個和 ScrollView 相同位置大小的視圖,并設置不滾動視圖相對于該視圖的約束。