你好,歡迎來到IOS教程網

 Ios教程網 >> IOS編程開發 >> IOS開發基礎 >> UIScrollView新手教程

UIScrollView新手教程

編輯:IOS開發基礎

本文由我是喬忘記瘋狂(簡書)翻譯自AppCoda,作者:joyce echessa
原文:A Beginner’s Guide to UIScrollView


在iOS開發中,滾動視圖(UIScrollView)通常用於顯示內容尺寸大於屏幕尺寸的視圖。滾動視圖有以下兩個主要作用:
  • 讓用戶可以通過拖拽手勢來觀看想看到的內容

  • 讓用戶可以通過捏合手勢來放大或縮小觀看的內容

在iOS應用中常見的表格視圖(UITableView)就繼承自滾動視圖,並因此可以通過上下滾動來顯示更多的內容。

在本篇教程中,我們將討論滾動視圖的諸多方面內容,主要包括:使用純代碼和可視化編程兩種方式來創建一個滾動視圖、實現滾動和縮放功能,以及如何嵌套使用滾動視圖。

363.jpg

繼續閱讀之前,請先下載本文示例代碼所需的資源文件,詳見:資源文件地址。(譯注:原文資源文件地址需要FQ訪問,本人已轉存到GitHub上,詳見這裡)

使用純代碼方式創建UIScrollView

UIScrollView同其他視圖一樣,可以通過純代碼和可視化編程兩種方式來創建。在創建之後,只需要少量額外設置就可以讓UIScrollView獲得基本的滾動功能。

UIScrollView也和其他視圖一樣,應該被一個控制器管理或者添加到某個視圖層級中。想要完成滾動功能還需要對UIScrollView進行以下兩步設置:

  • 必須設置UIScrollView的contentSize屬性,它提供了UIScrollView的內容的大小,也就是可以滾動的區域的大小。

  • 必須為UIScrollView添加一個或多個用於顯示和滾動的子視圖,這些視圖提供了UIScrollView顯示的內容。

你還可以根據應用的具體需求設置UIScrollView的一些顯示效果,比如:是否顯示水平和豎直方向的滾動條、滾動的彈性效果、縮放的彈性效果,以及允許的滾動方向等。

接下來我們將在代碼中創建一個UIScrollView。在下載的資源文件中打開ScrollViewDemo工程。它就是一個簡單的Single View Application工程,只不過將storyboard中根控制器的類型綁定為自己新建的叫做ScrollViewController的控制器,還在項目中添加了一張我們要用到的圖片,圖片名稱為image.png。

接下來打開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
    scrollView.autoresizingMask = UIViewAutoresizing.FlexibleWidth | UIViewAutoresizing.FlexibleHeight
    scrollView.addSubview(imageView)
    view.addSubview(scrollView)
}

上述代碼創建了一個UIScrollView和UIImageView,UIImageView被設置為UIScrollView的子視圖。contentSize屬性控制滾動區域的大小,我們將它設置為跟圖片的尺寸一樣大(2000×1500)。我們將滾動視圖的背景色設置為黑色,這樣圖片就像在一塊黑色幕布上滾動一樣。我們將滾動視圖的autoresizingMask屬性設置為.FlexibleWidth和.FlexibleHeight,使它能夠在設備旋轉之後自動適應新的寬度和高度。運行當前應用,你已經可以通過拖拽手勢來滾動顯示圖片了。

38.jpg

當你啟動應用後,你會發現圖片初始顯示區域是它左上角的部分。

40.jpg

這是因為滾動視圖的bounds的起點默認為(0, 0),代表了左上角。如果你想改變啟動後顯示的位置,你需要更改滾動視圖的bounds的起點。因為這種需求經常被提起,所以UIScrollView專門提供了一個屬性contentOffset用來實現這種需求。

在代碼中添加如下語句,注意添加在設置autoresizingMask語句之後。

scrollView.contentOffset = CGPoint(x: 1000, y: 450)

重新運行應用,你會發現一開始就會顯示圖片的另一部分而不是左上角。你可以通過這種方式來決定程序啟動後將要顯示的內容。

