原文: appcoda.com (IOS Beginner's Guide to UIScrollView 由joyce echessa發布
翻譯: 安明哲
說明: 轉載時請注明出處
在IOS中,scroll view 本用作顯示屏幕上不能完全裝下的內容。它主要有兩個作用:
- 用戶可以通過拖動的方式顯示更多內容
- 用戶可以通過手勢縮放現實的內容
IOS的公共控件UITbaleView就是繼承與UIScrollView并提供了一種不錯的方式去呈現內容(當這個內容大于屏幕尺寸)
在本節課程中,我們將從多方面了解ScrollView,特性,創建一個ScrollView(通過代碼和通過Interface Builder),滾動和縮放,insets和outsets。
開始閱讀之前,請首先下載本屆課程的源代碼。
譯者注:
這里的下載需要自帶梯子,如果沒有梯子,可以從我的服務器獲取
通過編碼方式創建ScrollView
不管是通過代碼或者Interface builder都可以在一個view中創建一個Scroll View,然后做一點點必要的配置就實現一個基本的ScrollView的功能了。
- 你必須設置
ContentSize
屬性,此屬性用于指定你要展現的內容的Size,IOS由此確認滾動區域。
- 你還必須添加一個或者多個View以供顯示。
當然,還有許多可選的配置,垂直或是水平滾動,滑動、縮放的效果,滾動條的路徑(滾動的方向)等等。
現在,我們開始通過代碼創建一個ScrollView,打開 ScrollViewDemo(剛才下載的項目),僅僅是一個簡單地Signle View,其中ScollerViewController這個類與Interface Builder中的UIViewController關聯,并且此項目還包含了一張圖片image.png (圖片來自unsplash.com)
打開ScrollViewController.swift 并且添加如下代碼:
var scrollView: UIScrollView!
var imageView: UIImageView!
修改 viewDidLoad() 如下:
override func viewDidLoad() {
super.viewDidLoad()
imageView = UIImageView(image: UIImage(named: "image.png"))
scrollView = UIScrollView(frame: view.bounds)
scrollView.backgroundColor = UIColor.blackColor()
scrollView.contentSize = imageView.bounds.size
//譯者注:如果你是用的是swift2.x 這行代碼會出現問題
scrollView.autoresizingMask = UIViewAutoresizing.FlexibleWidth | UIViewAutoresizing.FlexibleHeight
scrollView.addSubview(imageView)
view.addSubview(scrollView)
}
譯者注:
上面的代碼中帶注釋的一行會在swift2下報錯,在swift2.0中同時取得兩個枚舉值不再支持使用 | 運算符,而改用數組 ,所以swift2中正確的代碼應該是這個樣子
scrollView.autoresizingMask = [UIViewAutoresizing.FlexibleHeight,UIViewAutoresizing.FlexibleWidth]
上面的代碼創建了一個scroll view和一張圖片。其中ImageView是ScrollView的子view(有點繞);contentSize指定了可滾動的地帶為圖片的大小(2000 x 1500);scrollView的背景為黑色,設置autoresizeMask為.FlexibleWidth和 .FlexibleHeight以便于在屏幕旋轉的時候scrollview與parsentView維持正確位置關系。運行這個app的時候你應該能夠圖片的沒一部分。
當你運行的時候,你可能會注意到,通常你只能看到圖片左上角的那一部分,就像下面這樣:
這是因為scrollview的bound(默認)被設置為(0,0),也就是圖片的左上角。如果你希望重新定位第打開app時圖片的顯示位置,你需要改變scrollview的bound,SrollerView有一個contentOffset屬性可以幫助你實現這個需求。
添加如下代碼到你的代碼中,(注意這段代碼應該在autoresizingMask之后):
scrollView.contentOffset = CGPoint(x: 1000, y: 450)
這個時候再次運行app你將看到scrollview已經移動到圖皮的另一部分,這樣當view被加載的時候,你就可以確定你要給用戶呈現什么。
縮放
我們已經創建了一個scrollview并且允許用戶通過滾動來控制一個較大尺寸的view,但是如果視圖可以縮放,將進一步增強用戶體驗。
要支持縮放,你必須為view添加一個delegate,這個delegate必須遵從IScrollViewDelegate這個協議,并且必須要實現viewForZoomingInScrollView(),該方法返回一個view,這個view將可以在scrollview內縮放。
你依舊要做一點點的工作來支持縮放,你可以設置scrollvierw的 minimumZoomScale 和 maximumZoomScale屬性(如果不設定這兩個屬性,他們將會有一個默認值-->1.0)
修改ScrollerView的定義如下:
class ScrollViewController: UIViewController, UIScrollViewDelegate
然后添加如下方法到類中:
func viewForZoomingInScrollView(scrollView: UIScrollView) -> UIView? {
return imageView
}
最后,添加如下代碼到viewDidLoad()的底部:
譯者注:主要就是綁定delegate,設置縮放的范圍和步長
scrollView.delegate = self
scrollView.minimumZoomScale = 0.1
scrollView.maximumZoomScale = 4.0
scrollView.zoomScale = 1.0
上面的代碼中設置了zoomScale為1.0用于指定最大縮放和最小縮放的縮放因子(默認情況下縮放的大小),當你運行app,你可以滾動并且縮放,我們設置最大縮放比例4.0,所以你最大可以放大這張圖片到原始尺寸的4倍(最小縮放比例同理),但是當我們把圖片放大的時候,圖片會變得很很模糊,這并不是用戶想要看到的,下一步中我們將讓圖片返回到1.0初始的狀態。
在上邊,我們設置minimumZoomScale為0.1以至于縮小之后返回一個很小的圖片并且屏幕中出現了很多空白。我們想讓圖片自適應
要實現這個功能,我們需要根據scrollview的size和imageview的size計算最小縮放比例。
首先刪除viewDidLoad里面的幾行代碼:
scrollView.minimumZoomScale = 0.1
scrollView.maximumZoomScale = 4.0
scrollView.zoomScale = 1.0
添加一個方法到類中,我們得到的寬度和高度的比例,并選擇較小的兩者,并設置為minimumScale。提示一下,我們刪除了maxinmumZoomScale,所以他會被默認設置為1.0.
func setZoomScale(){
let imageViewSize = imageView.bounds.size
let scrollViewSize = scrollView.bounds.size
let widthSacle = scrollViewSize.width / imageViewSize.width
let heightSacle = scrollViewSize.height / imageViewSize.height
scrollView.minimumZoomScale = min(widthSacle, heightSacle)
scrollView.zoomScale = 1.0
}
然后再viewDidLoad()中調用這個方法
setZoomScale()
同時添加以下代碼,以便在設備方向改變后圖像依舊鋪滿屏幕。
override func viewWillLayoutSubviews() {
setZoomScale()
}
從上面的圖片中,你可能會注意到,圖片的位置在屏幕左上角,我們想改變他到屏幕的中心。
添加如下方法到類中:
func scrollViewDidZoom(scrollView: UIScrollView) {
let imageViewSize = imageView.frame.size
let scrollViewSize = scrollView.bounds.size
let verticalPadding = imageViewSize.height < scrollViewSize.height ? (scrollViewSize.height - imageViewSize.height) / 2 : 0
let horizontalPadding = imageViewSize.width < scrollViewSize.width ? (scrollViewSize.width - imageViewSize.width) / 2 : 0
scrollView.contentInset = UIEdgeInsets(top: verticalPadding, left: horizontalPadding, bottom: verticalPadding, right: horizontalPadding)
}
這個方法會在每次一縮放操作后執行,它告訴delegate,scrllowView的縮放比例發生了改變,上面的代碼計算了padding并且根據padding重新設置了scrollview 內容的padding
通過連按縮放
默認情況下ScrollView通過少量的代碼即可實現支持縮放(捏和撐)手勢,但是支持更多的手勢我們則需要再做一些工作。
IOS人機交互的借口定義了一種通過雙擊(連按)來進行縮放的方法。但是這個方法認為view的縮放級別是單一的(翻譯起來有點繞)總之就是雙擊一次執行了放大操作后下一次會默認執行縮小操作。但是很多程序的交互行為是需要更靈活的雙擊縮放的,比如地圖應用,需要不停地雙擊放大,而不是放大后再雙擊變成縮小。
在我們app中,我們將實現double-tap 把圖片放到最大,而后雙擊再縮小
添加如下代碼到類中:
func setupGestureRecognizer() {
let doubleTap = UITapGestureRecognizer(target: self, action: "handleDoubleTap:")
doubleTap.numberOfTapsRequired = 2
scrollView.addGestureRecognizer(doubleTap)
}
func handleDoubleTap(recognizer: UITapGestureRecognizer) {
if (scrollView.zoomScale > scrollView.minimumZoomScale) {
scrollView.setZoomScale(scrollView.minimumZoomScale, animated: true)
} else {
scrollView.setZoomScale(scrollView.maximumZoomScale, animated: true)
}
}
然后再viewDidLoad底部調用他們:
setupGestureRecognizer()
在上面的代碼中,我們添加了一個gesture recognize(手勢識別器),當用戶雙擊之后,我們可以根據當前的縮放級別來進行放大和縮小。
這樣,我們就可以通過雙擊放大和縮小圖片了。