使用SwiftUI客製化Alert

更新 發佈閱讀 14 分鐘

UIAlertController應該是大家都用過吧,最簡單的用法就是創造一個UIAlertController設定標題、內容跟按鈕

UIAlertConrtoller

UIAlertConrtoller



let alert = UIAlertController(title: "這是標題", message: "這是內容這是內容這是內容這是內容這是內容這是內容這是內容這是內容這是內容這是內容這是內容這是內容這是內容這是內容這是內容這是內容這是內容這是內容這是內容這是內容這是內容這是內容這是內容這是內容這是內容這是內容這是內容這是內容", preferredStyle: .alert)
let action = UIAlertAction(title: "OK", style: .default)
alert.addAction(action)
self.present(alert, animated: true)


但是今天有一個需求要客製化字體大小、內嵌連接在裡面🫨 同時要保留原生Alert高度隨著公告字數增長的特性,增長到最大範圍後才提供scroll操作

原生Alert高度會隨字數增長

原生Alert高度會隨字數增長


使用SwiftUI客製

覺得客製化的需求實在很難改,官方也講了UIAlertController不接受繼承

The UIAlertController class is intended to be used as-is and doesn’t support subclassing. The view hierarchy for this class is private and must not be modified.

直接用SwiftUI重刻一個

基本UI

基本UI


這邊為了方便看Alert都先把背景設成粉紅色
先做了標題、內容、連結、分隔線跟按鈕,並且固定寬度,把高度設在一定範圍之間

struct BasicAlert: View {
    let title: String
    let message: String
    let link: String?
    let buttonTitle: String
let action: (()->Void)?
    var body: some View {
        VStack {
            VStack {
                // 標題
                Text(title)
                    .font(.system(size: 20, weight: .bold))
                // 內容
                Text(message)
                    .font(.system(size: 18))
                // 連結
                if let link, let url = URL(string: link) {
                    Link("點擊這裡前往網站", destination: url)
                        .foregroundColor(.blue)
                        .frame(maxWidth: .infinity, alignment: .leading)
                        .padding(.leading, 9)
                }
            }.padding()
            // 一條分隔線
            Divider()
            // 按鈕
            createButton(title: buttonTitle).frame(height: 40.0)
        }
        .background(Color.pink)
        .cornerRadius(15.0)
        .frame(width: 270.0) // 固定寬度
        .frame(minHeight: 161, maxHeight: 603) // 設定高度範圍
    }

}

但是測試在高度超出範圍後,文字並沒有變成可以捲動,加上ScrollView看看