41.jpg

縮放

我們已經添加了一個UIScrollView,並且能夠讓用戶通過拖拽來觀看尺寸大於屏幕尺寸的內容。相當棒,但如果視圖能夠縮放的話會帶來更好的體驗。

要支持縮放功能,你必須為UIScrollView設置一個代理,而且代理必須遵守UIScrollViewDelegate協議,代理還需要實現viewForZoomingInScrollView()方法,該方法返回想要被縮放的視圖。

你還應該為縮放設置一個比例,可以通過UIScrollView的minimumZoomScale和maximumZoomScale這兩個屬性來實現,它們的默認值都是1.0。

按照如下代碼更改ScrollViewController的定義:

class ScrollViewController: UIViewController, UIScrollViewDelegate {

然後添加如下代碼:

func viewForZoomingInScrollView(scrollView: UIScrollView) -> UIView? {
    return imageView
}

接下來在viewDidLoad()方法的最後添加如下代碼:

scrollView.delegate = self    
scrollView.minimumZoomScale = 0.1
scrollView.maximumZoomScale = 4.0
scrollView.zoomScale = 1.0

在上述代碼中,我們設置了zoomScale為1.0,然後設置了縮放的最大和最小比例。在程序運行後,會按照圖片的原始尺寸顯示(因為zonmScale為1.0),當你使用捏合手勢來操作圖片時,你會發現圖片可以被縮放了。我們設置了maximumZoomScale為4.0,所以圖片最大只能放大到4倍。你也會發現,圖片放大4倍後會變得很模糊,所以接下來我們會把它的縮放比例重新設置為1.0。

42.jpg

從上面的圖片中我們可以發現,我們之前將minimumZoomScale設置為0.1實在是太小了,屏幕空出了很多空閒的地方。在橫屏模式下,空閒的區域看上去更大。我們希望圖片能在某一方向上能與屏幕相匹配,讓圖片既能完全顯示,又能盡量減少屏幕的空閒空間。

43.jpg

要達到這樣的效果,你必須通過圖片尺寸和UIScrollView的尺寸來計算最小的縮放比例。

首先在viewDidLoad()方法中刪除以下三行代碼:

scrollView.minimumZoomScale = 0.1
scrollView.maximumZoomScale = 4.0
scrollView.zoomScale = 1.0

在控制器類中添加如下方法。在方法中,我們算出圖片同UIScrollView的高度和寬度的比值,並將最小縮放比例設置為兩者中更小的那個。注意,我們已經刪除了maximumZoomScale的設置,所以它的默認值為1.0。

func setZoomScale() {
    let imageViewSize = imageView.bounds.size
    let scrollViewSize = scrollView.bounds.size
    let widthScale = scrollViewSize.width / imageViewSize.width
    let heightScale = scrollViewSize.height / imageViewSize.height
    scrollView.minimumZoomScale = min(widthScale, heightScale)
    scrollView.zoomScale = 1.0
}

在viewDidLoad()方法最後調用這個方法:

setZoomScale()

在viewWillLayoutSubviews()方法中也需要調用該方法,這樣當用戶改變屏幕方向後,圖片的尺寸仍然是正確的。

override func viewWillLayoutSubviews() {
    setZoomScale()
}

運行程序,現在你會發現無論你縮放到多小,圖片都會完整顯示並且盡量占滿剩余的空間。

44.jpg

我們可以發現,圖片是被定位在屏幕左上角的,我們希望將它放在屏幕中間。

在代碼中添加如下方法。

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)
    }

這個方法在縮放的時候就會被調用,它會通知代理UIScrollView的縮放比例發生改變了。在上面的方法中,我們計算了圖片在滾動視圖中的內間距,從而使圖片始終在屏幕的中間。對於上、下方向的內邊距,我們首先判斷圖片視圖的高度是否小於滾動視圖的高度,如果是就將邊距設為兩者的差值的一半,否則設為0。水平間距我們采用同樣的方式計算。然後通過contentInset屬性設置所有方向的內邊距,這個屬性代表了UIScrollView的內容距離UIScrollView本身四周的距離。

