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

自定义UIView添加子视图后无法从父视图移除问题求助

Fixing Your Swipe Card Removal Issue with Shadow/Swipe Subviews

Hey there, let's break down why your MainSwipeCardView isn't removing properly once you add shadowView and swipeView, and fix it step by step:

1. Wrong Constraint Anchors Are Messing Up Layout

The first big issue is in your constraint setup for swipeView and label. When you add a subview to another view, its constraints should reference the parent subview, not the top-level MainSwipeCardView. Right now, you're anchoring swipeView (a child of shadowView) to self's anchors, which breaks the view hierarchy and can interfere with gesture recognition and view removal.

Fixed Code:

func configureSwipeView() {
    swipeView.layer.cornerRadius = 15
    swipeView.clipsToBounds = true
    shadowView.addSubview(swipeView)
    swipeView.translatesAutoresizingMaskIntoConstraints = false
    // Anchor to shadowView instead of self
    swipeView.leftAnchor.constraint(equalTo: shadowView.leftAnchor).isActive = true
    swipeView.rightAnchor.constraint(equalTo: shadowView.rightAnchor).isActive = true
    swipeView.bottomAnchor.constraint(equalTo: shadowView.bottomAnchor).isActive = true
    swipeView.topAnchor.constraint(equalTo: shadowView.topAnchor).isActive = true
}

func configureLabelView() {
    swipeView.addSubview(label)
    label.backgroundColor = .white
    label.textColor = .black
    label.textAlignment = .center
    label.font = UIFont.systemFont(ofSize: 18)
    label.translatesAutoresizingMaskIntoConstraints = false
    // Anchor to swipeView instead of self
    label.leftAnchor.constraint(equalTo: swipeView.leftAnchor).isActive = true
    label.rightAnchor.constraint(equalTo: swipeView.rightAnchor).isActive = true
    label.bottomAnchor.constraint(equalTo: swipeView.bottomAnchor).isActive = true
    label.heightAnchor.constraint(equalToConstant: 85).isActive = true
}

2. Incorrect Parent Container Center Calculation

In your pan gesture handler, you're calculating the parent container's center using self.frame.width / 2—but self is the card itself, not its parent SwipeCardContainerView. This leads to wrong drag positioning, which can make the card appear to not move correctly and interfere with the removal trigger.

Fixed Gesture Handler:

@objc func handlePanGesture(sender: UIPanGestureRecognizer){
    guard let card = sender.view as? MainSwipeCardView, let parentContainer = card.superview else { return }
    
    let translation = sender.translation(in: parentContainer)
    let parentCenter = CGPoint(x: parentContainer.frame.width / 2, y: parentContainer.frame.height / 2)
    card.center = CGPoint(x: parentCenter.x + translation.x, y: parentCenter.y + translation.y)
    
    switch sender.state {
    case .ended:
        let cardCenterX = card.center.x
        // Use parent container bounds to check if card is fully swiped out
        if cardCenterX > parentContainer.frame.width + 50 {
            delegate?.swipeDidEnd(on: card)
            UIView.animate(withDuration: 0.2) {
                card.center = CGPoint(x: parentContainer.frame.width + 200, y: parentCenter.y + translation.y + 75)
                card.alpha = 0
            } completion: { _ in
                // Remove after animation completes to avoid layout glitches
                card.removeFromSuperview()
            }
            return
        } else if cardCenterX < -50 {
            delegate?.swipeDidEnd(on: card)
            UIView.animate(withDuration: 0.2) {
                card.center = CGPoint(x: -200, y: parentCenter.y + translation.y + 75)
                card.alpha = 0
            } completion: { _ in
                card.removeFromSuperview()
            }
            return
        }
        // Reset card position if not swiped far enough
        UIView.animate(withDuration: 0.2) {
            card.transform = .identity
            card.center = parentCenter
        }
    default:
        break
    }
}

3. Duplicate Card Additions to cardsView

In SwipeCardContainerView's addCardFrame method, you're calling cardsView.append(cardView) again—but this already happens in addCardView. This causes duplicate entries in your card array, leading to incorrect visibleCards counts and weird behavior when removing cards.

Fixed addCardFrame:

func addCardFrame(index: Int, cardView: MainSwipeCardView){
    // Remove the duplicate append call here
    var cardViewFrame = bounds
    let horizontalInset = (CGFloat(index) * self.horizontalInset)
    let verticalInset = CGFloat(index) * self.verticalInset
    cardViewFrame.size.width -= 2 * horizontalInset
    cardViewFrame.origin.x += horizontalInset
    cardViewFrame.origin.y += verticalInset
    cardView.frame = cardViewFrame
}

4. Move removeFromSuperview to Animation Completion

Previously, you were removing the card immediately when the swipe ends, before the animation finishes. This can cause layout inconsistencies because the view is removed mid-animation. Moving the removal to the animation's completion closure ensures the view is only removed after it's visually gone.


After applying all these fixes, your swipe cards should remove correctly, and the visibleCards count will properly decrease from 3→2→1 as expected.

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

相关产品推荐
方舟 Agent Plan

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

最近更新时间:2026.05.13 06:34:12