使用autolayout

时间:2015-06-11 13:02:16

标签: swift ios8 uiscrollview autolayout

我正在尝试将一些ObjC转换为水平滚动UITableViewCell到Swift。最初的ObjC版本使用了单元格内容的显式大小,但我试图在我的应用程序中使用autolayout来保持一致性。

一切顺利,直到我想要在屏幕的左侧和右侧创建按钮,可以通过以与Mail应用程序中的删除按钮相同的方式滑动来隐藏/取消隐藏按钮(但我想要一个更多的功能因此是一个自制的解决方案)。原始代码通过在左侧和右侧创建与按钮大小相同的scrollview内容插件实现了这一点,但我有一些概念和程序问题。

首先,我将contentInset理解为滚动视图周围的“缓冲区”,人们经常使用它来防止内容区域被状态或导航栏隐藏(即最大化屏幕空间的方式)。因此,无论contentInsets如何,滚动视图的内容区域应保持不变,因为它们本质上是一个边距。然而,原始编码器创建了一个负面插图,这些似乎神奇地增加了内容区域,但插图中的视图隐藏在屏幕外。这是怎么回事?为什么我们这样做而不仅仅是改变偏移来补偿屏幕外按钮的宽度?

其次,通过向远或足够快地滑动来显示按钮,以便滚动视图的最终静止点显示隐藏按钮。将scrollview锁定到位并停止重新隐藏按钮的代码位于scrollViewWillEndDragging函数内,并更改targetContentOffset以实现此目的。这在使用显式视图和按钮大小时有效,但在使用autolayout时无法工作。但是,如果您调用scrollview.setContentOffset它可以工作。为什么不同?当然这是一回事,但我猜测必须有一个不同的方法调用序列。

代码如下(我已经编辑了一些不那么重要的材料)。这是概念验证,所以不是很优雅!

创建scrollView:

        let scrollView = UIScrollView()
        scrollView.backgroundColor = UIColor.blueColor()
        scrollView.delegate = self;
        scrollView.scrollsToTop = false
        scrollView.showsHorizontalScrollIndicator = false
        scrollView.showsVerticalScrollIndicator = false
        self.contentView.addSubview(scrollView)
        // pin scrollView to cell contentView
        scrollView.setTranslatesAutoresizingMaskIntoConstraints(false)
        self.contentView.addConstraints(NSLayoutConstraint.constraintsWithVisualFormat("H:|[sv]|", options: nil, metrics: nil, views: ["sv" : scrollView]))
        self.contentView.addConstraints(NSLayoutConstraint.constraintsWithVisualFormat("V:|[sv]|", options: nil, metrics: nil, views: ["sv" : scrollView]))

        let scrollViewContent = UIView()
        scrollView.addSubview(scrollViewContent)

        // add content sequentially (L>>R) to the content subview of scrollView
        var lastObjectAdded: UIView? = nil // allows constraints to be created between adjacent contentView subviews

        // add button on the left
        let leftButton = UIButton.buttonWithType(UIButtonType.Custom) as! UIButton
        leftButton.backgroundColor = UIColor.purpleColor()
        leftButton.setTitle("Click Me!", forState: UIControlState.Normal)
        leftButton.setTitleColor(UIColor.whiteColor(), forState: UIControlState.Normal)
        // width needs to be set explicitly so inset for scroll view can be set in this class
        // (when using autolayout, frame dimensions are not available until after all subviews are laid out)
        leftButton.frame.size.width = CGFloat(100)
        scrollViewContent.addSubview(leftButton)
        // size using autolayout
        leftButton.setTranslatesAutoresizingMaskIntoConstraints(false)
        // give button a fixed width
        // TODO: Enable this to be defined by function call
        scrollViewContent.addConstraints(NSLayoutConstraint.constraintsWithVisualFormat("H:[but(==100)]", options: nil, metrics: nil, views: ["but" : leftButton]))
        // pin height to height of cell's contentView
        self.contentView.addConstraints(NSLayoutConstraint.constraintsWithVisualFormat("V:[but(==cv)]", options: nil, metrics: nil, views: ["but" : leftButton, "cv" : self.contentView]))
        // pin to top left of the scollView subview
        scrollViewContent.addConstraints(NSLayoutConstraint.constraintsWithVisualFormat("V:|[but]", options: nil, metrics: nil, views: ["but" : leftButton]))
        scrollViewContent.addConstraints(NSLayoutConstraint.constraintsWithVisualFormat("H:|[but]", options: nil, metrics: nil, views: ["but" : leftButton]))
        // store a reference to the button to be used for positioning other subviews
        lastObjectAdded = leftButton
        testView = leftButton

