{"id":17281316,"url":"https://github.com/xaoxuu/prohud","last_synced_at":"2025-04-10T04:05:40.030Z","repository":{"id":50324197,"uuid":"198419857","full_name":"xaoxuu/ProHUD","owner":"xaoxuu","description":"适用于任何定制化UI的专业级HUD容器（Toast、Alert、Sheet、Capsule四件套）","archived":false,"fork":false,"pushed_at":"2024-05-30T03:10:18.000Z","size":5750,"stargazers_count":99,"open_issues_count":1,"forks_count":8,"subscribers_count":1,"default_branch":"main","last_synced_at":"2025-04-10T04:05:29.111Z","etag":null,"topics":["alert","hud","sheet","toast"],"latest_commit_sha":null,"homepage":"https://xaoxuu.com/wiki/prohud","language":"Swift","has_issues":true,"has_wiki":null,"has_pages":null,"mirror_url":null,"source_name":null,"license":"mit","status":null,"scm":"git","pull_requests_enabled":true,"icon_url":"https://github.com/xaoxuu.png","metadata":{"files":{"readme":"README.md","changelog":null,"contributing":null,"funding":null,"license":"LICENSE","code_of_conduct":null,"threat_model":null,"audit":null,"citation":null,"codeowners":null,"security":null,"support":null,"governance":null,"roadmap":null,"authors":null,"dei":null,"publiccode":null,"codemeta":null}},"created_at":"2019-07-23T11:49:30.000Z","updated_at":"2025-04-09T07:50:24.000Z","dependencies_parsed_at":"2024-10-30T23:13:51.375Z","dependency_job_id":null,"html_url":"https://github.com/xaoxuu/ProHUD","commit_stats":{"total_commits":86,"total_committers":3,"mean_commits":"28.666666666666668","dds":"0.15116279069767447","last_synced_commit":"238ffa1055160224102a33ed4e9802a8ff65d71c"},"previous_names":[],"tags_count":15,"template":false,"template_full_name":null,"repository_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/xaoxuu%2FProHUD","tags_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/xaoxuu%2FProHUD/tags","releases_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/xaoxuu%2FProHUD/releases","manifests_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/xaoxuu%2FProHUD/manifests","owner_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/owners/xaoxuu","download_url":"https://codeload.github.com/xaoxuu/ProHUD/tar.gz/refs/heads/main","host":{"name":"GitHub","url":"https://github.com","kind":"github","repositories_count":248154981,"owners_count":21056543,"icon_url":"https://github.com/github.png","version":null,"created_at":"2022-05-30T11:31:42.601Z","updated_at":"2022-07-04T15:15:14.044Z","host_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub","repositories_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories","repository_names_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repository_names","owners_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/owners"}},"keywords":["alert","hud","sheet","toast"],"created_at":"2024-10-15T09:45:31.538Z","updated_at":"2025-04-10T04:05:40.003Z","avatar_url":"https://github.com/xaoxuu.png","language":"Swift","funding_links":[],"categories":[],"sub_categories":[],"readme":"# ProHUD\n\n\u003cbr\u003e\n\n**一个易于上手又完全可定制化的专业HUD库**（内含Toast、Alert、Sheet三件套）\n\n文档：\u003chttps://xaoxuu.com/wiki/prohud/\u003e\n\n\u003cbr\u003e\n\n\n\n## 特性\n\n**易于上手**\n\n- 用极少的参数就可以创建并显示一个实例。\n- 用相似的接口调用**Toast**、**Alert**、**Sheet**。\n\n**功能丰富**\n\n- 具有完善的实例管理（多实例共存方案、查找与更新方案）。\n- 可对已发布的实例进行数据更新。\n- 横竖屏和iPad布局优化。\n\n**完全可定制化**\n\n- 支持只使用ProHUD的容器，而容器内容可完全自定义。\n- 程序初始化时配置自定义UI样式，调用的时候只需要关注数据。\n- 易于扩展，可以很方便的添加任意控件。\n\n\n## Toast（顶部通知横幅）\n\n通知条控件，用于非阻塞性事件通知。显示效果如同原生通知，默认会自动消失，可以支持手势移除，有多条通知可以平铺并列显示。\n\n### 方式一：传入ViewModel生成实例\n\n这种方式创建的实例在调用`push()`之后才会显示出来，结构为： \n\n```swift\nlet 实例 = Toast(视图模型)\n实例.push()\n```\n\n也可以连在一起写，例如：\n\n```swift\nToast(.message(\"要显示的消息内容\")).push()\n```\n\n#### 如何创建ViewModel\n\nViewModel有多种创建方式，也可以自行扩展更多常用场景，例如：\n\n```swift\n// 纯文本\nlet vm = .message(\"要显示的消息内容\")\n// 持续2s的文本\nlet vm = .message(\"要显示的消息内容\").duration(2)\n// 标题 + 正文\nlet vm = .title(\"标题\").message(\"正文\")\n```\n\n内置了几种常见的场景扩展，例如正在加载的场景：\n```swift\nstatic var loading: ViewModel {\n    let obj = ViewModel(icon: UIImage(inProHUD: \"prohud.windmill\"))\n    obj.rotation = .init(repeatCount: .infinity)\n    return obj\n}\nstatic func loading(_ seconds: TimeInterval) -\u003e ViewModel {\n    let obj = ViewModel(icon: UIImage(inProHUD: \"prohud.windmill\"), duration: seconds)\n    obj.rotation = .init(repeatCount: .infinity)\n    return obj\n}\n```\n\n使用的时候可以：\n```swift\n// 无限持续时间\nlet vm = .loading\n// 无限持续时间, 带有文字\nlet vm = .loading.message(\"正在加载\")\n// 持续10s\nlet vm = .loading(10)\n// 持续10s, 带有文字\nlet vm = .loading(10).message(\"正在加载\")\n```\n\n### 方式二：以闭包形式创建并显示实例\n\n对于复杂实例，建议以这种方式使用，例如给实例增加事件响应：\n\n```swift\nlet title = \"您收到了一条消息\"\nlet message = \"点击通知横幅任意处即可回复\"\nToast { toast in\n    toast.vm = .msg.title(title).message(message)\n    toast.onTapped { toast in\n        toast.pop()\n        Alert(.success(1).message(\"操作成功\")).push()\n    }\n}\n```\n\n也可以增加多个按钮，横向平铺，在这个例子中，左侧图标位置自定义为头像：\n```swift\nlet title = \"您收到了一条好友申请\"\nlet message = \"丹妮莉丝·坦格利安申请添加您为好友，是否同意？\"\nToast(.title(title).message(message)) { toast in\n    toast.isRemovable = false\n    toast.vm.icon = UIImage(named: \"avatar\")\n    toast.imageView.layer.masksToBounds = true\n    toast.imageView.layer.cornerRadius = toast.config.iconSize.width / 2\n    toast.add(action: \"拒绝\", style: .destructive) { toast in\n        // 按钮点击事件回调\n        ...\n    }\n    toast.add(action: \"同意\") { toast in\n        // 按钮点击事件回调\n        toast.pop()\n        Alert(.success(1).message(\"Good choice!\")).push()\n    }\n}\n```\n\n### 如果存在就更新，不存在就创建新的实例\n\n例如弹出一个loading，有多个地方需要更新这个loading，为了避免重复弹出多个实例，可以使用 `lazyPush` 方法：\n\n```swift\nToast.lazyPush(identifier: \"loading\") { toast in\n    toast.vm = .loading.title(\"正在加载\\(i)\").message(\"这条消息不会重复显示多条\")\n}\n```\n\n### 如果存在就更新，不存在就忽略指令\n\n如果要对一个已经存在的实例进行更新，假如实例已经结束显示了，那就不进行任何操作，这时候可以使用 `find` 方法：\n\n```swift\nToast.find(identifier: \"loading\") { toast in\n    toast.vm = .success(2).message(\"加载成功\")\n}\n```\n\n## Alert（页面中心弹窗）\n\n弹窗控件，用于强阻塞性交互，用户必须做出选择或者等待结果才能进入下一步，当多个实例出现时，会以堆叠的形式显示，新的实例会在覆盖旧的实例上层。\n\nAlert和Toast一样有两种创建方法，不再赘述。\n\n### 修改实例内容\n\n在实例弹出后仍然可以修改实例内容：\n\n```swift\n// 持有实例的情况下：\nAlert(.note) { alert in\n    alert.vm.message = \"可以动态增加、删除、更新文字\"\n    alert.add(action: \"增加标题\") { alert in\n        alert.vm.title = \"这是标题\"\n        alert.reloadTextStack()\n    }\n    alert.add(action: \"增加正文\") { alert in\n        alert.vm.message = \"可以动态增加、删除、更新文字\"\n        alert.reloadTextStack()\n    }\n    alert.add(action: \"删除标题\", style: .destructive) { alert in\n        alert.vm.title = nil\n        alert.reloadTextStack()\n    }\n    alert.add(action: \"删除正文\", style: .destructive) { alert in\n        alert.vm.message = nil\n        alert.reloadTextStack()\n    }\n    alert.add(action: \"取消\", style: .gray)\n}\n// 未持有实例时，可通过 identifier 查找并更新：\nAlert.find(identifier: \"my-alert\") { alert in\n    alert.vm.title = \"这是标题\"\n    alert.reloadTextStack()\n}\n```\n\n### 按钮的增删改查\n\n```swift\nAlert(.note) { alert in\n    alert.vm.message = \"可以动态增加、删除按钮\"\n    alert.add(action: \"在底部增加按钮\", style: .filled(color: .systemGreen)) { alert in\n        alert.add(action: \"哈哈1\", identifier: \"haha1\")\n    }\n    alert.add(action: \"在当前按钮下方增加\", style: .filled(color: .systemIndigo), identifier: \"add\") { alert in\n        alert.insert(action: .init(identifier: \"haha2\", style: .light(color: .systemOrange), title: \"哈哈2\", handler: nil), after: \"add\")\n    }\n    alert.add(action: \"修改当前按钮文字\", identifier: \"edit\") { alert in\n        alert.update(action: \"已修改\", for: \"edit\")\n    }\n    alert.add(action: \"删除「哈哈1」\", style: .destructive) { alert in\n        alert.remove(actions: .identifiers(\"haha1\"))\n    }\n    alert.add(action: \"删除「哈哈1」和「哈哈2」\", style: .destructive) { alert in\n        alert.remove(actions: .identifiers(\"haha1\", \"haha2\"))\n    }\n    alert.add(action: \"删除全部按钮\", style: .destructive) { alert in\n        alert.remove(actions: .all)\n        DispatchQueue.main.asyncAfter(deadline: .now() + 2) {\n            alert.pop()\n        }\n    }\n    alert.add(action: \"取消\", style: .gray)\n}\n```\n\n### 添加自定义控件\n\n```swift\nAlert { alert in\n    alert.vm.title = \"自定义控件\"\n    // 图片\n    let imgv = UIImageView(image: UIImage(named: \"landscape\"))\n    imgv.contentMode = .scaleAspectFill\n    imgv.clipsToBounds = true\n    imgv.layer.cornerRadiusWithContinuous = 12\n    alert.add(subview: imgv).snp.makeConstraints { make in\n        make.height.equalTo(120)\n    }\n    // seg\n    let seg = UISegmentedControl(items: [\"开发\", \"测试\", \"预发\", \"生产\"])\n    seg.selectedSegmentIndex = 0\n    alert.add(subview: seg).snp.makeConstraints { make in\n        make.height.equalTo(40)\n        make.width.equalTo(400)\n    }\n    // slider\n    let slider = UISlider()\n    slider.minimumValue = 0\n    slider.maximumValue = 100\n    slider.value = 50\n    alert.add(subview: slider)\n    alert.add(spacing: 24)\n    alert.add(action: \"取消\", style: .gray)\n}\n```\n\n\n## Sheet（底部操作表）\n\n操作表控件，用于弱阻塞性交互。显示区域为从屏幕底部向上弹出的新图层，可以放置丰富的内容，自由度较高。\n\n### 布局\n\n操作表控件空间较大，可以放置更多的文字、按钮和其它任何控件。\n\n```swift\nSheet { sheet in\n    sheet.add(title: \"ProHUD\")\n    sheet.add(subTitle: \"什么是操作表控件\")\n    sheet.add(message: \"操作表控件，用于弱阻塞性交互。显示区域为从屏幕底部向上弹出的新图层，可以放置丰富的内容，自由度较高。\")\n    sheet.add(spacing: 24)\n    sheet.add(action: \"确认\", style: .destructive) { sheet in\n        Alert(.confirm) { alert in\n            alert.vm.title = \"处理点击事件\"\n            alert.add(action: \"我知道了\")\n        }\n    }\n    sheet.add(action: \"取消\", style: .gray)\n}\n```\n\n同样支持添加任意其它视图：\n\n```swift\nSheet { sheet in\n    sheet.add(title: \"ProHUD\")\n    // 图片\n    let imgv = UIImageView(image: UIImage(named: \"landscape\"))\n    imgv.contentMode = .scaleAspectFill\n    imgv.clipsToBounds = true\n    imgv.layer.cornerRadiusWithContinuous = 16\n    sheet.add(subview: imgv).snp.makeConstraints { make in\n        make.height.equalTo(200)\n    }\n    // seg\n    let seg = UISegmentedControl(items: [\"开发\", \"测试\", \"预发\", \"生产\"])\n    seg.selectedSegmentIndex = 0\n    sheet.add(subview: seg).snp.makeConstraints { make in\n        make.height.equalTo(40)\n        make.width.equalTo(400)\n    }\n    // slider\n    let slider = UISlider()\n    slider.minimumValue = 0\n    slider.maximumValue = 100\n    slider.value = 50\n    sheet.add(subview: slider).snp.makeConstraints { make in\n        make.height.equalTo(50)\n    }\n}\n```\n\n### 拦截背景点击事件\n\n有时候如果不希望点击背景直接`pop`掉，可以实现 `onTappedBackground` 以拦截背景点击事件\n\n```swift\nSheet { sheet in\n    sheet.add(title: \"ProHUD\")\n    sheet.add(message: \"点击背景将不会dismiss，必须在下方做出选择才能关掉\")\n    sheet.add(spacing: 24)\n    sheet.add(action: \"确认\")\n    sheet.add(action: \"取消\", style: .gray)\n} onTappedBackground: { sheet in\n    print(\"点击了背景\")\n    Toast.lazyPush(identifier: \"alert\") { toast in\n        toast.vm = .error\n        toast.vm.title = \"点击了背景\"\n        toast.vm.message = \"点击背景将不会dismiss，必须在下方做出选择才能关掉\"\n        toast.vm.duration = 2\n    }\n}\n```\n\n## 个性化设置\n\n### 完全自定义布局\n\nProHUD支持完全自定义布局，即将整个容器交给使用者来布局，在 `Alert.Configuration.shared` 中配置了 `reloadData` 规则之后，实例在显示前以及更新内容时都会进入此函数，执行自定义的 `reloadData` 代码。也可以指定部分 `identifier` 走自定义布局代码，其余走内置布局代码，例如：\n\n```swift\nAlert.Configuration.shared { config in\n    config.reloadData { vc in\n        if vc.identifier == \"custom\" {\n            return true\n        }\n        return false\n    }\n}\nAlert { alert in\n    alert.identifier = \"custom\"\n    alert.contentView.backgroundColor = .systemYellow\n    alert.view.addSubview(alert.contentView)\n    alert.contentView.layer.cornerRadiusWithContinuous = 32\n    alert.contentView.snp.makeConstraints { make in\n        make.width.equalTo(UIScreen.main.bounds.width - 100)\n        make.height.equalTo(UIScreen.main.bounds.height - 200)\n        make.center.equalToSuperview()\n    }\n    DispatchQueue.main.asyncAfter(deadline: .now() + 2) {\n        alert.pop()\n    }\n}\n```\n\n### 个性化选项\n\nProHUD内置的布局也支持丰富的个性化参数，例如：\n\n- 标题、正文、按钮字体字号\n- 背景颜色、模糊效果\n- 文字颜色\n- 图标大小\n- 卡片圆角\n- Sheet组件卡片距离屏幕的边距\n\n具体请探索 `ProHUD.Configuration` 类代码。\n\n\n## 文档\n\n\u003chttps://xaoxuu.com/wiki/prohud/\u003e\n","project_url":"https://awesome.ecosyste.ms/api/v1/projects/github.com%2Fxaoxuu%2Fprohud","html_url":"https://awesome.ecosyste.ms/projects/github.com%2Fxaoxuu%2Fprohud","lists_url":"https://awesome.ecosyste.ms/api/v1/projects/github.com%2Fxaoxuu%2Fprohud/lists"}