You need to enable JavaScript to run this app.
优惠活动
大模型
产品
解决方案
定价
更多

SwiftUI中如何缩小material-showcase-ios的展示视图尺寸?

解决material-showcase-ios展示视图过大及叠加问题

问题背景

登录后需要首次展示多步骤引导弹窗,使用material-showcase-ios框架(版本~>0.8.0)时遇到两个问题:

  • 展示视图整体尺寸过大,不符合设计需求
  • 多个引导弹窗同时叠加显示,无法按顺序展示

解决方案

1. 缩小展示视图尺寸

通过配置MaterialShowcase的核心属性,直接控制弹窗的视觉大小:

修改ShowcaseHost中的showcase配置代码

在showShowcase方法里,添加以下属性配置:

// 配置showcase部分
let showcase = MaterialShowcase()
showcase.setTargetView(view: targetView)
showcase.primaryText = showcaseItem.primaryText
showcase.secondaryText = showcaseItem.secondaryText
showcase.backgroundPromptColor = showcaseItem.backgroundColor
showcase.primaryTextColor = showcaseItem.textColor
showcase.secondaryTextColor = showcaseItem.textColor
showcase.targetHolderColor = UIColor.white

// --- 添加以下控制尺寸的代码 ---
// 缩小目标高亮区域的半径(匹配你设置的50x50 targetView,设为25刚好覆盖)
showcase.targetHolderRadius = 25
// 缩小提示背景的内边距,减少弹窗整体大小
showcase.backgroundPromptInsets = UIEdgeInsets(top: 12, left: 12, bottom: 12, right: 12)
// 调整文本字体大小,避免长文本撑大弹窗
showcase.primaryTextFont = UIFont.systemFont(ofSize: 16, weight: .semibold)
showcase.secondaryTextFont = UIFont.systemFont(ofSize: 13)
// 可选:限制提示文本的最大宽度,防止弹窗过宽
showcase.maxWidth = UIScreen.main.bounds.width * 0.75
// --- 结束添加 ---

DispatchQueue.main.asyncAfter(deadline: .now() + 0.1) {
    showcase.show(completion: {
        isPresented = false
        targetView.removeFromSuperview()
    })
}

2. 修复多展示叠加问题

当前代码同时渲染两个ShowcaseHost导致叠加,改为顺序触发展示,即第一个弹窗关闭后再显示第二个:

修改HomeNew视图的代码

struct HomeNew: View {
    // 用单个状态控制当前展示的引导项,避免同时显示多个
    @State private var currentShowcaseItem: ShowcaseItem?
    @State private var isShowcasePresented = false

    var profileShowcase: ShowcaseItem {
        ShowcaseItem(
            primaryText: "Profile",
            secondaryText: "Click here to check out your profile and Transport Details",
            animation: .topLeading,
            backgroundColor: UIColor(red: 0.984, green: 0.906, blue: 0.631, alpha: 1.0),
            textColor: .white
        )
    }

    var dashboardShowcase: ShowcaseItem {
        ShowcaseItem(
            primaryText: "Dashboard",
            secondaryText: "Click here to access Dashboards",
            animation: .center,
            backgroundColor: UIColor(red: 0.47, green: 0.75, blue: 0.78, alpha: 1.0),
            textColor: .white
        )
    }

    var body: some View {
        ZStack{
            Color.Neumorphic.main
                .ignoresSafeArea()
            
            // --- 原有界面代码保持不变 ---
            VStack{
                VStack{
                    HStack(alignment: .center) {
                        URLImageView(url: userPhoto.percentageEncoding(), placeholder: "NoProfilePic", width: 80, height: 80)
                            .cornerRadius(15)
                            .scaledToFit()
                            .overlay(
                                RoundedRectangle(cornerRadius: 15)
                                    .stroke(Color.appGreen, lineWidth: 2)
                            )
                            .onTapGesture {
                                if isShowcasePresented {
                                    isShowcasePresented = false
                                } else {
                                    gotoProfile = true
                                }
                            }
                    }
                    Spacer()
                }
                .padding(16)
            }
            
            ScrollView {
                VStack(spacing: 0) {
                    VStack(spacing: 0) {
                        HStack(spacing: 10) {
                            ZStack {
                                HStack {
                                    Spacer()
                                    Text("View dashboard")
                                        .font(.calibriRegular(with: 16))
                                        .foregroundColor(.appGreen)
                                }
                            }
                        }
                    }
                    .frame(height: 40)
                    .onTapGesture {
                        if isShowcasePresented {
                            isShowcasePresented = false
                        } else {
                            gotoDashboard = true
                        }
                    }
                }
            }
            // --- 原有界面代码结束 ---
            
            // 只渲染当前需要展示的引导弹窗
            if isShowcasePresented, let item = currentShowcaseItem {
                ShowcaseHost(isPresented: $isShowcasePresented, showcaseItem: item)
                    .onDisappear {
                        // 当前弹窗关闭后,触发下一个引导项
                        if item == profileShowcase {
                            currentShowcaseItem = dashboardShowcase
                            isShowcasePresented = true
                        }
                    }
            }
        }
        .onAppear {
            // 首次进入页面,启动第一个引导项
            currentShowcaseItem = profileShowcase
            isShowcasePresented = true
        }
    }
}

额外优化建议

  • 移除ShowcaseHost中onAppear里的自动关闭代码(DispatchQueue.main.asyncAfter),让用户点击弹窗后再关闭,符合引导弹窗的交互逻辑
  • 如果需要精准定位到页面上的实际UI元素(比如头像、Dashboard按钮),可以直接将这些SwiftUI视图转换为UIView作为target,而不是创建额外的targetView,这样引导的位置更准确

内容的提问来源于stack exchange,提问作者Swift

相关产品推荐
方舟 Agent Plan

超全模态模型 × Harness 升级,最新支持 Deepseek-V4.1-Flash、GLM-5.3 系列、Doubao-Seedream-5.0-pro、Kimi-K3 (部分), 限时 9.9 元起

最近更新时间:2026.06.19 07:47:04