0

Previously I did with Swift4 UIScrollView which scrolled with buttons and x offset. enter image description here

In Swift4 I have:

  1. Set Scrolling Enabled and Paging Enabled to false.

    List item

  2. Created the margins, offsets for each frame in UIScrollView and changed the position with buttons Back and Next.

Here is the code:

import UIKit

class ViewController: UIViewController {

@IBOutlet weak var buttonSound: UIButton!
@IBOutlet weak var buttonPrev: UIButton!
@IBOutlet weak var buttonNext: UIButton!
@IBOutlet weak var scrollView: UIScrollView!

var levels = ["level1", "level2", "level3", "level4"]
let screenWidth = UIScreen.main.bounds.width
let screenHeight = UIScreen.main.bounds.height
var currentLevel = 1
var previousLevel: Int? = nil

override func viewDidLoad() {
    super.viewDidLoad()

    //Defining the Various Swipe directions (left, right, up, down)
    let swipeLeft = UISwipeGestureRecognizer(target: self, action: #selector(self.handleGesture(gesture:)))
      swipeLeft.direction = .left
    self.view.addGestureRecognizer(swipeLeft)

    let swipeRight = UISwipeGestureRecognizer(target: self, action: #selector(self.handleGesture(gesture:)))
    swipeRight.direction = .right
    self.view.addGestureRecognizer(swipeRight)

    addHorizontalLevelsList()
    customizeButtons()
    resizeSelected()
}

func addHorizontalLevelsList() {

    var frame : CGRect?
    for i in 0..<levels.count {

        let button = UIButton(type: .custom)
        let buttonW = screenWidth/3
        let buttonH = screenHeight/2

        frame = CGRect(x: CGFloat(i+1) * (screenWidth/2) - (buttonW/2),
                       y: buttonH - 100,
                       width: buttonW,
                       height: buttonH)

        button.frame = frame!
        button.tag = i+1
        button.backgroundColor = .lightGray
        button.addTarget(self, action: #selector(selectTeam), for: .touchUpInside)
        button.setTitle(levels[i], for: .normal)
        scrollView.addSubview(button)
    }


    scrollView.contentSize = CGSize(width: (screenWidth/2 * CGFloat(levels.count)),
                                    height: screenHeight)
    scrollView.backgroundColor = .clear
    self.view.addSubview(scrollView)
}


func customizeButtons(){
    buttonPrev.frame = CGRect(x: 0,
                              y: (screenHeight/2) - 40,
                              width: 80, height: 80)
    buttonNext.frame = CGRect(x: screenWidth - 80,
                              y: (screenHeight/2) - 40,
                              width: 80, height: 80)
    buttonPrev.superview?.bringSubviewToFront(buttonPrev)
    buttonNext.superview?.bringSubviewToFront(buttonNext)
}

@objc func selectTeam(button: UIButton) {
    button.transform = CGAffineTransform(scaleX: 0.6, y: 0.6)
    UIView.animate(withDuration: 1.0,
                               delay: 0,
                               usingSpringWithDamping: CGFloat(0.20),
                               initialSpringVelocity: CGFloat(6.0),
                               options: UIView.AnimationOptions.allowUserInteraction,
                               animations: {
                                button.transform = CGAffineTransform.identity
        },
                               completion: { Void in()  }
    )

    print(levels[button.tag])

    let vc = PopTypeVC(nibName: "PopTypeVC", bundle: nil)
    vc.modalPresentationStyle = UIModalPresentationStyle.overCurrentContext
    self.present(vc, animated: true)
}

@IBAction func prevLevel(_ sender: Any) {
    if currentLevel > 0 {

        currentLevel -= 1
        scroll()
    }
}
@IBAction func nextLevel(_ sender: Any) {
    if currentLevel < levels.count {

        currentLevel += 1
        scroll()
    }
}

func scroll(){
    print(currentLevel)
    print(previousLevel as Any)

    scrollView.setContentOffset(CGPoint(x: currentLevel * Int(screenWidth/2), y: 0), animated: true)
    resizeSelected()
}

// The @objc before func is a must, since we are using #selector (above)
@objc func handleGesture(gesture: UISwipeGestureRecognizer) -> Void {
    if gesture.direction == UISwipeGestureRecognizer.Direction.right {
        prevLevel(self)
    }
    else if gesture.direction == UISwipeGestureRecognizer.Direction.left {
        nextLevel(self)
    }
}

func resizeSelected(){
    if previousLevel != nil {
        let previousFrame = CGRect(x:CGFloat(previousLevel!) * (screenWidth/2) - (screenWidth/3)/2,
                                   y:        (screenHeight/2) - 100,
                                   width:    screenWidth/3,
                                   height:   screenHeight/2)
        scrollView.viewWithTag(previousLevel!)?.frame = previousFrame
    }

    let currentFrame = CGRect(x: CGFloat(currentLevel) * (screenWidth/2) - (screenWidth/3)/2 - 10,
                              y:        (screenHeight/2) - 110,
                              width:    screenWidth/3 + 20,
                              height:   screenHeight/2 + 20)
    scrollView.viewWithTag(currentLevel)?.frame = currentFrame
        previousLevel = currentLevel
    }
}

The problem is I can't do this with SwiftUI:

struct ContentView: View {

    static var levels = ["level1",
                  "level2",
                  "level3",
                  "level4"]
    var currentLevel = 1
    var previousLevel: Int? = nil

    let screenW = UIScreen.main.bounds.width
    let screenH = UIScreen.main.bounds.height
    let margin1 = 50
    let margin2 = 100
    let margin3 = 20
    let sceneButtonW = 100
    let buttonPadding = 40

    var body: some View {

        ZStack {

            // Horizontal list
            VStack {
                Spacer()
                    .frame(height: margin2)
                ScrollView(.horizontal, showsIndicators: false) {

                    HStack{
                        Spacer()
                            .frame(width: buttonPadding + sceneButtonW/2)
                        ForEach(0..<ContentView.levels.count) { i in
                            cardView(i: i).tag(i+1)
                        }
                        Spacer()
                            .frame(width: buttonPadding + sceneButtonW/2)
                    }

                }
                Spacer()
                    .frame(height: margin3)
            }

        }
        .background(Image("bg")
        .resizable()
        .edgesIgnoringSafeArea(.all)
        .aspectRatio(contentMode: .fill))
    }
}

Question: Are there any methods to disable automatic scrolling at all and use offsets at ScrollView with SwiftUI?

J A S K I E R
  • 1,976
  • 3
  • 24
  • 42
  • you can use libraries like this https://github.com/nachonavarro/Pages ...but you should give us code here (SWIFTUI) which is at least compilable....you did not even try to compile what you have posted here....please read and consider this: https://stackoverflow.com/help/how-to-ask – Chris May 01 '20 at 12:21
  • 1
    If you want to move content by offset then you don't need built-in ScrollView at all - just offset HStack. Also those posts could be helpful [How to make a SwiftUI List scroll automatically?](https://stackoverflow.com/questions/57258846/how-to-make-a-swiftui-list-scroll-automatically/58708206#58708206) and [SwiftUI: How to scroll List programmatically?](https://stackoverflow.com/questions/60855852/swiftui-how-to-scroll-list-programmatically-solution) – Asperi May 01 '20 at 13:21

1 Answers1

0

This already built solution for SwiftUI

https://github.com/fermoya/SwiftUIPager

However, there is no real example.

J A S K I E R
  • 1,976
  • 3
  • 24
  • 42