運行程序,你會發現當你縮小圖片時,圖片始終保持在屏幕的中間。

45.jpg

通過雙擊來縮放

UIScrollView默認只支持通過捏合手勢來實現縮放效果,如果想實現通過雙擊來縮放,則需要自己做些額外的設置。

iOS人機界面指南中介紹了可以通過雙擊手勢來達到縮放的效果。使用雙擊手勢進行縮放需要一定的前提:要縮放的視圖只能在最大和最小比例兩個固定值之間來回縮放,就像蘋果官方的相冊應用一樣,當你雙擊圖片時,圖片放大至最大,當你再次雙擊時,圖片縮小至最小,或者可以通過連續的雙擊使視圖一點點達到最大,然後再次雙擊的時候,將視圖恢復為全屏顯示。但是大多數應用需要實現更靈活的雙擊縮放效果,例如地圖應用,當你雙擊時會使其放大,繼續雙擊會繼續放大,想要縮小則可以使用雙指捏合手勢來實現。

要想在你的程序中實現雙擊縮放功能,你需要監聽UIScrollView的手勢並進行處理。在我們的程序中,我們將模仿蘋果官方的相冊應用的效果,當你雙擊時放大到最大值,再次雙擊時則縮小到最小值。

在代碼中添加如下兩個方法。

