[iOS] #1 運用 Storyboard 模仿視覺化搜尋App『Pinterest』

之前沈迷於動物森友會(還在遊戲裡舉辦生日趴踢),常透過Pinterest尋找佈置靈感,情緒低落的時候也很適合打開Pinterest瀏覽各種可愛時尚漂亮的影像轉換心情!因此這次作業決定以Pinterest為模仿對象,練習各種UI元件的運用。

展示

minimap

頁面串接 > Tab Bar Controller

Pinterest以Tab切換五個主頁面:首頁、搜尋、建立、通知、已儲存,除了基本的各個View Controller的串接之外,特別筆記如何變更Tab字體及圖示的顏色。由於Attributes面板沒有相關設定,需改由Identity面板定義:

(1) 點選Tab Bar Controller 中的 Tab Bar

(2) 再切換至 Identity Inspector 於 User Define Runtime Attributes 設定

(3) Key Path = tintColor,Type = Color,Value = 由選色工具挑選

頁面串接 > Navigation Controller

五個主頁面都採用Navigation Controller串接不同階層的子頁面,每一層頁面會自動於左上方顯示Back按鈕,若有設定Title,Back會自動變更為Title字串,但若不想在頁面上顯示Title,又想自訂Back按鈕的文字,也可以利用Back Button項目客製。在此練習如何變更Back的字串和顏色:

> 變更Back文字

(1) 點選上一頁的Title Bar

(2) 切換至Attributes Inspector面板

(3) 在Back Button欄位輸入想要顯示的文字

> 變更 Back 顏色

(1) 展開上一頁的Navigation Item,點選Back Button

(2) 切換至Attributes Inspector面板

(3) 在 Tint 項目設定顏色

A. 首頁

(A-1) 橫向Scroll View

上方的橫向捲動按鈕選單,運用Scroll View實現。一開始在模擬器無法捲動,才發現由於這個Scroll View的位置和Navigation Title重疊,必須把Navigation Bar的User Interaction Enabled取消勾選,使用者才能直接點觸到Scroll View。

(A-2) 直向Scroll View

首頁的照片以Button、Label組成,利用Button的Corner Style設定照片的圓角效果,每張照片右下角的 + 按鈕,也是利用Button Corner Style = Capsule繪製成圓形。點選任一個照片按鈕,即可進入該照片的詳細說明頁。

(A-3) 詳細說明頁

詳細說明頁以圓角卡片的形式呈現。因此將外層View設定User Define Runtime Attributes:KeyPath = cornerRadius、Type = Number、Value=數字愈大愈圓。另外也要記得在View的Attribute模板勾選Clips to Bounds,才能讓Image View的邊緣也一同切出圓角。

B. 搜尋

搜尋功能我只繪製了Search Bar,待之後更熟悉Swift再來追加 !

C. 建立

Tab建立的頁面與其他Tab不同,點選之後並沒有切換頁面,而是在原本的頁面上方,新增只有螢幕高度一半的View,且將原頁面加上毛玻璃效果,以突顯新區塊的內容。若使用者再點選其他Tab,將解除畫面上的毛玻璃效果,並隱藏新區塊。

在網路上搜尋到的解決方案得透過程式實現,不確定做法是否正確。主要的概念是在既有的View上面,透過程式動態追加新的View蓋在上方,總共需要蓋兩個新的View,一個是毛玻璃View,一個是螢幕一半的View。

(C-1) 利用Storyboard繪製View,並指定Identity Id = MyView,以便程式透過Id取得View物件。

(C-2) 在ViewController.swift撰寫程式如下:

