【问题标题】:Is it possible to unclip just a single subview from its superview's bounds?是否可以从其父视图的边界中取消剪辑单个子视图?
【发布时间】:2020-03-04 11:46:50
【问题描述】:

我有一种情况,我希望单个子视图被裁剪到父视图的边界,而父视图的其余子视图被裁剪到其边界。有没有办法将某个UIView 排除在其超级视图的范围内。同样,UIView 可以指定它想要/不想裁剪到自己的边界的子视图吗?

就代码而言,我使用Koloda 创建类似于Tinder 的刷卡的UIViews。我有一个集合视图,其单元格本质上是 Koloda 视图。每当卡片开始平移时,我将其单元格的集合视图的clipsToBounds 属性设置为false。这允许单元格在导航栏上方平移而不会被剪裁。当平移结束时,视图单元格的集合视图的clipsToBounds 属性设置回true

import UIKit
import Koloda

class LikedUserCollectionViewCell: UICollectionViewCell {
    @IBOutlet var swipeView: KolodaView!
    var parentVC: MyViewController!
}

extension LikedUserCollectionViewCell: KolodaViewDelegate, KolodaViewDataSource {
    func koloda(_ koloda: KolodaView, viewForCardAt index: Int) -> UIView {
        //return a KolodaView, this code isn't important to the issue
        return KolodaView()
    }

    func kolodaNumberOfCards(_ koloda: KolodaView) -> Int {
        return 1
    }

    func kolodaPanBegan(_ koloda: KolodaView, card: DraggableCardView) {
        self.parentVC.collectionView.bringSubviewToFront(self)
        //Here, instead of unclipping all of the collection view's subviews, I would like to only unclip the one containing the subview that is being panned
        self.parentVC.collectionView.clipsToBounds = false
    }

    func kolodaPanFinished(_ koloda: KolodaView, card: DraggableCardView) {
        //Once the pan is finished, all of the collection view's subviews can be clipped again
        self.parentVC.collectionView.clipsToBounds = true
    }

    func koloda(_ koloda: KolodaView, didSwipeCardAt index: Int, in direction: SwipeResultDirection) {
        //Not relevant to the question
    }
}

问题是,当有部分单元格从集合视图中滚动出来,但还没有从集合视图中移除,因为它们还没有完全滚出集合视图,它们现在变得可见为集合视图的clipsToBounds现在设置为true。这就是为什么我希望能够指定集合视图的哪些子视图被剪裁到其边界。这种行为可以在下面的 gif 中看到:

所以,总而言之,有没有办法,而不是通过 superview.clipsToBounds = false 从其父视图的边界取消剪辑所有子视图,我只能从其父视图的边界取消剪辑单个子视图?

【问题讨论】:

    标签: ios swift uiview uikit clipstobounds


    【解决方案1】:

    这里的简单解决方案是,既然要为单个视图创建异常,请不要移动 collectionView 单元格。拍摄snapshotView 并移动快照;它可以在层次结构中的任何其他位置,并且不需要是集合视图的子视图。您可以使用UIView.convert(from:) 将单元格坐标转换为适当的父视图的坐标空间,以正确放置您的快照。

    从 OP 编辑​​:

    我听取了 Josh 的建议并将我的代码更新为以下内容,从而解决了我的问题:

    import UIKit
    import Koloda
    
    class LikedUserCollectionViewCell: UICollectionViewCell {
        @IBOutlet var swipeView: KolodaView!
        var parentVC: MyViewController!
        //DraggableCardView is a custom Koloda class
        var draggableCardView: DraggableCardView!
    }
    
    extension LikedUserCollectionViewCell: KolodaViewDelegate, KolodaViewDataSource {
        func koloda(_ koloda: KolodaView, viewForCardAt index: Int) -> UIView {
            //return a KolodaView, this code isn't important to the issue
            return KolodaView()
        }
    
        func kolodaNumberOfCards(_ koloda: KolodaView) -> Int {
            return 1
        }
    
        func kolodaPanBegan(_ koloda: KolodaView, card: DraggableCardView) {
            let snapshotView = self.swipeView.snapshotView(afterScreenUpdates: false)!
            snapshotView.accessibilityIdentifier = "snapshotView"
            self.parentVC.view.addSubview(snapshotView)
            snapshotView.frame.origin = self.parentVC.view.convert(swipeView.viewForCard(at: 0)!.frame.origin, from: swipeView)
            draggableCardView = card
            swipeView.viewForCard(at: 0)?.isHidden = true
        }
    
        func koloda(_ koloda: KolodaView, draggedCardWithPercentage finishPercentage: CGFloat, in direction: SwipeResultDirection) {
            let snapshotView = self.parentVC.view.subviews.first(where: { $0.accessibilityIdentifier == "snapshotView" })!
            snapshotView.frame.origin = self.parentVC.view.convert(draggableCardView.frame.origin, from: swipeView)
        }
    
        func kolodaPanFinished(_ koloda: KolodaView, card: DraggableCardView) {
            let snapshotView = self.parentVC.view.subviews.first(where: { $0.accessibilityIdentifier == "snapshotView" })!
            draggableCardView = nil
            snapshotView.removeFromSuperview()
            swipeView.viewForCard(at: 0)?.isHidden = false
        }
    
        func koloda(_ koloda: KolodaView, didSwipeCardAt index: Int, in direction: SwipeResultDirection) {
            //Not relevant to the question
        }
    }
    
    

    【讨论】:

    • 太棒了,谢谢。我会检查一下,如果它有效,我会回来。
    • 它肯定对我有用。我将编辑您的答案,以展示我稍后(也许明天)是如何实现它的
    【解决方案2】:

    看你的界面,为什么collectionView在(导航栏)上方?

    在这种情况下,您不需要任何剪辑,只要 collectionView 位于导航栏后面。

    要么调用 sendSubview(toBack: collectionView) 要么将 collectionView.layer.zPosition 设置为更大的值。

    【讨论】:

    • 我将它放在导航栏上方,因为我希望单元格在拖动时能够位于导航栏上方。
    • 在这种情况下,我会说最好将所有内容都放在同一个超级视图堆栈中,而不必真正破解。将所有内容作为子视图添加到 UINavigationController 的视图中,并从一个位置控制层层次结构。
    猜你喜欢
    • 1970-01-01
    • 2015-03-19
    • 1970-01-01
    • 2022-07-07
    • 1970-01-01
    • 1970-01-01
    • 2013-05-03
    • 2020-08-23
    • 1970-01-01
    相关资源
    最近更新 更多