VStack {
  ScrollView { // 新增scrollView
       VStack {
        // 標題
        Text(title)
         .font(.system(size: 20, weight: .bold))

// ....​


加上scrollView

加上scrollView


長的內容可以捲動了,但是scrollView的高度卻固定在最高限制🫨

去查SwiftUI的scrollView要如何設定捲動範圍,查到了fixedSize這個屬性

這邊官方範例就解釋得很清楚,會幫你把元件調整成適合的大小
在scrollView加上這個屬性,並固定最高高度為500

ScrollView {
   // ....
}
.frame(maxHeight: 500)
.fixedSize(horizontal: false, vertical: true)
//...


完美啦

完美啦

完整code

struct BasicAlert: View {
    let title: String
    let message: String
    let link: String?
    let buttonTitle: String
let action: (()->Void)?
    var body: some View {
        VStack {
            ScrollView {
                VStack {
                    // 標題
                    Text(title)
                        .font(.system(size: 20, weight: .bold))

                    // 內容
                    Text(message)
                        .font(.system(size: 18))
                    // 連結
                    if let link, let url = URL(string: link) {
                        Link("點擊這裡前往網站", destination: url)
                            .foregroundColor(.blue)
                            .frame(maxWidth: .infinity, alignment: .leading)
                            .padding(.leading, 9)

                    }
                }.padding()

            }
            .frame(maxHeight: 500)
            .fixedSize(horizontal: false, vertical: true)

        
            // 一條分隔線
            Divider()

            // 按鈕
            createButton(title: buttonTitle)

        }
        .background(Color.white)
        .cornerRadius(15.0)
        .frame(width: 270.0) // 固定寬度

    }

}

extension BasicAlert {
    func createButton(title: String) -> some View {
        Button {
action?()
        } label: {
            Text(title)
                .frame(height: 40.0)
                .frame(minWidth: 0, maxWidth: .infinity, alignment: .center)
        }

    }

}

背景透明黑底

這邊有很多種做法,因為我的專案大部分都是UIKit,所以我是用UIHostingController轉接再放到UIWindow上

class BasicAlertVC: UIViewController {
    let alertTitle: String
    let message: String
    let buttonTitle: String
    let link: String?
let action: (()->Void)?
    lazy var basicAlertView = makeBasicAlertView()

    init(title: String, message: String, link: String?, buttonTitle: String, action: (()->Void)?) {
        self.alertTitle = title
        self.message = message
        self.link = link
        self.buttonTitle = buttonTitle
self.action = action
        super.init(nibName: nil, bundle: nil)

    }

    required init?(coder: NSCoder) {
        fatalError("init(coder:) has not been implemented")
    }
    override func viewDidLoad() {
        super.viewDidLoad()
        addChild(basicAlertView)

        basicAlertView.view.backgroundColor = .clear
        basicAlertView.view.translatesAutoresizingMaskIntoConstraints = false
        view.addSubview(basicAlertView.view)
        basicAlertView.didMove(toParent: self)

        NSLayoutConstraint.activate([
            basicAlertView.view.widthAnchor.constraint(equalTo: view.widthAnchor),
            basicAlertView.view.topAnchor.constraint(equalTo: view.topAnchor),
            basicAlertView.view.centerXAnchor.constraint(equalTo: view.centerXAnchor),
            basicAlertView.view.bottomAnchor.constraint(equalTo: view.bottomAnchor)
        ])

    }

    private func makeBasicAlertView() -> UIHostingController<BasicAlert> {
        let basicAlert = BasicAlert(title: alertTitle, message: message, link: link, buttonTitle: buttonTitle, action: action)
        let controller = UIHostingController(rootView: basicAlert)
        return controller
    }

}

加到window上

let alertWindow = UIWindow(frame: UIScreen.main.bounds)
alertWindow.backgroundColor = UIColor(white: 0, alpha: 0.6)
alertWindow.windowLevel = .alert
alertWindow.rootViewController = BasicAlertVC(title: title, message: message, link: link, buttonTitle: buttonTitle, action: action)
alertWindow.makeKeyAndVisible()
alertWindow.isHidden = false
完整Alert

完整Alert




留言
avatar-img
Michelle Chen的沙龍
9會員
34內容數
紀錄iOS開發上遇到的問題或是一些流程筆記。主要都是Swift。
Michelle Chen的沙龍的其他內容
2024/09/06
本文介紹了使用KeyboardLayoutGuide的方法,以及在不同iOS版本和設備上遇到的佈局問題。透過調整TextView的底部對齊方式,成功解決了在模擬器和真實設備上出現的錯誤,提供了有用的建議給開發者。本文還探討了為何在iOS15與Xib的組合使用中會出現問題,以及解決方案。
Thumbnail
2024/09/06
本文介紹了使用KeyboardLayoutGuide的方法,以及在不同iOS版本和設備上遇到的佈局問題。透過調整TextView的底部對齊方式,成功解決了在模擬器和真實設備上出現的錯誤,提供了有用的建議給開發者。本文還探討了為何在iOS15與Xib的組合使用中會出現問題,以及解決方案。
Thumbnail
2024/08/07
使用者回報的超級奇怪線上問題,用數字鍵盤(NumberPad)更改欄位時,送出後尾數都會消失。例如:30 ⭢ 3,52 ⭢ 5。 尋尋覓覓了兩天終於被我找到這篇,apple的奇葩的bug 重現條件 iOS17 手機設定是繁體中文語系 前一個用過的鍵盤是Cangjie倉頡 or Suchen
2024/08/07
使用者回報的超級奇怪線上問題,用數字鍵盤(NumberPad)更改欄位時,送出後尾數都會消失。例如:30 ⭢ 3,52 ⭢ 5。 尋尋覓覓了兩天終於被我找到這篇,apple的奇葩的bug 重現條件 iOS17 手機設定是繁體中文語系 前一個用過的鍵盤是Cangjie倉頡 or Suchen
2024/07/02
本文介紹瞭如何在SwiftUI中調整元件的對齊方式,包括置中、向左/向右/向上/向下對齊的方法。透過調整HStack、VStack以及frame的maxWidth、maxHeight和alignment屬性,可以達到想要的對齊效果。
Thumbnail
2024/07/02
本文介紹瞭如何在SwiftUI中調整元件的對齊方式,包括置中、向左/向右/向上/向下對齊的方法。透過調整HStack、VStack以及frame的maxWidth、maxHeight和alignment屬性,可以達到想要的對齊效果。
Thumbnail
看更多
你可能也想看
Thumbnail
這是一場修復文化與重建精神的儀式,觀眾不需要完全看懂《遊林驚夢:巧遇Hagay》,但你能感受心與土地團聚的渴望,也不急著在此處釐清或定義什麼,但你的在場感受,就是一條線索,關於如何找著自己的路徑、自己的聲音。
Thumbnail
這是一場修復文化與重建精神的儀式,觀眾不需要完全看懂《遊林驚夢:巧遇Hagay》,但你能感受心與土地團聚的渴望,也不急著在此處釐清或定義什麼,但你的在場感受,就是一條線索,關於如何找著自己的路徑、自己的聲音。
Thumbnail
一般用戶不建議升級至 iOS 18 測試版,因為這個版本可能存在大量Bug和不穩定因素,導致如 LINE 功能錯誤或銀行 App 閃退等問題。Apple 釋出的 iOS 18 Beta 測試版本主要供開發者使用,並非穩定的正式版。建議等待正式版於9月推出後再考慮更新。
Thumbnail
一般用戶不建議升級至 iOS 18 測試版,因為這個版本可能存在大量Bug和不穩定因素,導致如 LINE 功能錯誤或銀行 App 閃退等問題。Apple 釋出的 iOS 18 Beta 測試版本主要供開發者使用,並非穩定的正式版。建議等待正式版於9月推出後再考慮更新。
Thumbnail
《轉轉生》(Re:INCARNATION)為奈及利亞編舞家庫德斯.奧尼奎庫與 Q 舞團創作的當代舞蹈作品,結合拉各斯街頭節奏、Afrobeat/Afrobeats、以及約魯巴宇宙觀的非線性時間,建構出關於輪迴的「誕生—死亡—重生」儀式結構。本文將從約魯巴哲學概念出發,解析其去殖民的身體政治。
Thumbnail
《轉轉生》(Re:INCARNATION)為奈及利亞編舞家庫德斯.奧尼奎庫與 Q 舞團創作的當代舞蹈作品,結合拉各斯街頭節奏、Afrobeat/Afrobeats、以及約魯巴宇宙觀的非線性時間,建構出關於輪迴的「誕生—死亡—重生」儀式結構。本文將從約魯巴哲學概念出發,解析其去殖民的身體政治。
Thumbnail
iPhone 最新作業系統 iOS 18 控制中心大更新,預設有常用功能、音樂播放器、連線控制三個頁面,並允許使用者自訂頁面,可以直接在控制中心管理所需的功能、調整位置和選擇尺寸。
Thumbnail
iPhone 最新作業系統 iOS 18 控制中心大更新,預設有常用功能、音樂播放器、連線控制三個頁面,並允許使用者自訂頁面,可以直接在控制中心管理所需的功能、調整位置和選擇尺寸。
Thumbnail
修復重要錯誤及安全性|Apple建議即update Apple稱新版本包含「重要錯誤修復和安全性更新」,適用於從 iPhone XS 及更新型號以上所有 iPhone,Apple 建議所有 iPhone 用戶安裝此最新軟體修補程式。 用戶只需要到「設定」點選的「常用」,然後選擇「軟體更新」,即可
Thumbnail
修復重要錯誤及安全性|Apple建議即update Apple稱新版本包含「重要錯誤修復和安全性更新」,適用於從 iPhone XS 及更新型號以上所有 iPhone,Apple 建議所有 iPhone 用戶安裝此最新軟體修補程式。 用戶只需要到「設定」點選的「常用」,然後選擇「軟體更新」,即可
Thumbnail
本文介紹如何使用UINavigationBarAppearance調整四種場景下的UI外觀,並探討客製化返回鍵UI又保留返回手勢的做法,可以有效地客製化NavigationBar的外觀,並避免一些NG作法。
Thumbnail
本文介紹如何使用UINavigationBarAppearance調整四種場景下的UI外觀,並探討客製化返回鍵UI又保留返回手勢的做法,可以有效地客製化NavigationBar的外觀,並避免一些NG作法。
Thumbnail
10個今年WWDC,蘋果把AI功能導入IOS之後的新功能
Thumbnail
10個今年WWDC,蘋果把AI功能導入IOS之後的新功能
Thumbnail
iOS 17.5 正式版上架更新日預測| iPhone 早前在4月初發表了開發者測試版 iOS 17.5 Beta , 為手機帶來很多新功能及細節改良, 那一般用戶幾時才可以正式用到 iOS 17.5 ?當中又有甚麼吸引、實用新功能呢? 「天氣」桌面工具 iOS 17.5 微調了桌
Thumbnail
iOS 17.5 正式版上架更新日預測| iPhone 早前在4月初發表了開發者測試版 iOS 17.5 Beta , 為手機帶來很多新功能及細節改良, 那一般用戶幾時才可以正式用到 iOS 17.5 ?當中又有甚麼吸引、實用新功能呢? 「天氣」桌面工具 iOS 17.5 微調了桌
Thumbnail
這篇文章探討瞭如何在iOS應用程式中客製化Alert,包括改變字體大小、內嵌連結以及讓Alert的高度隨著字數增長並提供scroll操作。同時使用SwiftUI進行客製化,並介紹瞭解決高度超出範圍後文字捲動與scrollView固定高度的方法。
Thumbnail
這篇文章探討瞭如何在iOS應用程式中客製化Alert,包括改變字體大小、內嵌連結以及讓Alert的高度隨著字數增長並提供scroll操作。同時使用SwiftUI進行客製化,並介紹瞭解決高度超出範圍後文字捲動與scrollView固定高度的方法。
Thumbnail
本文分析導演巴里・柯斯基(Barrie Kosky)如何運用極簡的舞臺配置,將布萊希特(Bertolt Brecht)的「疏離效果」轉化為視覺奇觀與黑色幽默,探討《三便士歌劇》在當代劇場中的新詮釋,並藉由舞臺、燈光、服裝、音樂等多方面,分析該作如何在保留批判核心的同時,觸及觀眾的觀看位置與人性幽微。
Thumbnail
本文分析導演巴里・柯斯基(Barrie Kosky)如何運用極簡的舞臺配置,將布萊希特(Bertolt Brecht)的「疏離效果」轉化為視覺奇觀與黑色幽默,探討《三便士歌劇》在當代劇場中的新詮釋,並藉由舞臺、燈光、服裝、音樂等多方面,分析該作如何在保留批判核心的同時,觸及觀眾的觀看位置與人性幽微。
Thumbnail
5 月將於臺北表演藝術中心映演的「2026 北藝嚴選」《海妲・蓋柏樂》,由臺灣劇團「晃晃跨幅町」製作,本文將以從舞台符號、聲音與表演調度切入,討論海妲・蓋柏樂在父權社會結構下的困境,並結合榮格心理學與馮.法蘭茲對「阿尼姆斯」與「永恆少年」原型的分析,理解女人何以走向精神性的操控、毀滅與死亡。
Thumbnail
5 月將於臺北表演藝術中心映演的「2026 北藝嚴選」《海妲・蓋柏樂》,由臺灣劇團「晃晃跨幅町」製作,本文將以從舞台符號、聲音與表演調度切入,討論海妲・蓋柏樂在父權社會結構下的困境,並結合榮格心理學與馮.法蘭茲對「阿尼姆斯」與「永恆少年」原型的分析,理解女人何以走向精神性的操控、毀滅與死亡。
Thumbnail
這篇文章教你如何製作側邊欄,包括準備工作、HTML和CSS的部分,還有一些互動效果。文章涵蓋了連結、圖片、超連結、大小、顏色、排版、flex和滑鼠互動等內容。
Thumbnail
這篇文章教你如何製作側邊欄,包括準備工作、HTML和CSS的部分,還有一些互動效果。文章涵蓋了連結、圖片、超連結、大小、顏色、排版、flex和滑鼠互動等內容。
追蹤感興趣的內容從 Google News 追蹤更多 vocus 的最新精選內容追蹤 Google News