#22 實作 Table View 的基本功能 -FB 頁面 part4

Lou
彼得潘的 Swift iOS / Flutter App 開發教室
18 min readJul 27, 2023

首頁選擇照片後跳轉po文頁面

選擇照片
segue id

HomePageTableViewController 傳遞資料到PostViewController

     override func prepare(for segue: UIStoryboardSegue, sender: Any?) {
if segue.identifier == "selcetPhoto",
let postViewController = segue.destination as? PostViewController,
let image = sender as? UIImage {
postViewController.selectedImage = image
}
}

PHPickerViewControllerDelegate

import PhotosUI

extension HomePageTableViewController: PHPickerViewControllerDelegate {

func picker(_ picker: PHPickerViewController, didFinishPicking results: [PHPickerResult]) {
picker.dismiss(animated: true)

guard !results.isEmpty else {
// 使用者沒有選擇照片
return
}

let itemProvider = results.first?.itemProvider

if let itemProvider = itemProvider, itemProvider.canLoadObject(ofClass: UIImage.self) {
itemProvider.loadObject(ofClass: UIImage.self) { [weak self] (object, error) in
DispatchQueue.main.async {
if let error = error {
print("Error loading image: \(error)")
return
}

if let image = object as? UIImage {
// 使用 Segue 跳轉 PostViewController傳遞圖片
self?.performSegue(withIdentifier: "selcetPhoto", sender: image)
}
}
}
}

}
}

首頁點選po文欄位跳轉

進入po文頁面

PostViewController新增貼文頁面

PostViewController 元件
import UIKit
import PhotosUI

class PostViewController: UIViewController {

@IBOutlet weak var userImageView: UIImageView!
@IBOutlet weak var userNameLabel: UILabel!
@IBOutlet weak var postTextView: UITextView!
@IBOutlet weak var postImageView: UIImageView!
@IBOutlet weak var stateButton: UIButton!
@IBOutlet weak var addPhotoButton: UIButton!
var postButton: UIButton!
var isPostPublic = true // 貼文公開狀態
var selectedImage: UIImage? // 前一頁選擇的照片

override func viewDidLoad() {
super.viewDidLoad()
navigationController?.hidesBarsOnSwipe = false
tabBarController?.tabBar.isHidden = true
postTextView.delegate = self // 代理TextView
updateUI()
setNavigationbar()
// 使用選取的照片 更新畫面
if let image = selectedImage {
postImageView.image = image
}
}

發布貼文按鈕樣式變更(有選擇圖片會變藍色)

按鈕樣式變更
    override func viewWillAppear(_ animated: Bool) {
super.viewWillAppear(animated)

// 有選擇圖片 發布按鈕樣式變成藍色
if selectedImage != nil {
postButton.backgroundColor = UIColor(red: 23/255, green: 119/255, blue: 241/255, alpha: 1)
}
}

設定UI畫面

    func updateUI() {

userNameLabel.text = "Lou"
userImageView.image = UIImage(named: "userphoto")
stateButton.layer.borderWidth = 1
stateButton.layer.borderColor = CGColor(red: 100/255, green: 103/255, blue: 106/255, alpha: 1)
stateButton.layer.cornerRadius = 10
stateButton.setImage(UIImage(systemName: "globe.asia.australia.fill"), for: .normal)
stateButton.tintColor = UIColor(red: 100/255, green: 103/255, blue: 106/255, alpha: 1)
stateButton.contentHorizontalAlignment = .left
addPhotoButton.layer.borderWidth = 1
addPhotoButton.layer.borderColor = CGColor(red: 100/255, green: 103/255, blue: 106/255, alpha: 1)
addPhotoButton.layer.cornerRadius = 10

// 調整間距 (檢查版本兩種寫法 消除舊版黃色警告)
if #available(iOS 15.0, *) {
var config = UIButton.Configuration.plain()
config.contentInsets = NSDirectionalEdgeInsets(top: 0, leading: 10, bottom: 0, trailing: 0)
stateButton.configuration = config
} else {
// 使用舊版的方式
stateButton.contentEdgeInsets = UIEdgeInsets(top: 0, left: 10, bottom: 0, right: 0)
}

}

自訂Navigation bar