class TabBarController: UITabBarController, UITabBarControllerDelegate {

override func viewDidLoad() {
super.viewDidLoad()
self.delegate = self
}

func tabBarController(_ tabBarController: UITabBarController,
shouldSelect viewController: UIViewController) -> Bool {

//偵測目前使用者點選了哪一個Tab
let tabbarIndex = tabBarController.viewControllers!.firstIndex(of: viewController)!

//偵測目前畫面上停留的是哪一個View
let getCurrentView = tabBarController.selectedViewController!.view!

//remove subviews
//檢查目前是不是已經有毛玻璃View和“建立View",若有的話要先移除,不然會產生千千萬萬個View
//程式產生"建立View"時,已指定View.Tag=999,因此可以透過viewWithTag的function找到它
if let viewWithTag = getCurrentView.viewWithTag(999) {
//將"建立View"移除
viewWithTag.removeFromSuperview()
}

//程式產生毛玻璃View時,已指定View.Tag=998,因此可以透過viewWithTag的function找到它
if let maskWithTag = getCurrentView.viewWithTag(998) {
//將毛玻璃View移除
maskWithTag.removeFromSuperview()
}

//如果使用者點選“建立Tab”
if tabbarIndex == 2 {

//---- 毛玻璃View ----//
//設定毛玻璃效果
let blurEffect = UIBlurEffect(style: .systemUltraThinMaterialLight)

//產生一個新的view,加上毛玻璃效果
let blurView = UIVisualEffectView(effect: blurEffect)

//給毛玻璃View加個標籤,之後需要透過Tag找到它
blurView.tag = 998

//指定View在螢幕上的座標和長寬尺寸
//毛玻璃要蓋住整個View,所以直接取用目前的尺寸
blurView.frame = CGRectMake(0, 0, self.view.frame.size.width, self.view.frame.size.height);

//在目前顯示的View上面,加一層新的View
getCurrentView.addSubview(blurView)

//---- "建立View" ----
//直接把透過Storyboard繪製的View作為"建立View"
//預先在Storyboard的Identity面板設定View的Id="MyView"
//利用Id找到已繪製好的View
let myview = storyboard!.instantiateViewController(withIdentifier: "MyView").view

//給"建立View"加個標籤,之後需要透過Tag找到它
myview?.tag = 999

//指定View在螢幕上的座標和長寬尺寸
//View是在螢幕的下方,高度300,因此Y座標可以利用上一層View的高度-300計算而得
myview?.frame = CGRectMake(0, self.view.frame.size.height-300, self.view.frame.size.width, 300);

//在目前顯示的View上面,加一層新的View
getCurrentView.addSubview(myview!)

//確保"建立View"蓋在所有View的最上方
getCurrentView.bringSubviewToFront(myview!)

return false

} else {

return true
}
}
}

D. 通知

Table View Controller

通知主頁採用Table View,表格選擇靜態格式 ( Content = Static Cells ),以符合每一列內容都不相同的需求。原本畫面最上方的 “更新” 及 “訊息“ 按鈕,應是固定在Title Bar的位置,當捲動Table View時,兩個按鈕固定待在原處才對,但我一直找不到方法在Table View的Header放置按鈕,只好暫時將兩個按鈕放在Table View內的第一列中,也因此會跟著整個表格往上捲。之後若找到解決方式再來更新文章。

相片拼貼

Pinterest常有相片拼貼的區塊,區塊內的相片會以白色邊線區隔。每個區塊以一個View和多個Image View組成。

底層的View,BackgroundColor = 白色,且設定為圓角(在Identity模板設定User Define Runtime Attributes:KeyPath = cornerRadius、Type = Number、Value=數字愈大愈圓),也要記得在Attribute模板勾選Clips to Bounds,才能讓Image View的邊緣也一同切出圓角。

Image View可以隨意編排,但彼此之間保留一點空隙,就會有白色邊線的效果。

E. 已儲存

已儲存Tab的內容,和其他Tab採用的UI大致相似,比較不一樣的地方是進入第二層相片流選單時,下方的Tab Button自動隱藏。這可簡單於Storyboard的Attribute面板設定即可。

(1) 點選View Controller

(2) 切換至Attributes Inspector面板

(3) 勾選 Hide Bottom Bar On Push

心得

練習真的是熟悉的最佳法門!從一開始參考課程投影片一步一步操作,到後來幾秒鐘就可以設定好Scroll View了。忍不住要讚嘆Xcode的開發環境真的非常友善,元件們會乖乖地待在正確的位置,很多背後的小細節都幫忙處理好,畫面和工具也簡單明暸,不會迷失在繁複的介面中。一方面也期許自己深入認識更多種類的UI元件,才能挑選出最符合需求的UI組合。

GitHub連結

--

--