func setGestureRecognizer() {
    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()方法最後調用上面的方法。

setGestureRecognizer()

在上面的代碼中,我們為UIScrollView添加了一個雙擊手勢的監聽,然後根據圖片當前的縮放比例,來判斷是將圖片放大或者縮小。

運行程序,你會發現已經能通過雙擊手勢來縮放圖片了。

用可視化編程方式創建UIScrollView

使用storyboard可以實現和我們上面使用代碼方式實現的同樣的功能,而且更為簡單,代碼量更少。

在Main.storyboard文件中,拖一個新的視圖控制器,並將其設置為初始控制器(既可以將箭頭拖到新控制器上,也可以在屬性選項卡中選中Is Initial View Controller復選框)。

拖一個UIScrollView到新的控制器中,然後設置其邊緣始終粘著屏幕。

46.png

然後拖一個UIImageView到剛才的UIScrollView中,將它的邊緣設置為粘著UIScrollView。

47.png

要記住UIScrollView需要知道它的內容的大小,才可以實現滾動。當你為UIImageView設置圖片時,UIScrollView的內容大小就會被自動設置為圖片的大小。

在UIImageView的屬性選項卡中,將Image屬性設置為image.png,然後通過updating the frames解決自動布局的問題。運行程序,你會發現已經實現圖片的滾動顯示了,並且沒有敲一行代碼。你還可以在UIScrollView的屬性選項卡中查看還有哪些屬性可以設置,比如可以設置最大和最小的縮放比例。

如果想要實現縮放功能,你仍然需要通過代碼,設置代理並實現viewForZoomingInScrollView()方法,同我們之前做過的一樣,就不再重復一遍了。

UIScrollView的嵌套使用

可以在一個UIScrollView中嵌套另一個UIScrollView,兩個UIScrollView既可以是相同方向滾動的,也可以是不同方向的。這部分內容的示例代碼請使用NestedScrollViews項目。

相同方向的UIScrollView嵌套

相同方向的UIScrollView嵌套是指一個UIScrollView,它有另一個UIScrollView作為子控件,並且它們的滾動方向一致。你可以用相同方向的嵌套來實現這樣的效果,比如在UIScrollView中添加多組要區分開的數據,你還可以通過它來實現兩個UIScrollView同時滾動時的視差效果。在我們的示例中,我們將兩個相同方向的UIScrollView設置不同的滾動速度,從而實現滾動時的視差效果。

打開NestedScrollViews項目中的storyboard文件,你將看到兩個UIScrollView,分別叫做foreground和background。background裡面添加了一個UIImageView,並將圖片設置為image.png,foreground裡面添加了一些標簽和一個作為容器用的UIVIew,這些標簽只是為了方便我們觀看視圖的滾動,容器視圖我們將在下一節內容中才用到。

我們的界面這樣就算搭建完成了,現在運行程序的話,你會發現只有foreground視圖在滾動,而background視圖保持不動。接下來我們將要實現background的滾動,並且實現滾動的視差效果。

首先將foreground和background兩個UIScrollView連線到控制器,之後代碼會如下所示:

@IBOutlet weak var background: UIScrollView!
@IBOutlet weak var foreground: UIScrollView!

我們需要知道foreground視圖滾動了多長的距離,用來計算background視圖需要滾動多長的距離。所以我們需要為foreground視圖設置一個代理,用來監聽它的滾動。

class ViewController: UIViewController, UIScrollViewDelegate {

在viewDidLoad()方法中設置foreground視圖的代理。

foreground.delegate = self

然後實現如下代理方法。

func scrollViewDidScroll(scrollView: UIScrollView) {
    let foregroundHeight = foreground.contentSize.height - CGRectGetHeight(foreground.bounds)
    let percentageScroll = foreground.contentOffset.y / foregroundHeight
    let backgroundHeight = background.contentSize.height - CGRectGetHeight(background.bounds)
    background.contentOffset = CGPoint(x: 0, y: backgroundHeight * percentageScroll)
}

在上面的代碼中,我們獲取了foreground視圖可以滾動的最大高度,然後用當前滾動的距離除以它以獲取滾動的比例,然後獲取background視圖可以滾動的最大高度,將其乘以滾動比例,就可以得到background應該滾動的距離。運行你的程序,在進行滾動時你會發現foreground和background兩個視圖都在滾動,並且background視圖滾動的更快,從而有一種視差效果。

51.gif

交叉方向的UIScrollView嵌套

交叉方向的UIScrollView嵌套是指一個UIScrollView,它有另一個UIScrollView作為子控件,並且它們的滾動方向正好相差90°,接下來我們就演示一下這種情況。

在NestedScrollViews項目中,你會發現在foreground裡面有一個Container View,我們將用它來設置我們水平滾動的UIScrollView。

在storyboard中新拖入一個控制器,按住Control鍵從Container View拖到新的控制器,選擇embed方式。然後選中這個控制器,將它的Size選項設為Freeform並將其高度設為128,因為Container View的高度就是128。

往新控制器中拖入一個UIScrollView,設置其邊緣始終粘著父控件。然後在UIScrollView中拖入一個70×70的UIView,將其背景色設為灰色方便我們觀看,然後復制多個,從左到右依次擺放在UIScrollView中。你不需要精確地去設置每一個UIView的位置,接下來我會教你們怎麼去做。現在我們的控制器界面應該是這個樣子。

52.png

選擇最左邊的UIView,添加它上邊和左邊的約束,再添加寬度和高度約束。

53.png

再選擇最右邊的UIView,添加它的上邊、右邊、寬度和高度約束。

54.png

接下來,選中我們的UIScrollView,然後點擊上面菜單欄中的Editor > Resolve Auto Layout Issues > All Views > Add Missing Constraints。這樣我們所有的UIView就都添加好了約束。運行你的程序,豎直滾動到底部,你會看見我們的Container View,你可以水平滾動它裡面的內容。下圖中,我將控制器自身視圖的背景色設置為透明,所以你看到的效果就是這樣的。

56.gif


我們的教程這就結束了,並沒有包含UIScrollView所有的方方面面,但我希望通過這篇教程可以讓你對UIScrollView有初步的了解,更多UIScrollView的知識,你可以查看蘋果的官方文檔:Scroll View Programming Guide。

你可以在這裡下載完整的示例程序作為學習參考。(譯注:原文資源文件地址需要FQ訪問,本人已轉存到GitHub上,詳見這裡)

  1. 上一頁:
  2. 下一頁:
蘋果刷機越獄教程| IOS教程問題解答| IOS技巧綜合| IOS7技巧| IOS8教程
Copyright © Ios教程網 All Rights Reserved