< SNIP ---
--- SNIP>

        // test that I can add a label that matches the  width of the tableViewCell's contentView subview'
        let specialLab = UILabel()
        specialLab.setTranslatesAutoresizingMaskIntoConstraints(false)
        specialLab.backgroundColor = UIColor.orangeColor()
        specialLab.text = "WIDTH MATCHES TABLEVIEWCELL WIDTH"
        scrollViewContent.addSubview(specialLab)
        scrollViewContent.addConstraints(NSLayoutConstraint.constraintsWithVisualFormat("V:|-(10)-[lab]", options: nil, metrics: nil, views: ["lab" : specialLab]))
        // this is the important constraint
        self.contentView.addConstraints(NSLayoutConstraint.constraintsWithVisualFormat("H:[lab(==cv)]", options: nil, metrics: nil, views: ["lab" : specialLab, "cv" : contentView]))
        scrollViewContent.addConstraints(NSLayoutConstraint.constraintsWithVisualFormat("H:[last]-(10)-[lab]", options: nil, metrics: nil, views: ["lab" : specialLab, "last" : lastObjectAdded!]))
        lastObjectAdded = specialLab

        // pin last label to right which dictates content size width
        scrollViewContent.addConstraints(NSLayoutConstraint.constraintsWithVisualFormat("H:[lab]-10-|", options: nil, metrics: nil, views: ["lab" : lastObjectAdded!]))

        // set scrollView's content view height and frame-to-superview constraints
        // (width comes from subview constraints)
        // content view is calculated for us
        scrollViewContent.setTranslatesAutoresizingMaskIntoConstraints(false)
        scrollView.addConstraints(NSLayoutConstraint.constraintsWithVisualFormat("H:|[svc]|", options: nil, metrics: nil, views: ["svc" : scrollViewContent]))
        scrollView.addConstraints(NSLayoutConstraint.constraintsWithVisualFormat("V:|[svc]|", options: nil, metrics: nil, views: ["svc" : scrollViewContent]))

        // create inset to hide button on left
         scrollView.contentInset = UIEdgeInsetsMake(0, -leftButton.bounds.width, 0, 0)

第二位代码涉及取消隐藏左侧的按钮:

extension SwipeableViewCell: UIScrollViewDelegate {

    func scrollViewWillEndDragging(scrollView: UIScrollView, withVelocity velocity: CGPoint, targetContentOffset: UnsafeMutablePointer<CGPoint>) {
        let left = CGFloat(100.0) // this is the inset required to hide the left button(s)
        let kSwipeableTableViewCellOpenVelocityThreshold = CGFloat(0.6) // minimum velocity req to reveal buttons
        let kSwipeableTableViewCellMaxCloseMilliseconds = CGFloat(300) // max time for the button to be hidden
        let x = scrollView.contentOffset.x

        // check to see if swipe from left is far enough and fast enough to reveal button
        if (left > 0 && (x < 0 || (x < left && velocity.x < -kSwipeableTableViewCellOpenVelocityThreshold))) {
            // manually set the offset to reveal the whole button but no more
//            targetContentOffset.memory = CGPointZero // this should work but doesn't - offset is not retained
            dispatch_async(dispatch_get_main_queue()) {
                scrollView.setContentOffset(CGPointZero, animated: true) // this works!
            }
        } else {
            // if not, hide the button
            dispatch_async(dispatch_get_main_queue()) {
                scrollView.setContentOffset(CGPoint(x: CGFloat(100), y: CGFloat(0)), animated: true)
            }
        }
    }
}

0 个答案:

没有答案