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

iOS中UIScrollView仅显示最后添加视图的问题排查求助

Why Only the Last Wallet View Shows Up in Your UIScrollView?

Hey there, let's break down what's going wrong with your code and fix it step by step.

Core Issues in Your Code

1. Conflict Between AutoLayout and Manual Frame Setting

You set walletView.translatesAutoresizingMaskIntoConstraints = false, which tells iOS to use AutoLayout for this view. But then you manually set the frame—and didn't add any AutoLayout constraints to define the view's position/size. Without constraints, iOS doesn't know where to place these views, so all your Wallet views end up overlapping at the (0,0) position of accountSavingSubView. Only the last one you add is visible on top.

2. Wrong yPosition Calculation

Your line yPosition += walletView.frame.maxY is causing the y-coordinate to grow way too fast:

  • First view: y=0, maxY = view height h → yPosition becomes h
  • Second view: y=h, maxY = h + h = 2h → yPosition becomes h + 2h = 3h
  • Third view: y=3h, maxY = 3h + h = 4h → yPosition becomes 3h + 4h =7h
    This pushes later views way off-screen, while earlier ones are stuck at (0,0) due to the AutoLayout conflict.

Fixes to Try

Since you're already enabling AutoLayout, let's use proper constraints to position your Wallet views:

private func createAndAddWallets() {
    var previousWallet: UIView? = nil
    
    for key in dictData.keys {
        // Load the Wallet nib with safe unwrapping
        guard let walletView = Bundle.main.loadNibNamed("Wallet", owner: self, options: nil)?.first as? Wallet else {
            continue // Add error handling here if needed
        }
        
        walletView.translatesAutoresizingMaskIntoConstraints = false
        walletView.accountNameLabel.text = key
        walletView.isUserInteractionEnabled = true
        accountSavingSubView.addSubview(walletView)
        
        // Pin width to accountSavingSubView, set height (match subview or use fixed value)
        NSLayoutConstraint.activate([
            walletView.leadingAnchor.constraint(equalTo: accountSavingSubView.leadingAnchor),
            walletView.trailingAnchor.constraint(equalTo: accountSavingSubView.trailingAnchor),
            walletView.heightAnchor.constraint(equalTo: accountSavingSubView.heightAnchor)
        ])
        
        // Vertical positioning: stack views one after another
        if let prevWallet = previousWallet {
            walletView.topAnchor.constraint(equalTo: prevWallet.bottomAnchor).isActive = true
        } else {
            walletView.topAnchor.constraint(equalTo: accountSavingSubView.topAnchor).isActive = true
        }
        
        previousWallet = walletView
        print("walletView frame: \(walletView.frame)")
    }
    
    // Pin the last wallet to the bottom of accountSavingSubView so scrollView calculates contentSize automatically
    if let lastWallet = previousWallet {
        lastWallet.bottomAnchor.constraint(equalTo: accountSavingSubView.bottomAnchor).isActive = true
    }
    
    // No need to manually set contentSize—AutoLayout handles it if your scrollView's constraints are set up correctly
}

Option 2: Stick to Frame Layout (If You Prefer)

If you want to use manual frame setting, turn off AutoLayout for the Wallet views and fix the yPosition logic:

private func createAndAddWallets() {
    var yPosition: CGFloat = 0.0
    let walletWidth = accountSavingSubView.frame.width
    let walletHeight = accountSavingSubView.frame.height
    
    for key in dictData.keys {
        guard let walletView = Bundle.main.loadNibNamed("Wallet", owner: self, options: nil)?.first as? Wallet else {
            continue
        }
        
        // Enable autoresizing masks so frame settings work
        walletView.translatesAutoresizingMaskIntoConstraints = true
        walletView.frame = CGRect(x: 0, y: yPosition, width: walletWidth, height: walletHeight)
        walletView.accountNameLabel.text = key
        accountSavingSubView.addSubview(walletView)
        
        // Update yPosition by adding the view's height, not maxY
        yPosition += walletHeight
        
        walletView.isUserInteractionEnabled = true
        print("walletView frame: \(walletView.frame)")
    }
    
    // Set contentSize to the final yPosition (total height of all wallets)
    self.contanerScrollView.contentSize = CGSize(width: walletWidth, height: yPosition)
}

Extra Tips

  • Call createAndAddWallets() in viewDidLayoutSubviews instead of viewDidLoad—this ensures accountSavingSubView has its final frame size when you create the Wallet views.
  • If your Wallet nib has internal AutoLayout constraints, stick with Option 1 to avoid layout conflicts and ensure better adaptability across screen sizes.

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

相关产品推荐
方舟 Agent Plan

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

最近更新时间:2026.05.11 09:19:11