【问题标题】:Add scrollable button to scrollview向滚动视图添加可滚动按钮
【发布时间】:2016-05-06 06:18:02
【问题描述】:

我想在滚动视图中滚动五个按钮。当用户停止拖动按钮时,它应该移动到下一个按钮。我在这里做错了什么?

class ViewController: UIViewController {

    @IBOutlet weak var categoryScrollView: UIScrollView!
    var categoryArr = ["Jack","Mark","Down","Bill","Steve"]

    override func viewDidLoad() {
        super.viewDidLoad()
        let scrollingView = colorButtonsView(CGSizeMake(150,categoryScrollView.frame.size.height), buttonCount: 5)
        categoryScrollView.contentSize = scrollingView.frame.size
        categoryScrollView.addSubview(scrollingView)
        categoryScrollView.showsVerticalScrollIndicator = false
        categoryScrollView.delegate = self
        categoryScrollView.pagingEnabled = true
        categoryScrollView.indicatorStyle = .Default
    }


func colorButtonsView(buttonSize:CGSize, buttonCount:Int) -> UIView {
        let buttonView = UIView()
        buttonView.frame.origin = CGPointMake(0,0)
        let padding = CGSizeMake(10, 10)
        buttonView.frame.size.width = (buttonSize.width + padding.width) * CGFloat(buttonCount)
        var buttonPosition = CGPointMake(padding.width * 0.5, padding.height)
        let buttonIncrement = buttonSize.width + padding.width
        for i in 0...(buttonCount - 1)  {
            var button = UIButton.buttonWithType(.Custom) as! UIButton
            button.frame.size = buttonSize
            button.frame.origin = buttonPosition
            buttonPosition.x = buttonPosition.x + buttonIncrement
            button.setTitle(categoryArr[i], forState: UIControlState.Normal)
            buttonView.addSubview(button)
        }
        return buttonView
    }
}
extension ViewController:UIScrollViewDelegate{
    func scrollViewDidEndDecelerating(scrollView: UIScrollView) {

        let index = round(scrollView.contentOffset.x / scrollView.frame.size.width)
        print(index)
    }
}

滚动视图滚动良好.. 但只有两次。它不会滚动到下一个按钮。我该怎么办?

【问题讨论】:

  • 在我的回答中使用代码。它对我来说很好,并且一次在水平方向滚动一个按钮
  • 你在使用自动布局吗?

标签: ios swift scrollview


【解决方案1】:
func setContentOffset(scrollView: UIScrollView) {
    
    let numOfItems = itemCount  // 5
    let stopOver = scrollView.contentSize.width / CGFloat(numOfItems)
    let x = round(scrollView.contentOffset.x / stopOver) * stopOver
    
    guard x >= 0 && x <= scrollView.contentSize.width - scrollView.frame.width else {
        return
    }
    
    scrollView.setContentOffset(CGPointMake(x, scrollView.contentOffset.y), animated: true)
}

extension ViewController: UIScrollViewDelegate {

    func scrollViewWillBeginDecelerating(scrollView: UIScrollView) {
    
        setContentOffset(scrollView)
    }

    func scrollViewDidEndDragging(scrollView: UIScrollView, willDecelerate decelerate: Bool) {
    
        guard !decelerate else {
            return
        }
    
        setContentOffset(scrollView)
    }
}

还在 Github 做了一个演示项目
https://github.com/rishi420/ScrollViewCustomPaging


更新:

尝试考虑用户 endDragging 时的滚动速度。

var velocityX = CGFloat(0.0) 

.

func setContentOffset(scrollView: UIScrollView) {
    
    let numOfItems = itemCount
    let stopOver = scrollView.contentSize.width / CGFloat(numOfItems)
    var x = round((scrollView.contentOffset.x + (velocityX * 150)) / stopOver) * stopOver // 150 is for test. Change it for your liking
    
    x = max(0, min(x, scrollView.contentSize.width - scrollView.frame.width))
    
    scrollView.setContentOffset(CGPointMake(x, scrollView.contentOffset.y), animated: true)
}

.

func scrollViewWillEndDragging(scrollView: UIScrollView, withVelocity velocity: CGPoint, targetContentOffset: UnsafeMutablePointer<CGPoint>)
{
    velocityX = velocity.x
}

【讨论】:

  • 工作正常..但我如何找到索引?现在可见的那个
  • round(scrollView.contentOffset.x / stopOver)
  • 如果我想要快速滚动的动画怎么办?最后一个似乎并没有让人感到困惑,无论是活跃还是不活跃?
  • 试过scrollViewDidEndDecelerating,速度很快,但动画不好看。你可以自己试试。而不是 scrollViewWillBeginDecelerating 调用来自 scrollViewDidEndDecelerating 的方法
  • 另一种方法是使用scrollViewWillEndDragging:withVelocity。如果速度较高,可能会增加索引计数。所以 scrollView 滚动更多并停在下一个索引处。
【解决方案2】:

您是否尝试过使用 UITableView 而不是 UIScrollView 并使 tableview 的大小等于您想要的按钮大小。 然后将按钮添加到其单元格。 启用 UITableView 的 "Paging"

这将帮助您更好地管理内容,即更方便地管理按钮,因为您可以将按钮数组传递给 tableview 并在其 cellForAtIndex 方法中进行管理。

【讨论】:

  • 为什么是tableview而不是collection view?如果我想在同一个单元格中添加两个按钮,我认为它不起作用?
【解决方案3】:

在您的scrollViewDidEndDecelerating() 方法中计算按钮索引后,只需调用scrollRectToVisible(rect, animated:) 并使用该索引处的按钮框架。