貼文按鈕
func setNavigationbar() {
// 設定左邊關閉按鈕
let closeButton = UIButton(type: .system)
closeButton.frame = CGRect(x: 0, y: 0, width: 40, height: 40)
let closeSymbolConfig = UIImage.SymbolConfiguration(weight: .heavy)
let closeImage = UIImage(systemName: "xmark", withConfiguration: closeSymbolConfig)
closeButton.setImage(closeImage, for: .normal)
closeButton.tintColor = UIColor(red: 5/255, green: 5/255, blue: 5/255, alpha: 1)
closeButton.addTarget(self, action: #selector(closeButtonTapped), for: .touchUpInside)
let closeButtonItem = UIBarButtonItem(customView: closeButton)
navigationItem.leftBarButtonItem = closeButtonItem

// 設定右邊發文按鈕
postButton = UIButton(type: .system)
postButton.setTitle("發布", for: .normal)
postButton.titleLabel?.font = UIFont.systemFont(ofSize: 18, weight: .bold)
postButton.backgroundColor = UIColor(red: 228/255, green: 229/255, blue: 234/255, alpha: 1)
postButton.setTitleColor(UIColor(red: 1, green: 1, blue: 1, alpha: 1), for: .normal)
postButton.frame = CGRect(x: 0, y: 0, width: 80, height: 40)
postButton.layer.cornerRadius = 4
postButton.addTarget(self, action: #selector(postButtonTapped), for: .touchUpInside)
let postButtonItem = UIBarButtonItem(customView: postButton)
navigationItem.rightBarButtonItem = postButtonItem

// 設定標題
navigationItem.title = "建立貼文"
let attributes: [NSAttributedString.Key: Any] = [
.foregroundColor: UIColor(red: 5/255, green: 5/255, blue: 5/255, alpha: 1),
.font: UIFont.systemFont(ofSize: 18)
]
navigationController?.navigationBar.titleTextAttributes = attributes

navigationController?.navigationBar.barTintColor = UIColor(red: 247/255, green: 248/255, blue: 249/255, alpha: 1)

}

新增照片按鈕

新增照片

PHPickerViewControllerDelegate

import PhotosUI

extension PostViewController: PHPickerViewControllerDelegate {
func picker(_ picker: PHPickerViewController, didFinishPicking results: [PHPickerResult]) {
dismiss(animated: true, completion: nil)

let itemProvider = results.first?.itemProvider

if let itemProvider = itemProvider, itemProvider.canLoadObject(ofClass: UIImage.self) {
itemProvider.loadObject(ofClass: UIImage.self) { [weak self] (image, error) in
DispatchQueue.main.async {
if let image = image as? UIImage {
self?.postImageView.image = image
// 變更發布按鈕樣式
self?.postButton.backgroundColor = UIColor(red: 23/255, green: 119/255, blue: 241/255, alpha: 1)
}
}
}
}
}
}


// 按鈕選擇照片
@IBAction func selectphoto(_ sender: Any) {
var configuration = PHPickerConfiguration()
configuration.filter = .images
let picker = PHPickerViewController(configuration: configuration)
picker.delegate = self
present(picker, animated: true)
}

新增文字內容

透過UITextViewDelegate 使用TextView function

import UIKit

extension PostViewController: UITextViewDelegate {

func textViewDidChange(_ textView: UITextView) {
// 發布按鈕樣式 隨著內文變更
if textView.text.isEmpty {
postButton.backgroundColor = UIColor(red: 228/255, green: 229/255, blue: 234/255, alpha: 1)
} else {
postButton.backgroundColor = UIColor(red: 23/255, green: 119/255, blue: 241/255, alpha: 1)
}
}

func textViewDidBeginEditing(_ textView: UITextView) {
// 開始打字時 文字欄變空白
textView.text = ""
textView.textColor = UIColor(red: 5/255, green: 5/255, blue: 5/255, alpha: 1)
}
}

貼文隱私狀態按鈕 Pop Up Button

Pop Up Button貼文隱私選單

點選 storyboard從右鍵選單點選 Open As > Source Code,顯示 storyboard xml

object id

定義選單功能

@objc func selectPublic() {
stateButton.setImage(UIImage(systemName: "globe.asia.australia.fill"), for: .normal)
isPostPublic = true
}

@objc func selectPrivate() {
stateButton.setImage(UIImage(systemName: "person.2.fill"), for: .normal)
isPostPublic = false
}

action 的 selector 欄位設定上面定義的 function ,destination 欄位設定 controller 的 object id 3HZ-Xi-a6P,id 欄位設定一個隨機不重覆的 id

參考如下

發布貼文&返回功能

po文
@objc func postButtonTapped() {

// 沒有文字或圖片 無法發布
guard !(postTextView.text.isEmpty || postTextView.text == "在想些什麼?") || postImageView.image != nil else {
return
}

// 儲存圖片至app資料夾 並獲取圖片路徑
if let postImage = postImageView.image,
let imageData = postImage.pngData(),
let documentsDirectory = FileManager.default.urls(for: .documentDirectory, in: .userDomainMask).first {

let fileName = UUID().uuidString
let fileURL = documentsDirectory.appendingPathComponent(fileName)

do {
try imageData.write(to: fileURL)
} catch {
print("Error saving image: \(error)")
}

// 沒有輸入文字 只儲存圖片
let text = postTextView.text.isEmpty || postTextView.text == "在想些什麼?" ? "" : postTextView.text
let postInfo = PostInfo(userName: "Lou", profilePictureName: "userphoto", timestamp: Date(), isPublic: isPostPublic, text: text, imageName: fileName)
postArray.append(postInfo)
} else {
// 無圖片 只儲存文字
let text = postTextView.text.isEmpty || postTextView.text == "在想些什麼?" ? "" : postTextView.text

let postInfo = PostInfo(userName: "Lou", profilePictureName: "userphoto", timestamp: Date(), isPublic: isPostPublic, text: text, imageName: nil)
postArray.append(postInfo)
}

self.navigationController?.popViewController(animated: true) //發布即跳出視窗
}



@objc func closeButtonTapped() {
// 返回上一頁
self.navigationController?.popViewController(animated: true)
}

--

--