【讨论】:

  • 我无法真正计算索引。它只显示两个索引 0.0 和 1.0 ..我想要一种机制,可以为五个按钮显示五个索引,对吧?
【解决方案4】:

UIScrollView 并不总是减速。您可以使用此答案中的方法:https://stackoverflow.com/a/13067444,或使用scrollViewWillEndDragging:withVelocity:targetContentOffset: 方法中的targetContentOffset

【讨论】:

    【解决方案5】:

    稍微微调了 Aruna 的代码。设置一些背景颜色,方便调试查看是否得到了预期的行为。

    class ViewController: UIViewController {
    
        @IBOutlet weak var categoryScrollView: UIScrollView!
        var categoryArr = ["Jack","Mark","Down","Bill","Steve"]
        var buttonColors = [UIColor.greenColor(), UIColor.blueColor(), UIColor.blackColor(), UIColor.cyanColor(), UIColor.magentaColor()]
        let kPadding:CGFloat = 10
    
        override func viewDidLoad() {
            super.viewDidLoad()
    
            let buttonSize = CGSizeMake(categoryScrollView.bounds.size.width/2, categoryScrollView.bounds.size.height/2)//hal
    
            let scrollingView = colorButtonsView(buttonSize, buttonCount: 5)
            categoryScrollView.contentSize = scrollingView.frame.size
            categoryScrollView.addSubview(scrollingView)
            categoryScrollView.showsVerticalScrollIndicator = false
            categoryScrollView.delegate = self
            categoryScrollView.pagingEnabled = true
            categoryScrollView.indicatorStyle = .Default
            categoryScrollView.contentOffset = CGPointMake(0, 0)
        }
    
    
        func colorButtonsView(buttonSize:CGSize, buttonCount:Int) -> UIView {
            let buttonView = UIView()
            buttonView.frame.origin = CGPointMake(0,0)
            let padding = CGSizeMake(kPadding, kPadding)
            buttonView.frame.size.width = (buttonSize.width + padding.width) * CGFloat(buttonCount)
            var buttonPosition = CGPointMake(0, padding.height)
            let buttonIncrement = buttonSize.width + padding.width
            for i in 0...(buttonCount - 1)  {
                let button = UIButton(type: .Custom)
                button.frame.size = buttonSize
                button.frame.origin = buttonPosition
                buttonPosition.x = buttonPosition.x + buttonIncrement
                button.setTitle(categoryArr[i], forState: UIControlState.Normal)
                button.backgroundColor = buttonColors[i]
                buttonView.addSubview(button)
            }
            buttonView.backgroundColor = UIColor.redColor()
            return buttonView
        }
    }
    extension ViewController:UIScrollViewDelegate{
        func scrollViewDidEndDecelerating(scrollView: UIScrollView) {
    
            let index = round(scrollView.contentOffset.x / scrollView.frame.size.width)
            print(index)
        }
    }
    

    【讨论】:

    • 它可以工作,但索引不正确...因为有 5 个按钮,但索引从 0 到 3
    【解决方案6】:

    请检查修改后的代码:

    class ViewController: UIViewController {
    
    @IBOutlet weak var categoryScrollView: UIScrollView!
    var categoryArr = ["Jack","Mark","Down","Bill","Steve"]
    
    override func viewDidLoad() {
        super.viewDidLoad()
        let scrollingView = colorButtonsView(CGSizeMake(categoryScrollView.frame.size.width / 3 ,categoryScrollView.frame.size.height), buttonCount: 5)
        categoryScrollView.contentSize = scrollingView.frame.size
        categoryScrollView.addSubview(scrollingView)
        categoryScrollView.showsVerticalScrollIndicator = false
        categoryScrollView.delegate = self
        categoryScrollView.pagingEnabled = false
        categoryScrollView.bounces = false
        categoryScrollView.indicatorStyle = .Default
    }
    
    
    func colorButtonsView(buttonSize:CGSize, buttonCount:Int) -> UIView {
        let buttonView = UIView()
        buttonView.frame.origin = CGPointMake(0,0)
        let padding = CGSizeMake(10, 10)
        buttonView.frame.size.width = (buttonSize.width + padding.width) * CGFloat(buttonCount)
        var buttonPosition = CGPointMake(padding.width * 0.5, padding.height)
        let buttonIncrement = buttonSize.width + padding.width
        for i in 0...(buttonCount - 1)  {
            let button = UIButton(type: .Custom)
            button.backgroundColor = UIColor.redColor()
            button.frame.size = buttonSize
            button.frame.origin = buttonPosition
            buttonPosition.x = buttonPosition.x + buttonIncrement
            button.setTitle(categoryArr[i], forState: UIControlState.Normal)
            buttonView.addSubview(button)
        }
        return buttonView
    }
    

    }

    extension ViewController:UIScrollViewDelegate{
    
        func scrollViewWillEndDragging(scrollView: UIScrollView, withVelocity velocity: CGPoint, targetContentOffset: UnsafeMutablePointer<CGPoint>) {
            let buttonWidth = scrollView.frame.size.width / 3
            let index = round(scrollView.contentOffset.x / buttonWidth)
            targetContentOffset.memory.x = index*buttonWidth + index*10
        }
    
    }
    

    【讨论】:

    • 我没有看到变化?
    • 这一行:let scrollingView = colorButtonsView(categoryScrollView.frame.size, buttonCount: 5)
    • 它可以工作,但不如预期..如果我希望按钮宽度为 categoryScrollView 框架的 1/3
    猜你喜欢
    • 1970-01-01
    • 1970-01-01
    • 2011-01-22
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    相关资源
    最近更新 更多