Issue in blocking Vertical scroll on UIScrollView in Swift 4.0












6















I have an Image carousel in my app I use a UIScrollView to show the images inside. everything works fine, it's just that I want to know how do I block up movements in the UIScrollView



I'm trying to block the vertical scroll by doing:



scrollView.showsVerticalScrollIndicator = false
scrollView.contentSize = CGSize(width: scrollView.contentSize.width, height: 0) //disable vertical


everything in that works fine and it really blocks the vertical scroll



The problem is,
that I also have a timer, that moves the UIScrollView programmatically by doing:



var frame: CGRect = scrollView.frame
frame.origin.x = frame.size.width * CGFloat(pageToMove)
frame.origin.y = -35
scrollView.scrollRectToVisible(frame, animated: true)


and once I block the vertical scroll,
this function to scrollReactToVisible doesn't do anything.
and I don't get any error for that.



is there a way currently to also block the scroll vertically (and allow to scroll right and left as usual) and also move the scrollview programmatically?



I'm attaching my full view controller:



class CaruselleScreenViewController: UIViewController, CaruselleScreenViewProtocol, UIScrollViewDelegate {

var myPresenter: CaruselleScreenPresenterProtocol?

@IBOutlet weak var pageControl: UIPageControl!
@IBOutlet weak var scrollView: UIScrollView!

var slides:[CaruselleTipsCard] = ;

var timer:Timer?
var currentPageMultiplayer = 0

override func viewDidLoad() {
super.viewDidLoad()

myPresenter = CaruselleScreenPresenter(controller: self)

//initlizes view
pageControl.numberOfPages = slides.count
pageControl.currentPage = 0
view.bringSubview(toFront: pageControl)

//delegates
scrollView.delegate = self

////blocks vertical movement
scrollView.showsVerticalScrollIndicator = false
//scrollView.contentSize = CGSize(width: scrollView.contentSize.width, height: 0) //disable vertical
}

func scheduleTimer(_ timeInterval: TimeInterval){
timer = Timer.scheduledTimer(timeInterval: timeInterval, target: self, selector: #selector(timerCall), userInfo: nil, repeats: false)
}

@objc func timerCall(){
print("Timer executed")

currentPageMultiplayer = currentPageMultiplayer + 1

if (currentPageMultiplayer == 5) {
currentPageMultiplayer = 0
}
pageControl.currentPage = currentPageMultiplayer
scrollToPage(pageToMove: currentPageMultiplayer)

scheduleTimer(5)
}

func scrollToPage(pageToMove: Int) {
print ("new one")
var frame: CGRect = scrollView.frame
frame.origin.x = frame.size.width * CGFloat(pageToMove)
frame.origin.y = -35
scrollView.scrollRectToVisible(frame, animated: true)
}

func createSlides() -> [CaruselleTipsCard] {

let slide1:CaruselleTipsCard = Bundle.main.loadNibNamed("CaruselleTipsCard", owner: self, options: nil)?.first as! CaruselleTipsCard
slide1.mainPic.image = UIImage(named: "backlightingIllo")

//
let slide2:CaruselleTipsCard = Bundle.main.loadNibNamed("CaruselleTipsCard", owner: self, options: nil)?.first as! CaruselleTipsCard
slide2.mainPic.image = UIImage(named: "comfortableIllo")

//
let slide3:CaruselleTipsCard = Bundle.main.loadNibNamed("CaruselleTipsCard", owner: self, options: nil)?.first as! CaruselleTipsCard
slide3.mainPic.image = UIImage(named: "pharmacyIllo")

//
let slide4:CaruselleTipsCard = Bundle.main.loadNibNamed("CaruselleTipsCard", owner: self, options: nil)?.first as! CaruselleTipsCard
slide4.mainPic.image = UIImage(named: "batteryIllo")

//
let slide5:CaruselleTipsCard = Bundle.main.loadNibNamed("CaruselleTipsCard", owner: self, options: nil)?.first as! CaruselleTipsCard
slide5.mainPic.image = UIImage(named: "wiFiIllo")

return [slide1, slide2, slide3, slide4, slide5]
}

func setupSlideScrollView(slides : [CaruselleTipsCard]) {
scrollView.frame = CGRect(x: 0, y: 0, width: view.frame.width, height: view.frame.height)
scrollView.contentSize = CGSize(width: view.frame.width * CGFloat(slides.count), height: view.frame.height)
scrollView.isPagingEnabled = true

for i in 0 ..< slides.count {
slides[i].frame = CGRect(x: view.frame.width * CGFloat(i), y: 0, width: view.frame.width, height: view.frame.height)
scrollView.addSubview(slides[i])
}
}


//////

/*
* default function called when view is scrolled. In order to enable callback
* when scrollview is scrolled, the below code needs to be called:
* slideScrollView.delegate = self or
*/
func scrollViewDidScroll(_ scrollView: UIScrollView) {
let pageIndex = round(scrollView.contentOffset.x/view.frame.width)
pageControl.currentPage = Int(pageIndex)

let maximumHorizontalOffset: CGFloat = scrollView.contentSize.width - scrollView.frame.width
let currentHorizontalOffset: CGFloat = scrollView.contentOffset.x

// vertical
let maximumVerticalOffset: CGFloat = scrollView.contentSize.height - scrollView.frame.height
let currentVerticalOffset: CGFloat = scrollView.contentOffset.y

let percentageHorizontalOffset: CGFloat = currentHorizontalOffset / maximumHorizontalOffset
let percentageVerticalOffset: CGFloat = currentVerticalOffset / maximumVerticalOffset


/*
* below code changes the background color of view on paging the scrollview
*/
// self.scrollView(scrollView, didScrollToPercentageOffset: percentageHorizontalOffset)


/*
* below code scales the imageview on paging the scrollview
*/
let percentOffset: CGPoint = CGPoint(x: percentageHorizontalOffset, y: percentageVerticalOffset)

if(percentOffset.x > 0 && percentOffset.x <= 0.25) {

slides[0].mainPic.transform = CGAffineTransform(scaleX: (0.25-percentOffset.x)/0.25, y: (0.25-percentOffset.x)/0.25)
slides[1].mainPic.transform = CGAffineTransform(scaleX: percentOffset.x/0.25, y: percentOffset.x/0.25)

} else if(percentOffset.x > 0.25 && percentOffset.x <= 0.50) {
slides[1].mainPic.transform = CGAffineTransform(scaleX: (0.50-percentOffset.x)/0.25, y: (0.50-percentOffset.x)/0.25)
slides[2].mainPic.transform = CGAffineTransform(scaleX: percentOffset.x/0.50, y: percentOffset.x/0.50)

} else if(percentOffset.x > 0.50 && percentOffset.x <= 0.75) {
slides[2].mainPic.transform = CGAffineTransform(scaleX: (0.75-percentOffset.x)/0.25, y: (0.75-percentOffset.x)/0.25)
slides[3].mainPic.transform = CGAffineTransform(scaleX: percentOffset.x/0.75, y: percentOffset.x/0.75)

} else if(percentOffset.x > 0.75 && percentOffset.x <= 1) {
slides[3].mainPic.transform = CGAffineTransform(scaleX: (1-percentOffset.x)/0.25, y: (1-percentOffset.x)/0.25)
slides[4].mainPic.transform = CGAffineTransform(scaleX: percentOffset.x, y: percentOffset.x)
}
}

override func prepare(for segue: UIStoryboardSegue, sender: Any?) {
if segue.identifier == "findingClinitionSugue" {
let destination = segue.destination as! FirstAvailableSearchViewController
//destination.consumer = consumer
}

if (timer != nil) {
timer?.invalidate()
}
}

// protocol functions

func initlizeSlides() {
slides = createSlides()
setupSlideScrollView(slides: slides)
}

func initlizeTimer() {
scheduleTimer(5)
}
}









share|improve this question





























    6















    I have an Image carousel in my app I use a UIScrollView to show the images inside. everything works fine, it's just that I want to know how do I block up movements in the UIScrollView



    I'm trying to block the vertical scroll by doing:



    scrollView.showsVerticalScrollIndicator = false
    scrollView.contentSize = CGSize(width: scrollView.contentSize.width, height: 0) //disable vertical


    everything in that works fine and it really blocks the vertical scroll



    The problem is,
    that I also have a timer, that moves the UIScrollView programmatically by doing:



    var frame: CGRect = scrollView.frame
    frame.origin.x = frame.size.width * CGFloat(pageToMove)
    frame.origin.y = -35
    scrollView.scrollRectToVisible(frame, animated: true)


    and once I block the vertical scroll,
    this function to scrollReactToVisible doesn't do anything.
    and I don't get any error for that.



    is there a way currently to also block the scroll vertically (and allow to scroll right and left as usual) and also move the scrollview programmatically?



    I'm attaching my full view controller:



    class CaruselleScreenViewController: UIViewController, CaruselleScreenViewProtocol, UIScrollViewDelegate {

    var myPresenter: CaruselleScreenPresenterProtocol?

    @IBOutlet weak var pageControl: UIPageControl!
    @IBOutlet weak var scrollView: UIScrollView!

    var slides:[CaruselleTipsCard] = ;

    var timer:Timer?
    var currentPageMultiplayer = 0

    override func viewDidLoad() {
    super.viewDidLoad()

    myPresenter = CaruselleScreenPresenter(controller: self)

    //initlizes view
    pageControl.numberOfPages = slides.count
    pageControl.currentPage = 0
    view.bringSubview(toFront: pageControl)

    //delegates
    scrollView.delegate = self

    ////blocks vertical movement
    scrollView.showsVerticalScrollIndicator = false
    //scrollView.contentSize = CGSize(width: scrollView.contentSize.width, height: 0) //disable vertical
    }

    func scheduleTimer(_ timeInterval: TimeInterval){
    timer = Timer.scheduledTimer(timeInterval: timeInterval, target: self, selector: #selector(timerCall), userInfo: nil, repeats: false)
    }

    @objc func timerCall(){
    print("Timer executed")

    currentPageMultiplayer = currentPageMultiplayer + 1

    if (currentPageMultiplayer == 5) {
    currentPageMultiplayer = 0
    }
    pageControl.currentPage = currentPageMultiplayer
    scrollToPage(pageToMove: currentPageMultiplayer)

    scheduleTimer(5)
    }

    func scrollToPage(pageToMove: Int) {
    print ("new one")
    var frame: CGRect = scrollView.frame
    frame.origin.x = frame.size.width * CGFloat(pageToMove)
    frame.origin.y = -35
    scrollView.scrollRectToVisible(frame, animated: true)
    }

    func createSlides() -> [CaruselleTipsCard] {

    let slide1:CaruselleTipsCard = Bundle.main.loadNibNamed("CaruselleTipsCard", owner: self, options: nil)?.first as! CaruselleTipsCard
    slide1.mainPic.image = UIImage(named: "backlightingIllo")

    //
    let slide2:CaruselleTipsCard = Bundle.main.loadNibNamed("CaruselleTipsCard", owner: self, options: nil)?.first as! CaruselleTipsCard
    slide2.mainPic.image = UIImage(named: "comfortableIllo")

    //
    let slide3:CaruselleTipsCard = Bundle.main.loadNibNamed("CaruselleTipsCard", owner: self, options: nil)?.first as! CaruselleTipsCard
    slide3.mainPic.image = UIImage(named: "pharmacyIllo")

    //
    let slide4:CaruselleTipsCard = Bundle.main.loadNibNamed("CaruselleTipsCard", owner: self, options: nil)?.first as! CaruselleTipsCard
    slide4.mainPic.image = UIImage(named: "batteryIllo")

    //
    let slide5:CaruselleTipsCard = Bundle.main.loadNibNamed("CaruselleTipsCard", owner: self, options: nil)?.first as! CaruselleTipsCard
    slide5.mainPic.image = UIImage(named: "wiFiIllo")

    return [slide1, slide2, slide3, slide4, slide5]
    }

    func setupSlideScrollView(slides : [CaruselleTipsCard]) {
    scrollView.frame = CGRect(x: 0, y: 0, width: view.frame.width, height: view.frame.height)
    scrollView.contentSize = CGSize(width: view.frame.width * CGFloat(slides.count), height: view.frame.height)
    scrollView.isPagingEnabled = true

    for i in 0 ..< slides.count {
    slides[i].frame = CGRect(x: view.frame.width * CGFloat(i), y: 0, width: view.frame.width, height: view.frame.height)
    scrollView.addSubview(slides[i])
    }
    }


    //////

    /*
    * default function called when view is scrolled. In order to enable callback
    * when scrollview is scrolled, the below code needs to be called:
    * slideScrollView.delegate = self or
    */
    func scrollViewDidScroll(_ scrollView: UIScrollView) {
    let pageIndex = round(scrollView.contentOffset.x/view.frame.width)
    pageControl.currentPage = Int(pageIndex)

    let maximumHorizontalOffset: CGFloat = scrollView.contentSize.width - scrollView.frame.width
    let currentHorizontalOffset: CGFloat = scrollView.contentOffset.x

    // vertical
    let maximumVerticalOffset: CGFloat = scrollView.contentSize.height - scrollView.frame.height
    let currentVerticalOffset: CGFloat = scrollView.contentOffset.y

    let percentageHorizontalOffset: CGFloat = currentHorizontalOffset / maximumHorizontalOffset
    let percentageVerticalOffset: CGFloat = currentVerticalOffset / maximumVerticalOffset


    /*
    * below code changes the background color of view on paging the scrollview
    */
    // self.scrollView(scrollView, didScrollToPercentageOffset: percentageHorizontalOffset)


    /*
    * below code scales the imageview on paging the scrollview
    */
    let percentOffset: CGPoint = CGPoint(x: percentageHorizontalOffset, y: percentageVerticalOffset)

    if(percentOffset.x > 0 && percentOffset.x <= 0.25) {

    slides[0].mainPic.transform = CGAffineTransform(scaleX: (0.25-percentOffset.x)/0.25, y: (0.25-percentOffset.x)/0.25)
    slides[1].mainPic.transform = CGAffineTransform(scaleX: percentOffset.x/0.25, y: percentOffset.x/0.25)

    } else if(percentOffset.x > 0.25 && percentOffset.x <= 0.50) {
    slides[1].mainPic.transform = CGAffineTransform(scaleX: (0.50-percentOffset.x)/0.25, y: (0.50-percentOffset.x)/0.25)
    slides[2].mainPic.transform = CGAffineTransform(scaleX: percentOffset.x/0.50, y: percentOffset.x/0.50)

    } else if(percentOffset.x > 0.50 && percentOffset.x <= 0.75) {
    slides[2].mainPic.transform = CGAffineTransform(scaleX: (0.75-percentOffset.x)/0.25, y: (0.75-percentOffset.x)/0.25)
    slides[3].mainPic.transform = CGAffineTransform(scaleX: percentOffset.x/0.75, y: percentOffset.x/0.75)

    } else if(percentOffset.x > 0.75 && percentOffset.x <= 1) {
    slides[3].mainPic.transform = CGAffineTransform(scaleX: (1-percentOffset.x)/0.25, y: (1-percentOffset.x)/0.25)
    slides[4].mainPic.transform = CGAffineTransform(scaleX: percentOffset.x, y: percentOffset.x)
    }
    }

    override func prepare(for segue: UIStoryboardSegue, sender: Any?) {
    if segue.identifier == "findingClinitionSugue" {
    let destination = segue.destination as! FirstAvailableSearchViewController
    //destination.consumer = consumer
    }

    if (timer != nil) {
    timer?.invalidate()
    }
    }

    // protocol functions

    func initlizeSlides() {
    slides = createSlides()
    setupSlideScrollView(slides: slides)
    }

    func initlizeTimer() {
    scheduleTimer(5)
    }
    }









    share|improve this question



























      6












      6








      6








      I have an Image carousel in my app I use a UIScrollView to show the images inside. everything works fine, it's just that I want to know how do I block up movements in the UIScrollView



      I'm trying to block the vertical scroll by doing:



      scrollView.showsVerticalScrollIndicator = false
      scrollView.contentSize = CGSize(width: scrollView.contentSize.width, height: 0) //disable vertical


      everything in that works fine and it really blocks the vertical scroll



      The problem is,
      that I also have a timer, that moves the UIScrollView programmatically by doing:



      var frame: CGRect = scrollView.frame
      frame.origin.x = frame.size.width * CGFloat(pageToMove)
      frame.origin.y = -35
      scrollView.scrollRectToVisible(frame, animated: true)


      and once I block the vertical scroll,
      this function to scrollReactToVisible doesn't do anything.
      and I don't get any error for that.



      is there a way currently to also block the scroll vertically (and allow to scroll right and left as usual) and also move the scrollview programmatically?



      I'm attaching my full view controller:



      class CaruselleScreenViewController: UIViewController, CaruselleScreenViewProtocol, UIScrollViewDelegate {

      var myPresenter: CaruselleScreenPresenterProtocol?

      @IBOutlet weak var pageControl: UIPageControl!
      @IBOutlet weak var scrollView: UIScrollView!

      var slides:[CaruselleTipsCard] = ;

      var timer:Timer?
      var currentPageMultiplayer = 0

      override func viewDidLoad() {
      super.viewDidLoad()

      myPresenter = CaruselleScreenPresenter(controller: self)

      //initlizes view
      pageControl.numberOfPages = slides.count
      pageControl.currentPage = 0
      view.bringSubview(toFront: pageControl)

      //delegates
      scrollView.delegate = self

      ////blocks vertical movement
      scrollView.showsVerticalScrollIndicator = false
      //scrollView.contentSize = CGSize(width: scrollView.contentSize.width, height: 0) //disable vertical
      }

      func scheduleTimer(_ timeInterval: TimeInterval){
      timer = Timer.scheduledTimer(timeInterval: timeInterval, target: self, selector: #selector(timerCall), userInfo: nil, repeats: false)
      }

      @objc func timerCall(){
      print("Timer executed")

      currentPageMultiplayer = currentPageMultiplayer + 1

      if (currentPageMultiplayer == 5) {
      currentPageMultiplayer = 0
      }
      pageControl.currentPage = currentPageMultiplayer
      scrollToPage(pageToMove: currentPageMultiplayer)

      scheduleTimer(5)
      }

      func scrollToPage(pageToMove: Int) {
      print ("new one")
      var frame: CGRect = scrollView.frame
      frame.origin.x = frame.size.width * CGFloat(pageToMove)
      frame.origin.y = -35
      scrollView.scrollRectToVisible(frame, animated: true)
      }

      func createSlides() -> [CaruselleTipsCard] {

      let slide1:CaruselleTipsCard = Bundle.main.loadNibNamed("CaruselleTipsCard", owner: self, options: nil)?.first as! CaruselleTipsCard
      slide1.mainPic.image = UIImage(named: "backlightingIllo")

      //
      let slide2:CaruselleTipsCard = Bundle.main.loadNibNamed("CaruselleTipsCard", owner: self, options: nil)?.first as! CaruselleTipsCard
      slide2.mainPic.image = UIImage(named: "comfortableIllo")

      //
      let slide3:CaruselleTipsCard = Bundle.main.loadNibNamed("CaruselleTipsCard", owner: self, options: nil)?.first as! CaruselleTipsCard
      slide3.mainPic.image = UIImage(named: "pharmacyIllo")

      //
      let slide4:CaruselleTipsCard = Bundle.main.loadNibNamed("CaruselleTipsCard", owner: self, options: nil)?.first as! CaruselleTipsCard
      slide4.mainPic.image = UIImage(named: "batteryIllo")

      //
      let slide5:CaruselleTipsCard = Bundle.main.loadNibNamed("CaruselleTipsCard", owner: self, options: nil)?.first as! CaruselleTipsCard
      slide5.mainPic.image = UIImage(named: "wiFiIllo")

      return [slide1, slide2, slide3, slide4, slide5]
      }

      func setupSlideScrollView(slides : [CaruselleTipsCard]) {
      scrollView.frame = CGRect(x: 0, y: 0, width: view.frame.width, height: view.frame.height)
      scrollView.contentSize = CGSize(width: view.frame.width * CGFloat(slides.count), height: view.frame.height)
      scrollView.isPagingEnabled = true

      for i in 0 ..< slides.count {
      slides[i].frame = CGRect(x: view.frame.width * CGFloat(i), y: 0, width: view.frame.width, height: view.frame.height)
      scrollView.addSubview(slides[i])
      }
      }


      //////

      /*
      * default function called when view is scrolled. In order to enable callback
      * when scrollview is scrolled, the below code needs to be called:
      * slideScrollView.delegate = self or
      */
      func scrollViewDidScroll(_ scrollView: UIScrollView) {
      let pageIndex = round(scrollView.contentOffset.x/view.frame.width)
      pageControl.currentPage = Int(pageIndex)

      let maximumHorizontalOffset: CGFloat = scrollView.contentSize.width - scrollView.frame.width
      let currentHorizontalOffset: CGFloat = scrollView.contentOffset.x

      // vertical
      let maximumVerticalOffset: CGFloat = scrollView.contentSize.height - scrollView.frame.height
      let currentVerticalOffset: CGFloat = scrollView.contentOffset.y

      let percentageHorizontalOffset: CGFloat = currentHorizontalOffset / maximumHorizontalOffset
      let percentageVerticalOffset: CGFloat = currentVerticalOffset / maximumVerticalOffset


      /*
      * below code changes the background color of view on paging the scrollview
      */
      // self.scrollView(scrollView, didScrollToPercentageOffset: percentageHorizontalOffset)


      /*
      * below code scales the imageview on paging the scrollview
      */
      let percentOffset: CGPoint = CGPoint(x: percentageHorizontalOffset, y: percentageVerticalOffset)

      if(percentOffset.x > 0 && percentOffset.x <= 0.25) {

      slides[0].mainPic.transform = CGAffineTransform(scaleX: (0.25-percentOffset.x)/0.25, y: (0.25-percentOffset.x)/0.25)
      slides[1].mainPic.transform = CGAffineTransform(scaleX: percentOffset.x/0.25, y: percentOffset.x/0.25)

      } else if(percentOffset.x > 0.25 && percentOffset.x <= 0.50) {
      slides[1].mainPic.transform = CGAffineTransform(scaleX: (0.50-percentOffset.x)/0.25, y: (0.50-percentOffset.x)/0.25)
      slides[2].mainPic.transform = CGAffineTransform(scaleX: percentOffset.x/0.50, y: percentOffset.x/0.50)

      } else if(percentOffset.x > 0.50 && percentOffset.x <= 0.75) {
      slides[2].mainPic.transform = CGAffineTransform(scaleX: (0.75-percentOffset.x)/0.25, y: (0.75-percentOffset.x)/0.25)
      slides[3].mainPic.transform = CGAffineTransform(scaleX: percentOffset.x/0.75, y: percentOffset.x/0.75)

      } else if(percentOffset.x > 0.75 && percentOffset.x <= 1) {
      slides[3].mainPic.transform = CGAffineTransform(scaleX: (1-percentOffset.x)/0.25, y: (1-percentOffset.x)/0.25)
      slides[4].mainPic.transform = CGAffineTransform(scaleX: percentOffset.x, y: percentOffset.x)
      }
      }

      override func prepare(for segue: UIStoryboardSegue, sender: Any?) {
      if segue.identifier == "findingClinitionSugue" {
      let destination = segue.destination as! FirstAvailableSearchViewController
      //destination.consumer = consumer
      }

      if (timer != nil) {
      timer?.invalidate()
      }
      }

      // protocol functions

      func initlizeSlides() {
      slides = createSlides()
      setupSlideScrollView(slides: slides)
      }

      func initlizeTimer() {
      scheduleTimer(5)
      }
      }









      share|improve this question
















      I have an Image carousel in my app I use a UIScrollView to show the images inside. everything works fine, it's just that I want to know how do I block up movements in the UIScrollView



      I'm trying to block the vertical scroll by doing:



      scrollView.showsVerticalScrollIndicator = false
      scrollView.contentSize = CGSize(width: scrollView.contentSize.width, height: 0) //disable vertical


      everything in that works fine and it really blocks the vertical scroll



      The problem is,
      that I also have a timer, that moves the UIScrollView programmatically by doing:



      var frame: CGRect = scrollView.frame
      frame.origin.x = frame.size.width * CGFloat(pageToMove)
      frame.origin.y = -35
      scrollView.scrollRectToVisible(frame, animated: true)


      and once I block the vertical scroll,
      this function to scrollReactToVisible doesn't do anything.
      and I don't get any error for that.



      is there a way currently to also block the scroll vertically (and allow to scroll right and left as usual) and also move the scrollview programmatically?



      I'm attaching my full view controller:



      class CaruselleScreenViewController: UIViewController, CaruselleScreenViewProtocol, UIScrollViewDelegate {

      var myPresenter: CaruselleScreenPresenterProtocol?

      @IBOutlet weak var pageControl: UIPageControl!
      @IBOutlet weak var scrollView: UIScrollView!

      var slides:[CaruselleTipsCard] = ;

      var timer:Timer?
      var currentPageMultiplayer = 0

      override func viewDidLoad() {
      super.viewDidLoad()

      myPresenter = CaruselleScreenPresenter(controller: self)

      //initlizes view
      pageControl.numberOfPages = slides.count
      pageControl.currentPage = 0
      view.bringSubview(toFront: pageControl)

      //delegates
      scrollView.delegate = self

      ////blocks vertical movement
      scrollView.showsVerticalScrollIndicator = false
      //scrollView.contentSize = CGSize(width: scrollView.contentSize.width, height: 0) //disable vertical
      }

      func scheduleTimer(_ timeInterval: TimeInterval){
      timer = Timer.scheduledTimer(timeInterval: timeInterval, target: self, selector: #selector(timerCall), userInfo: nil, repeats: false)
      }

      @objc func timerCall(){
      print("Timer executed")

      currentPageMultiplayer = currentPageMultiplayer + 1

      if (currentPageMultiplayer == 5) {
      currentPageMultiplayer = 0
      }
      pageControl.currentPage = currentPageMultiplayer
      scrollToPage(pageToMove: currentPageMultiplayer)

      scheduleTimer(5)
      }

      func scrollToPage(pageToMove: Int) {
      print ("new one")
      var frame: CGRect = scrollView.frame
      frame.origin.x = frame.size.width * CGFloat(pageToMove)
      frame.origin.y = -35
      scrollView.scrollRectToVisible(frame, animated: true)
      }

      func createSlides() -> [CaruselleTipsCard] {

      let slide1:CaruselleTipsCard = Bundle.main.loadNibNamed("CaruselleTipsCard", owner: self, options: nil)?.first as! CaruselleTipsCard
      slide1.mainPic.image = UIImage(named: "backlightingIllo")

      //
      let slide2:CaruselleTipsCard = Bundle.main.loadNibNamed("CaruselleTipsCard", owner: self, options: nil)?.first as! CaruselleTipsCard
      slide2.mainPic.image = UIImage(named: "comfortableIllo")

      //
      let slide3:CaruselleTipsCard = Bundle.main.loadNibNamed("CaruselleTipsCard", owner: self, options: nil)?.first as! CaruselleTipsCard
      slide3.mainPic.image = UIImage(named: "pharmacyIllo")

      //
      let slide4:CaruselleTipsCard = Bundle.main.loadNibNamed("CaruselleTipsCard", owner: self, options: nil)?.first as! CaruselleTipsCard
      slide4.mainPic.image = UIImage(named: "batteryIllo")

      //
      let slide5:CaruselleTipsCard = Bundle.main.loadNibNamed("CaruselleTipsCard", owner: self, options: nil)?.first as! CaruselleTipsCard
      slide5.mainPic.image = UIImage(named: "wiFiIllo")

      return [slide1, slide2, slide3, slide4, slide5]
      }

      func setupSlideScrollView(slides : [CaruselleTipsCard]) {
      scrollView.frame = CGRect(x: 0, y: 0, width: view.frame.width, height: view.frame.height)
      scrollView.contentSize = CGSize(width: view.frame.width * CGFloat(slides.count), height: view.frame.height)
      scrollView.isPagingEnabled = true

      for i in 0 ..< slides.count {
      slides[i].frame = CGRect(x: view.frame.width * CGFloat(i), y: 0, width: view.frame.width, height: view.frame.height)
      scrollView.addSubview(slides[i])
      }
      }


      //////

      /*
      * default function called when view is scrolled. In order to enable callback
      * when scrollview is scrolled, the below code needs to be called:
      * slideScrollView.delegate = self or
      */
      func scrollViewDidScroll(_ scrollView: UIScrollView) {
      let pageIndex = round(scrollView.contentOffset.x/view.frame.width)
      pageControl.currentPage = Int(pageIndex)

      let maximumHorizontalOffset: CGFloat = scrollView.contentSize.width - scrollView.frame.width
      let currentHorizontalOffset: CGFloat = scrollView.contentOffset.x

      // vertical
      let maximumVerticalOffset: CGFloat = scrollView.contentSize.height - scrollView.frame.height
      let currentVerticalOffset: CGFloat = scrollView.contentOffset.y

      let percentageHorizontalOffset: CGFloat = currentHorizontalOffset / maximumHorizontalOffset
      let percentageVerticalOffset: CGFloat = currentVerticalOffset / maximumVerticalOffset


      /*
      * below code changes the background color of view on paging the scrollview
      */
      // self.scrollView(scrollView, didScrollToPercentageOffset: percentageHorizontalOffset)


      /*
      * below code scales the imageview on paging the scrollview
      */
      let percentOffset: CGPoint = CGPoint(x: percentageHorizontalOffset, y: percentageVerticalOffset)

      if(percentOffset.x > 0 && percentOffset.x <= 0.25) {

      slides[0].mainPic.transform = CGAffineTransform(scaleX: (0.25-percentOffset.x)/0.25, y: (0.25-percentOffset.x)/0.25)
      slides[1].mainPic.transform = CGAffineTransform(scaleX: percentOffset.x/0.25, y: percentOffset.x/0.25)

      } else if(percentOffset.x > 0.25 && percentOffset.x <= 0.50) {
      slides[1].mainPic.transform = CGAffineTransform(scaleX: (0.50-percentOffset.x)/0.25, y: (0.50-percentOffset.x)/0.25)
      slides[2].mainPic.transform = CGAffineTransform(scaleX: percentOffset.x/0.50, y: percentOffset.x/0.50)

      } else if(percentOffset.x > 0.50 && percentOffset.x <= 0.75) {
      slides[2].mainPic.transform = CGAffineTransform(scaleX: (0.75-percentOffset.x)/0.25, y: (0.75-percentOffset.x)/0.25)
      slides[3].mainPic.transform = CGAffineTransform(scaleX: percentOffset.x/0.75, y: percentOffset.x/0.75)

      } else if(percentOffset.x > 0.75 && percentOffset.x <= 1) {
      slides[3].mainPic.transform = CGAffineTransform(scaleX: (1-percentOffset.x)/0.25, y: (1-percentOffset.x)/0.25)
      slides[4].mainPic.transform = CGAffineTransform(scaleX: percentOffset.x, y: percentOffset.x)
      }
      }

      override func prepare(for segue: UIStoryboardSegue, sender: Any?) {
      if segue.identifier == "findingClinitionSugue" {
      let destination = segue.destination as! FirstAvailableSearchViewController
      //destination.consumer = consumer
      }

      if (timer != nil) {
      timer?.invalidate()
      }
      }

      // protocol functions

      func initlizeSlides() {
      slides = createSlides()
      setupSlideScrollView(slides: slides)
      }

      func initlizeTimer() {
      scheduleTimer(5)
      }
      }






      swift xcode uiscrollview






      share|improve this question















      share|improve this question













      share|improve this question




      share|improve this question








      edited Jan 23 at 2:35









      Cœur

      18k9108148




      18k9108148










      asked Dec 31 '18 at 9:29









      Chief MadogChief Madog

      5551926




      5551926
























          6 Answers
          6






          active

          oldest

          votes


















          0














          The problem might be about setting the contentSize height value to 0 initally, so even though timer wants scrollView to move, it cannot do that.



          Can you try replacing this line:



          scrollView.contentSize = CGSize(width: scrollView.contentSize.width, height: 0)


          With:



          scrollView.contentInsetAdjustmentBehavior = .never





          share|improve this answer
























          • this doesn't block the vertical movement, i tried it now, i can still swipe up

            – Chief Madog
            Dec 31 '18 at 14:28





















          0














          Depending the application and functionality required within the scrollview - could you disable user interaction of the scrollview so it can still be moved programmatically?



          That would just be



          scrollView.isUserInteractionEnabled = false


          This would of course depend on whether you need items in the scrollview to be interactive






          share|improve this answer
























          • this just blocks the swipe all together, what i need is swipe enabled, and ALSO programmatically moved, just the vertical blocked

            – Chief Madog
            Jan 1 at 8:01











          • At the risk of it being a bit of a workaround rather than a solution; you could try unblocking the vertical movement when the timer is called then blocking the vertical scroll again when it has finished programmatically scrolling. You could avoid any unwanted behaviour by also temporarily disabling user interaction at the same time as removing the vertical block (and re-enabling once it’s finished scrolling programmatically)

            – Joe L
            Jan 1 at 11:23



















          0














          Maybe you can subclass your UIScrollView, and override touchesBegan.



          class CustomScrollView: UIScrollView {

          var touchesDisabled = false
          override func touchesBegan(_ touches: Set<UITouch>, with event: UIEvent?) {
          if touchesDisabled {
          // here parse the touches, if they go in the horizontal direction, allow scrolling
          // set tolerance for vertical movement
          let tolerance: CGFloat = 5.0
          let variance = touches.reduce(0, { Yvariation, touch in
          Yvariation + abs(touch.location(in: view).y - touch.previousLocation(in: view).y)
          })
          if variance <= tolerance * CGFloat(touches.count) {
          let Xtravelled = touches.reduce(0, { Xstep, touch in
          Xstep + (touch.location(in: view).x - touch.previousLocation(in: view).x)
          })
          // scroll horizontally by the x component of hand gesture
          var newFrame: CGRect = scrollView.frame
          newFrame.origin.x += Xtravelled
          self.scrollRectToVisible(frame, animated: true)
          }
          }

          else {
          super.touchesBegan(touches: touches, withEvent: event)
          }
          }
          }


          This way you can manually move the scrollview horizontally while disabling vertical movement when touchesDisabled is set true.






          share|improve this answer































            0














            If I've understood you problem well, you can stop scrolling whenever you want with this



            scrollView.isScrollEnabled = false





            share|improve this answer































              0














              Using UIScrollViewDelegate (or KVO on scrollView's contentOffset), you can just counteract any vertical movement in the carousel. Something like this:



              var oldYOffset: CGFloat ....

              func scrollViewDidScroll(_ scrollView: UIScrollView) {
              let deltaY = oldYOffset - scrollView.contentOffset.y
              oldYOffset = scrollView.contentOffset.y
              scrollView.contentOffset.y -= deltaY
              }


              This offset change will not be visible to the user. You could even use this to increase the speed of the scrolling, invert the scrolling (pan left and scrollView scrolls right), or entirely lock the motion of the scrollView without touching isScrollEnabled, contentSize, etc.






              share|improve this answer































                0














                This turned out to be quite an interesting problem...



                While it is easy to lock UIScrollView scrolling to one axis only using the UIScrollViewDelegate, it is impossible to provide smooth scrolling while changing the scrolling programmatically (as you do with the Timer) at the same time.



                Below, you will find a DirectionLockingScrollView class I just wrote that should make things easier for you. It's a UIScrollView that you can initialize either programmatically, or via the Interface Builder.



                It features isHorizontalScrollingEnabled and isVerticalScrollingEnabled properties.



                HOW IT WORKS INTERNALLY



                It adds a second "control" UIScrollView that is identical to the main DirectionLockingScrollView and propagates to it all pan events intended for the main scroll view. Every time the "control" scroll view's bounds change, the change is propagated to the main scroll view BUT x and y are altered (based on isHorizontalScrollingEnabled and isVerticalScrollingEnabled) to disable scrolling on the requested axis.



                DirectionLockingScrollView.swift



                /// `UIScrollView` subclass that supports disabling scrolling on any direction
                /// while allowing the other direction to be changed programmatically (via
                /// `setContentOffset(_:animated)` or `scrollRectToVisible(_:animated)` or changing the
                /// bounds etc.
                ///
                /// Can be initialized programmatically or via the Interface Builder.
                class DirectionLockingScrollView: UIScrollView {
                var isHorizontalScrollingEnabled = true
                var isVerticalScrollingEnabled = true

                /// The control scrollview is added below the `DirectionLockingScrollView`
                /// and is used to implement all native scrollview behaviours (such as bouncing)
                /// based on user input.
                ///
                /// It is required to be able to change the bounds of the `DirectionLockingScrollView`
                /// while maintaining scrolling in only one direction and allowing for setting the contentOffset
                /// (changing scrolling for any axis - even the disabled ones) programmatically.
                private let _controlScrollView = UIScrollView(frame: .zero)

                required init?(coder aDecoder: NSCoder) {
                super.init(coder: aDecoder)
                installCustomScrollView()
                }

                override init(frame: CGRect) {
                super.init(frame: frame)
                installCustomScrollView()
                }

                override func layoutSubviews() {
                super.layoutSubviews()
                updateCustomScrollViewFrame()
                }

                override func didMoveToSuperview() {
                super.didMoveToSuperview()
                guard let superview = superview else {
                _controlScrollView.removeFromSuperview()
                return
                }

                superview.insertSubview(_controlScrollView, belowSubview: self)
                updateCustomScrollViewFrame()
                }

                // MARK: - UIEvent propagation

                func viewIgnoresEvents(_ view: UIView?) -> Bool {
                let viewIgnoresEvents =
                view == nil ||
                view == self ||
                !view!.isUserInteractionEnabled ||
                !(view is UIControl && (view!.gestureRecognizers ?? ).count == 0)

                return viewIgnoresEvents
                }

                override func hitTest(_ point: CGPoint, with event: UIEvent?) -> UIView? {
                let view = super.hitTest(point, with: event)
                if viewIgnoresEvents(view) {
                return _controlScrollView
                }

                return view
                }

                // MARK: - Main scrollview settings propagation to `controlScrollView`

                override var contentInset: UIEdgeInsets {
                didSet {
                _controlScrollView.contentInset = contentInset
                }
                }

                override var contentScaleFactor: CGFloat {
                didSet {
                _controlScrollView.contentScaleFactor = contentScaleFactor
                }
                }

                override var contentSize: CGSize {
                didSet {
                _controlScrollView.contentSize = contentSize
                }
                }

                override var bounces: Bool {
                didSet {
                _controlScrollView.bounces = bounces
                }
                }

                override var bouncesZoom: Bool {
                didSet {
                _controlScrollView.bouncesZoom = bouncesZoom
                }
                }
                }

                extension DirectionLockingScrollView: UIScrollViewDelegate {
                func scrollViewDidScroll(_ scrollView: UIScrollView) {
                updateBoundsFromCustomScrollView(scrollView)
                }
                }

                private extension DirectionLockingScrollView {
                /// Propagates `controlScrollView` bounds to the actual scrollview.
                /// - Parameter scrollView: If the scrollview provided is not the `controlScrollView`
                // the main scrollview bounds are not updated.
                func updateBoundsFromCustomScrollView(_ scrollView: UIScrollView) {
                if scrollView != _controlScrollView {
                return
                }

                var newBounds = scrollView.bounds.origin
                if !isHorizontalScrollingEnabled {
                newBounds.x = self.contentOffset.x
                }

                if !isVerticalScrollingEnabled {
                newBounds.y = self.contentOffset.y
                }

                bounds.origin = newBounds
                }

                func installCustomScrollView() {
                _controlScrollView.delegate = self
                _controlScrollView.contentSize = contentSize
                _controlScrollView.showsVerticalScrollIndicator = false
                _controlScrollView.showsHorizontalScrollIndicator = false

                // The panGestureRecognizer is removed because pan gestures might be triggered
                // on subviews of the scrollview which do not ignore touch events (determined
                // by `viewIgnoresEvents(_ view: UIView?)`). This can happen for example
                // if you tap and drag on a button inside the scroll view.
                removeGestureRecognizer(panGestureRecognizer)
                }

                func updateCustomScrollViewFrame() {
                if _controlScrollView.frame == frame { return }
                _controlScrollView.frame = frame
                }
                }


                USAGE



                After you've included the above class in your app, don't forget to change your scroll view's class to DirectionLockingScrollView in your .xib or .storyboard.



                Then update your code as below (only two lines changed, marked with // *****).



                class CaruselleScreenViewController: UIViewController, CaruselleScreenViewProtocol, UIScrollViewDelegate {
                var myPresenter: CaruselleScreenPresenterProtocol?

                @IBOutlet weak var pageControl: UIPageControl!
                @IBOutlet weak var scrollView: DirectionLockingScrollView! // *****

                var slides:[CaruselleTipsCard] = ;


                var timer:Timer?
                var currentPageMultiplayer = 0

                override func viewDidLoad() {
                super.viewDidLoad()

                myPresenter = CaruselleScreenPresenter(controller: self)

                //initlizes view
                pageControl.numberOfPages = slides.count
                pageControl.currentPage = 0
                view.bringSubview(toFront: pageControl)

                scrollView.isHorizontalScrollingEnabled = false // *****

                //delegates
                scrollView.delegate = self

                ////blocks vertical movement
                scrollView.showsVerticalScrollIndicator = false
                //scrollView.contentSize = CGSize(width: scrollView.contentSize.width, height: 0) //disable vertical
                }

                func scheduleTimer(_ timeInterval: TimeInterval){
                timer = Timer.scheduledTimer(timeInterval: timeInterval, target: self, selector: #selector(timerCall), userInfo: nil, repeats: false)
                }

                @objc func timerCall(){
                print("Timer executed")

                currentPageMultiplayer = currentPageMultiplayer + 1

                if (currentPageMultiplayer == 5) {
                currentPageMultiplayer = 0
                }
                pageControl.currentPage = currentPageMultiplayer
                scrollToPage(pageToMove: currentPageMultiplayer)

                scheduleTimer(5)
                }

                func scrollToPage(pageToMove: Int) {
                print ("new one")
                var frame: CGRect = scrollView.frame
                frame.origin.x = frame.size.width * CGFloat(pageToMove)
                frame.origin.y = -35
                scrollView.scrollRectToVisible(frame, animated: true)
                }


                func createSlides() -> [CaruselleTipsCard] {

                let slide1:CaruselleTipsCard = Bundle.main.loadNibNamed("CaruselleTipsCard", owner: self, options: nil)?.first as! CaruselleTipsCard
                slide1.mainPic.image = UIImage(named: "backlightingIllo")

                //
                let slide2:CaruselleTipsCard = Bundle.main.loadNibNamed("CaruselleTipsCard", owner: self, options: nil)?.first as! CaruselleTipsCard
                slide2.mainPic.image = UIImage(named: "comfortableIllo")

                //
                let slide3:CaruselleTipsCard = Bundle.main.loadNibNamed("CaruselleTipsCard", owner: self, options: nil)?.first as! CaruselleTipsCard
                slide3.mainPic.image = UIImage(named: "pharmacyIllo")

                //
                let slide4:CaruselleTipsCard = Bundle.main.loadNibNamed("CaruselleTipsCard", owner: self, options: nil)?.first as! CaruselleTipsCard
                slide4.mainPic.image = UIImage(named: "batteryIllo")

                //
                let slide5:CaruselleTipsCard = Bundle.main.loadNibNamed("CaruselleTipsCard", owner: self, options: nil)?.first as! CaruselleTipsCard
                slide5.mainPic.image = UIImage(named: "wiFiIllo")

                return [slide1, slide2, slide3, slide4, slide5]
                }

                func setupSlideScrollView(slides : [CaruselleTipsCard]) {
                scrollView.frame = CGRect(x: 0, y: 0, width: view.frame.width, height: view.frame.height)
                scrollView.contentSize = CGSize(width: view.frame.width * CGFloat(slides.count), height: view.frame.height)
                scrollView.isPagingEnabled = true

                for i in 0 ..< slides.count {
                slides[i].frame = CGRect(x: view.frame.width * CGFloat(i), y: 0, width: view.frame.width, height: view.frame.height)
                scrollView.addSubview(slides[i])
                }
                }


                //////

                /*
                * default function called when view is scrolled. In order to enable callback
                * when scrollview is scrolled, the below code needs to be called:
                * slideScrollView.delegate = self or
                */
                func scrollViewDidScroll(_ scrollView: UIScrollView) {
                let pageIndex = round(scrollView.contentOffset.x/view.frame.width)
                pageControl.currentPage = Int(pageIndex)

                let maximumHorizontalOffset: CGFloat = scrollView.contentSize.width - scrollView.frame.width
                let currentHorizontalOffset: CGFloat = scrollView.contentOffset.x

                // vertical
                let maximumVerticalOffset: CGFloat = scrollView.contentSize.height - scrollView.frame.height
                let currentVerticalOffset: CGFloat = scrollView.contentOffset.y

                let percentageHorizontalOffset: CGFloat = currentHorizontalOffset / maximumHorizontalOffset
                let percentageVerticalOffset: CGFloat = currentVerticalOffset / maximumVerticalOffset


                /*
                * below code changes the background color of view on paging the scrollview
                */
                // self.scrollView(scrollView, didScrollToPercentageOffset: percentageHorizontalOffset)


                /*
                * below code scales the imageview on paging the scrollview
                */
                let percentOffset: CGPoint = CGPoint(x: percentageHorizontalOffset, y: percentageVerticalOffset)

                if(percentOffset.x > 0 && percentOffset.x <= 0.25) {

                slides[0].mainPic.transform = CGAffineTransform(scaleX: (0.25-percentOffset.x)/0.25, y: (0.25-percentOffset.x)/0.25)
                slides[1].mainPic.transform = CGAffineTransform(scaleX: percentOffset.x/0.25, y: percentOffset.x/0.25)

                } else if(percentOffset.x > 0.25 && percentOffset.x <= 0.50) {
                slides[1].mainPic.transform = CGAffineTransform(scaleX: (0.50-percentOffset.x)/0.25, y: (0.50-percentOffset.x)/0.25)
                slides[2].mainPic.transform = CGAffineTransform(scaleX: percentOffset.x/0.50, y: percentOffset.x/0.50)

                } else if(percentOffset.x > 0.50 && percentOffset.x <= 0.75) {
                slides[2].mainPic.transform = CGAffineTransform(scaleX: (0.75-percentOffset.x)/0.25, y: (0.75-percentOffset.x)/0.25)
                slides[3].mainPic.transform = CGAffineTransform(scaleX: percentOffset.x/0.75, y: percentOffset.x/0.75)

                } else if(percentOffset.x > 0.75 && percentOffset.x <= 1) {
                slides[3].mainPic.transform = CGAffineTransform(scaleX: (1-percentOffset.x)/0.25, y: (1-percentOffset.x)/0.25)
                slides[4].mainPic.transform = CGAffineTransform(scaleX: percentOffset.x, y: percentOffset.x)
                }
                }

                override func prepare(for segue: UIStoryboardSegue, sender: Any?) {
                if segue.identifier == "findingClinitionSugue" {
                let destination = segue.destination as! FirstAvailableSearchViewController
                //destination.consumer = consumer
                }

                if (timer != nil) {
                timer?.invalidate()
                }
                }

                // protocol functions

                func initlizeSlides() {
                slides = createSlides()
                setupSlideScrollView(slides: slides)
                }

                func initlizeTimer() {
                scheduleTimer(5)
                }
                }





                share|improve this answer

























                  Your Answer






                  StackExchange.ifUsing("editor", function () {
                  StackExchange.using("externalEditor", function () {
                  StackExchange.using("snippets", function () {
                  StackExchange.snippets.init();
                  });
                  });
                  }, "code-snippets");

                  StackExchange.ready(function() {
                  var channelOptions = {
                  tags: "".split(" "),
                  id: "1"
                  };
                  initTagRenderer("".split(" "), "".split(" "), channelOptions);

                  StackExchange.using("externalEditor", function() {
                  // Have to fire editor after snippets, if snippets enabled
                  if (StackExchange.settings.snippets.snippetsEnabled) {
                  StackExchange.using("snippets", function() {
                  createEditor();
                  });
                  }
                  else {
                  createEditor();
                  }
                  });

                  function createEditor() {
                  StackExchange.prepareEditor({
                  heartbeatType: 'answer',
                  autoActivateHeartbeat: false,
                  convertImagesToLinks: true,
                  noModals: true,
                  showLowRepImageUploadWarning: true,
                  reputationToPostImages: 10,
                  bindNavPrevention: true,
                  postfix: "",
                  imageUploader: {
                  brandingHtml: "Powered by u003ca class="icon-imgur-white" href="https://imgur.com/"u003eu003c/au003e",
                  contentPolicyHtml: "User contributions licensed under u003ca href="https://creativecommons.org/licenses/by-sa/3.0/"u003ecc by-sa 3.0 with attribution requiredu003c/au003e u003ca href="https://stackoverflow.com/legal/content-policy"u003e(content policy)u003c/au003e",
                  allowUrls: true
                  },
                  onDemand: true,
                  discardSelector: ".discard-answer"
                  ,immediatelyShowMarkdownHelp:true
                  });


                  }
                  });














                  draft saved

                  draft discarded


















                  StackExchange.ready(
                  function () {
                  StackExchange.openid.initPostLogin('.new-post-login', 'https%3a%2f%2fstackoverflow.com%2fquestions%2f53985780%2fissue-in-blocking-vertical-scroll-on-uiscrollview-in-swift-4-0%23new-answer', 'question_page');
                  }
                  );

                  Post as a guest















                  Required, but never shown

























                  6 Answers
                  6






                  active

                  oldest

                  votes








                  6 Answers
                  6






                  active

                  oldest

                  votes









                  active

                  oldest

                  votes






                  active

                  oldest

                  votes









                  0














                  The problem might be about setting the contentSize height value to 0 initally, so even though timer wants scrollView to move, it cannot do that.



                  Can you try replacing this line:



                  scrollView.contentSize = CGSize(width: scrollView.contentSize.width, height: 0)


                  With:



                  scrollView.contentInsetAdjustmentBehavior = .never





                  share|improve this answer
























                  • this doesn't block the vertical movement, i tried it now, i can still swipe up

                    – Chief Madog
                    Dec 31 '18 at 14:28


















                  0














                  The problem might be about setting the contentSize height value to 0 initally, so even though timer wants scrollView to move, it cannot do that.



                  Can you try replacing this line:



                  scrollView.contentSize = CGSize(width: scrollView.contentSize.width, height: 0)


                  With:



                  scrollView.contentInsetAdjustmentBehavior = .never





                  share|improve this answer
























                  • this doesn't block the vertical movement, i tried it now, i can still swipe up

                    – Chief Madog
                    Dec 31 '18 at 14:28
















                  0












                  0








                  0







                  The problem might be about setting the contentSize height value to 0 initally, so even though timer wants scrollView to move, it cannot do that.



                  Can you try replacing this line:



                  scrollView.contentSize = CGSize(width: scrollView.contentSize.width, height: 0)


                  With:



                  scrollView.contentInsetAdjustmentBehavior = .never





                  share|improve this answer













                  The problem might be about setting the contentSize height value to 0 initally, so even though timer wants scrollView to move, it cannot do that.



                  Can you try replacing this line:



                  scrollView.contentSize = CGSize(width: scrollView.contentSize.width, height: 0)


                  With:



                  scrollView.contentInsetAdjustmentBehavior = .never






                  share|improve this answer












                  share|improve this answer



                  share|improve this answer










                  answered Dec 31 '18 at 10:58









                  emrepunemrepun

                  1,3801517




                  1,3801517













                  • this doesn't block the vertical movement, i tried it now, i can still swipe up

                    – Chief Madog
                    Dec 31 '18 at 14:28





















                  • this doesn't block the vertical movement, i tried it now, i can still swipe up

                    – Chief Madog
                    Dec 31 '18 at 14:28



















                  this doesn't block the vertical movement, i tried it now, i can still swipe up

                  – Chief Madog
                  Dec 31 '18 at 14:28







                  this doesn't block the vertical movement, i tried it now, i can still swipe up

                  – Chief Madog
                  Dec 31 '18 at 14:28















                  0














                  Depending the application and functionality required within the scrollview - could you disable user interaction of the scrollview so it can still be moved programmatically?



                  That would just be



                  scrollView.isUserInteractionEnabled = false


                  This would of course depend on whether you need items in the scrollview to be interactive






                  share|improve this answer
























                  • this just blocks the swipe all together, what i need is swipe enabled, and ALSO programmatically moved, just the vertical blocked

                    – Chief Madog
                    Jan 1 at 8:01











                  • At the risk of it being a bit of a workaround rather than a solution; you could try unblocking the vertical movement when the timer is called then blocking the vertical scroll again when it has finished programmatically scrolling. You could avoid any unwanted behaviour by also temporarily disabling user interaction at the same time as removing the vertical block (and re-enabling once it’s finished scrolling programmatically)

                    – Joe L
                    Jan 1 at 11:23
















                  0














                  Depending the application and functionality required within the scrollview - could you disable user interaction of the scrollview so it can still be moved programmatically?



                  That would just be



                  scrollView.isUserInteractionEnabled = false


                  This would of course depend on whether you need items in the scrollview to be interactive






                  share|improve this answer
























                  • this just blocks the swipe all together, what i need is swipe enabled, and ALSO programmatically moved, just the vertical blocked

                    – Chief Madog
                    Jan 1 at 8:01











                  • At the risk of it being a bit of a workaround rather than a solution; you could try unblocking the vertical movement when the timer is called then blocking the vertical scroll again when it has finished programmatically scrolling. You could avoid any unwanted behaviour by also temporarily disabling user interaction at the same time as removing the vertical block (and re-enabling once it’s finished scrolling programmatically)

                    – Joe L
                    Jan 1 at 11:23














                  0












                  0








                  0







                  Depending the application and functionality required within the scrollview - could you disable user interaction of the scrollview so it can still be moved programmatically?



                  That would just be



                  scrollView.isUserInteractionEnabled = false


                  This would of course depend on whether you need items in the scrollview to be interactive






                  share|improve this answer













                  Depending the application and functionality required within the scrollview - could you disable user interaction of the scrollview so it can still be moved programmatically?



                  That would just be



                  scrollView.isUserInteractionEnabled = false


                  This would of course depend on whether you need items in the scrollview to be interactive







                  share|improve this answer












                  share|improve this answer



                  share|improve this answer










                  answered Dec 31 '18 at 23:31









                  Joe LJoe L

                  11




                  11













                  • this just blocks the swipe all together, what i need is swipe enabled, and ALSO programmatically moved, just the vertical blocked

                    – Chief Madog
                    Jan 1 at 8:01











                  • At the risk of it being a bit of a workaround rather than a solution; you could try unblocking the vertical movement when the timer is called then blocking the vertical scroll again when it has finished programmatically scrolling. You could avoid any unwanted behaviour by also temporarily disabling user interaction at the same time as removing the vertical block (and re-enabling once it’s finished scrolling programmatically)

                    – Joe L
                    Jan 1 at 11:23



















                  • this just blocks the swipe all together, what i need is swipe enabled, and ALSO programmatically moved, just the vertical blocked

                    – Chief Madog
                    Jan 1 at 8:01











                  • At the risk of it being a bit of a workaround rather than a solution; you could try unblocking the vertical movement when the timer is called then blocking the vertical scroll again when it has finished programmatically scrolling. You could avoid any unwanted behaviour by also temporarily disabling user interaction at the same time as removing the vertical block (and re-enabling once it’s finished scrolling programmatically)

                    – Joe L
                    Jan 1 at 11:23

















                  this just blocks the swipe all together, what i need is swipe enabled, and ALSO programmatically moved, just the vertical blocked

                  – Chief Madog
                  Jan 1 at 8:01





                  this just blocks the swipe all together, what i need is swipe enabled, and ALSO programmatically moved, just the vertical blocked

                  – Chief Madog
                  Jan 1 at 8:01













                  At the risk of it being a bit of a workaround rather than a solution; you could try unblocking the vertical movement when the timer is called then blocking the vertical scroll again when it has finished programmatically scrolling. You could avoid any unwanted behaviour by also temporarily disabling user interaction at the same time as removing the vertical block (and re-enabling once it’s finished scrolling programmatically)

                  – Joe L
                  Jan 1 at 11:23





                  At the risk of it being a bit of a workaround rather than a solution; you could try unblocking the vertical movement when the timer is called then blocking the vertical scroll again when it has finished programmatically scrolling. You could avoid any unwanted behaviour by also temporarily disabling user interaction at the same time as removing the vertical block (and re-enabling once it’s finished scrolling programmatically)

                  – Joe L
                  Jan 1 at 11:23











                  0














                  Maybe you can subclass your UIScrollView, and override touchesBegan.



                  class CustomScrollView: UIScrollView {

                  var touchesDisabled = false
                  override func touchesBegan(_ touches: Set<UITouch>, with event: UIEvent?) {
                  if touchesDisabled {
                  // here parse the touches, if they go in the horizontal direction, allow scrolling
                  // set tolerance for vertical movement
                  let tolerance: CGFloat = 5.0
                  let variance = touches.reduce(0, { Yvariation, touch in
                  Yvariation + abs(touch.location(in: view).y - touch.previousLocation(in: view).y)
                  })
                  if variance <= tolerance * CGFloat(touches.count) {
                  let Xtravelled = touches.reduce(0, { Xstep, touch in
                  Xstep + (touch.location(in: view).x - touch.previousLocation(in: view).x)
                  })
                  // scroll horizontally by the x component of hand gesture
                  var newFrame: CGRect = scrollView.frame
                  newFrame.origin.x += Xtravelled
                  self.scrollRectToVisible(frame, animated: true)
                  }
                  }

                  else {
                  super.touchesBegan(touches: touches, withEvent: event)
                  }
                  }
                  }


                  This way you can manually move the scrollview horizontally while disabling vertical movement when touchesDisabled is set true.






                  share|improve this answer




























                    0














                    Maybe you can subclass your UIScrollView, and override touchesBegan.



                    class CustomScrollView: UIScrollView {

                    var touchesDisabled = false
                    override func touchesBegan(_ touches: Set<UITouch>, with event: UIEvent?) {
                    if touchesDisabled {
                    // here parse the touches, if they go in the horizontal direction, allow scrolling
                    // set tolerance for vertical movement
                    let tolerance: CGFloat = 5.0
                    let variance = touches.reduce(0, { Yvariation, touch in
                    Yvariation + abs(touch.location(in: view).y - touch.previousLocation(in: view).y)
                    })
                    if variance <= tolerance * CGFloat(touches.count) {
                    let Xtravelled = touches.reduce(0, { Xstep, touch in
                    Xstep + (touch.location(in: view).x - touch.previousLocation(in: view).x)
                    })
                    // scroll horizontally by the x component of hand gesture
                    var newFrame: CGRect = scrollView.frame
                    newFrame.origin.x += Xtravelled
                    self.scrollRectToVisible(frame, animated: true)
                    }
                    }

                    else {
                    super.touchesBegan(touches: touches, withEvent: event)
                    }
                    }
                    }


                    This way you can manually move the scrollview horizontally while disabling vertical movement when touchesDisabled is set true.






                    share|improve this answer


























                      0












                      0








                      0







                      Maybe you can subclass your UIScrollView, and override touchesBegan.



                      class CustomScrollView: UIScrollView {

                      var touchesDisabled = false
                      override func touchesBegan(_ touches: Set<UITouch>, with event: UIEvent?) {
                      if touchesDisabled {
                      // here parse the touches, if they go in the horizontal direction, allow scrolling
                      // set tolerance for vertical movement
                      let tolerance: CGFloat = 5.0
                      let variance = touches.reduce(0, { Yvariation, touch in
                      Yvariation + abs(touch.location(in: view).y - touch.previousLocation(in: view).y)
                      })
                      if variance <= tolerance * CGFloat(touches.count) {
                      let Xtravelled = touches.reduce(0, { Xstep, touch in
                      Xstep + (touch.location(in: view).x - touch.previousLocation(in: view).x)
                      })
                      // scroll horizontally by the x component of hand gesture
                      var newFrame: CGRect = scrollView.frame
                      newFrame.origin.x += Xtravelled
                      self.scrollRectToVisible(frame, animated: true)
                      }
                      }

                      else {
                      super.touchesBegan(touches: touches, withEvent: event)
                      }
                      }
                      }


                      This way you can manually move the scrollview horizontally while disabling vertical movement when touchesDisabled is set true.






                      share|improve this answer













                      Maybe you can subclass your UIScrollView, and override touchesBegan.



                      class CustomScrollView: UIScrollView {

                      var touchesDisabled = false
                      override func touchesBegan(_ touches: Set<UITouch>, with event: UIEvent?) {
                      if touchesDisabled {
                      // here parse the touches, if they go in the horizontal direction, allow scrolling
                      // set tolerance for vertical movement
                      let tolerance: CGFloat = 5.0
                      let variance = touches.reduce(0, { Yvariation, touch in
                      Yvariation + abs(touch.location(in: view).y - touch.previousLocation(in: view).y)
                      })
                      if variance <= tolerance * CGFloat(touches.count) {
                      let Xtravelled = touches.reduce(0, { Xstep, touch in
                      Xstep + (touch.location(in: view).x - touch.previousLocation(in: view).x)
                      })
                      // scroll horizontally by the x component of hand gesture
                      var newFrame: CGRect = scrollView.frame
                      newFrame.origin.x += Xtravelled
                      self.scrollRectToVisible(frame, animated: true)
                      }
                      }

                      else {
                      super.touchesBegan(touches: touches, withEvent: event)
                      }
                      }
                      }


                      This way you can manually move the scrollview horizontally while disabling vertical movement when touchesDisabled is set true.







                      share|improve this answer












                      share|improve this answer



                      share|improve this answer










                      answered Jan 4 at 4:27









                      ocsahanocsahan

                      614




                      614























                          0














                          If I've understood you problem well, you can stop scrolling whenever you want with this



                          scrollView.isScrollEnabled = false





                          share|improve this answer




























                            0














                            If I've understood you problem well, you can stop scrolling whenever you want with this



                            scrollView.isScrollEnabled = false





                            share|improve this answer


























                              0












                              0








                              0







                              If I've understood you problem well, you can stop scrolling whenever you want with this



                              scrollView.isScrollEnabled = false





                              share|improve this answer













                              If I've understood you problem well, you can stop scrolling whenever you want with this



                              scrollView.isScrollEnabled = false






                              share|improve this answer












                              share|improve this answer



                              share|improve this answer










                              answered Jan 9 at 8:35









                              EhsanEhsan

                              527




                              527























                                  0














                                  Using UIScrollViewDelegate (or KVO on scrollView's contentOffset), you can just counteract any vertical movement in the carousel. Something like this:



                                  var oldYOffset: CGFloat ....

                                  func scrollViewDidScroll(_ scrollView: UIScrollView) {
                                  let deltaY = oldYOffset - scrollView.contentOffset.y
                                  oldYOffset = scrollView.contentOffset.y
                                  scrollView.contentOffset.y -= deltaY
                                  }


                                  This offset change will not be visible to the user. You could even use this to increase the speed of the scrolling, invert the scrolling (pan left and scrollView scrolls right), or entirely lock the motion of the scrollView without touching isScrollEnabled, contentSize, etc.






                                  share|improve this answer




























                                    0














                                    Using UIScrollViewDelegate (or KVO on scrollView's contentOffset), you can just counteract any vertical movement in the carousel. Something like this:



                                    var oldYOffset: CGFloat ....

                                    func scrollViewDidScroll(_ scrollView: UIScrollView) {
                                    let deltaY = oldYOffset - scrollView.contentOffset.y
                                    oldYOffset = scrollView.contentOffset.y
                                    scrollView.contentOffset.y -= deltaY
                                    }


                                    This offset change will not be visible to the user. You could even use this to increase the speed of the scrolling, invert the scrolling (pan left and scrollView scrolls right), or entirely lock the motion of the scrollView without touching isScrollEnabled, contentSize, etc.






                                    share|improve this answer


























                                      0












                                      0








                                      0







                                      Using UIScrollViewDelegate (or KVO on scrollView's contentOffset), you can just counteract any vertical movement in the carousel. Something like this:



                                      var oldYOffset: CGFloat ....

                                      func scrollViewDidScroll(_ scrollView: UIScrollView) {
                                      let deltaY = oldYOffset - scrollView.contentOffset.y
                                      oldYOffset = scrollView.contentOffset.y
                                      scrollView.contentOffset.y -= deltaY
                                      }


                                      This offset change will not be visible to the user. You could even use this to increase the speed of the scrolling, invert the scrolling (pan left and scrollView scrolls right), or entirely lock the motion of the scrollView without touching isScrollEnabled, contentSize, etc.






                                      share|improve this answer













                                      Using UIScrollViewDelegate (or KVO on scrollView's contentOffset), you can just counteract any vertical movement in the carousel. Something like this:



                                      var oldYOffset: CGFloat ....

                                      func scrollViewDidScroll(_ scrollView: UIScrollView) {
                                      let deltaY = oldYOffset - scrollView.contentOffset.y
                                      oldYOffset = scrollView.contentOffset.y
                                      scrollView.contentOffset.y -= deltaY
                                      }


                                      This offset change will not be visible to the user. You could even use this to increase the speed of the scrolling, invert the scrolling (pan left and scrollView scrolls right), or entirely lock the motion of the scrollView without touching isScrollEnabled, contentSize, etc.







                                      share|improve this answer












                                      share|improve this answer



                                      share|improve this answer










                                      answered Jan 9 at 22:02









                                      kid_xkid_x

                                      547420




                                      547420























                                          0














                                          This turned out to be quite an interesting problem...



                                          While it is easy to lock UIScrollView scrolling to one axis only using the UIScrollViewDelegate, it is impossible to provide smooth scrolling while changing the scrolling programmatically (as you do with the Timer) at the same time.



                                          Below, you will find a DirectionLockingScrollView class I just wrote that should make things easier for you. It's a UIScrollView that you can initialize either programmatically, or via the Interface Builder.



                                          It features isHorizontalScrollingEnabled and isVerticalScrollingEnabled properties.



                                          HOW IT WORKS INTERNALLY



                                          It adds a second "control" UIScrollView that is identical to the main DirectionLockingScrollView and propagates to it all pan events intended for the main scroll view. Every time the "control" scroll view's bounds change, the change is propagated to the main scroll view BUT x and y are altered (based on isHorizontalScrollingEnabled and isVerticalScrollingEnabled) to disable scrolling on the requested axis.



                                          DirectionLockingScrollView.swift



                                          /// `UIScrollView` subclass that supports disabling scrolling on any direction
                                          /// while allowing the other direction to be changed programmatically (via
                                          /// `setContentOffset(_:animated)` or `scrollRectToVisible(_:animated)` or changing the
                                          /// bounds etc.
                                          ///
                                          /// Can be initialized programmatically or via the Interface Builder.
                                          class DirectionLockingScrollView: UIScrollView {
                                          var isHorizontalScrollingEnabled = true
                                          var isVerticalScrollingEnabled = true

                                          /// The control scrollview is added below the `DirectionLockingScrollView`
                                          /// and is used to implement all native scrollview behaviours (such as bouncing)
                                          /// based on user input.
                                          ///
                                          /// It is required to be able to change the bounds of the `DirectionLockingScrollView`
                                          /// while maintaining scrolling in only one direction and allowing for setting the contentOffset
                                          /// (changing scrolling for any axis - even the disabled ones) programmatically.
                                          private let _controlScrollView = UIScrollView(frame: .zero)

                                          required init?(coder aDecoder: NSCoder) {
                                          super.init(coder: aDecoder)
                                          installCustomScrollView()
                                          }

                                          override init(frame: CGRect) {
                                          super.init(frame: frame)
                                          installCustomScrollView()
                                          }

                                          override func layoutSubviews() {
                                          super.layoutSubviews()
                                          updateCustomScrollViewFrame()
                                          }

                                          override func didMoveToSuperview() {
                                          super.didMoveToSuperview()
                                          guard let superview = superview else {
                                          _controlScrollView.removeFromSuperview()
                                          return
                                          }

                                          superview.insertSubview(_controlScrollView, belowSubview: self)
                                          updateCustomScrollViewFrame()
                                          }

                                          // MARK: - UIEvent propagation

                                          func viewIgnoresEvents(_ view: UIView?) -> Bool {
                                          let viewIgnoresEvents =
                                          view == nil ||
                                          view == self ||
                                          !view!.isUserInteractionEnabled ||
                                          !(view is UIControl && (view!.gestureRecognizers ?? ).count == 0)

                                          return viewIgnoresEvents
                                          }

                                          override func hitTest(_ point: CGPoint, with event: UIEvent?) -> UIView? {
                                          let view = super.hitTest(point, with: event)
                                          if viewIgnoresEvents(view) {
                                          return _controlScrollView
                                          }

                                          return view
                                          }

                                          // MARK: - Main scrollview settings propagation to `controlScrollView`

                                          override var contentInset: UIEdgeInsets {
                                          didSet {
                                          _controlScrollView.contentInset = contentInset
                                          }
                                          }

                                          override var contentScaleFactor: CGFloat {
                                          didSet {
                                          _controlScrollView.contentScaleFactor = contentScaleFactor
                                          }
                                          }

                                          override var contentSize: CGSize {
                                          didSet {
                                          _controlScrollView.contentSize = contentSize
                                          }
                                          }

                                          override var bounces: Bool {
                                          didSet {
                                          _controlScrollView.bounces = bounces
                                          }
                                          }

                                          override var bouncesZoom: Bool {
                                          didSet {
                                          _controlScrollView.bouncesZoom = bouncesZoom
                                          }
                                          }
                                          }

                                          extension DirectionLockingScrollView: UIScrollViewDelegate {
                                          func scrollViewDidScroll(_ scrollView: UIScrollView) {
                                          updateBoundsFromCustomScrollView(scrollView)
                                          }
                                          }

                                          private extension DirectionLockingScrollView {
                                          /// Propagates `controlScrollView` bounds to the actual scrollview.
                                          /// - Parameter scrollView: If the scrollview provided is not the `controlScrollView`
                                          // the main scrollview bounds are not updated.
                                          func updateBoundsFromCustomScrollView(_ scrollView: UIScrollView) {
                                          if scrollView != _controlScrollView {
                                          return
                                          }

                                          var newBounds = scrollView.bounds.origin
                                          if !isHorizontalScrollingEnabled {
                                          newBounds.x = self.contentOffset.x
                                          }

                                          if !isVerticalScrollingEnabled {
                                          newBounds.y = self.contentOffset.y
                                          }

                                          bounds.origin = newBounds
                                          }

                                          func installCustomScrollView() {
                                          _controlScrollView.delegate = self
                                          _controlScrollView.contentSize = contentSize
                                          _controlScrollView.showsVerticalScrollIndicator = false
                                          _controlScrollView.showsHorizontalScrollIndicator = false

                                          // The panGestureRecognizer is removed because pan gestures might be triggered
                                          // on subviews of the scrollview which do not ignore touch events (determined
                                          // by `viewIgnoresEvents(_ view: UIView?)`). This can happen for example
                                          // if you tap and drag on a button inside the scroll view.
                                          removeGestureRecognizer(panGestureRecognizer)
                                          }

                                          func updateCustomScrollViewFrame() {
                                          if _controlScrollView.frame == frame { return }
                                          _controlScrollView.frame = frame
                                          }
                                          }


                                          USAGE



                                          After you've included the above class in your app, don't forget to change your scroll view's class to DirectionLockingScrollView in your .xib or .storyboard.



                                          Then update your code as below (only two lines changed, marked with // *****).



                                          class CaruselleScreenViewController: UIViewController, CaruselleScreenViewProtocol, UIScrollViewDelegate {
                                          var myPresenter: CaruselleScreenPresenterProtocol?

                                          @IBOutlet weak var pageControl: UIPageControl!
                                          @IBOutlet weak var scrollView: DirectionLockingScrollView! // *****

                                          var slides:[CaruselleTipsCard] = ;


                                          var timer:Timer?
                                          var currentPageMultiplayer = 0

                                          override func viewDidLoad() {
                                          super.viewDidLoad()

                                          myPresenter = CaruselleScreenPresenter(controller: self)

                                          //initlizes view
                                          pageControl.numberOfPages = slides.count
                                          pageControl.currentPage = 0
                                          view.bringSubview(toFront: pageControl)

                                          scrollView.isHorizontalScrollingEnabled = false // *****

                                          //delegates
                                          scrollView.delegate = self

                                          ////blocks vertical movement
                                          scrollView.showsVerticalScrollIndicator = false
                                          //scrollView.contentSize = CGSize(width: scrollView.contentSize.width, height: 0) //disable vertical
                                          }

                                          func scheduleTimer(_ timeInterval: TimeInterval){
                                          timer = Timer.scheduledTimer(timeInterval: timeInterval, target: self, selector: #selector(timerCall), userInfo: nil, repeats: false)
                                          }

                                          @objc func timerCall(){
                                          print("Timer executed")

                                          currentPageMultiplayer = currentPageMultiplayer + 1

                                          if (currentPageMultiplayer == 5) {
                                          currentPageMultiplayer = 0
                                          }
                                          pageControl.currentPage = currentPageMultiplayer
                                          scrollToPage(pageToMove: currentPageMultiplayer)

                                          scheduleTimer(5)
                                          }

                                          func scrollToPage(pageToMove: Int) {
                                          print ("new one")
                                          var frame: CGRect = scrollView.frame
                                          frame.origin.x = frame.size.width * CGFloat(pageToMove)
                                          frame.origin.y = -35
                                          scrollView.scrollRectToVisible(frame, animated: true)
                                          }


                                          func createSlides() -> [CaruselleTipsCard] {

                                          let slide1:CaruselleTipsCard = Bundle.main.loadNibNamed("CaruselleTipsCard", owner: self, options: nil)?.first as! CaruselleTipsCard
                                          slide1.mainPic.image = UIImage(named: "backlightingIllo")

                                          //
                                          let slide2:CaruselleTipsCard = Bundle.main.loadNibNamed("CaruselleTipsCard", owner: self, options: nil)?.first as! CaruselleTipsCard
                                          slide2.mainPic.image = UIImage(named: "comfortableIllo")

                                          //
                                          let slide3:CaruselleTipsCard = Bundle.main.loadNibNamed("CaruselleTipsCard", owner: self, options: nil)?.first as! CaruselleTipsCard
                                          slide3.mainPic.image = UIImage(named: "pharmacyIllo")

                                          //
                                          let slide4:CaruselleTipsCard = Bundle.main.loadNibNamed("CaruselleTipsCard", owner: self, options: nil)?.first as! CaruselleTipsCard
                                          slide4.mainPic.image = UIImage(named: "batteryIllo")

                                          //
                                          let slide5:CaruselleTipsCard = Bundle.main.loadNibNamed("CaruselleTipsCard", owner: self, options: nil)?.first as! CaruselleTipsCard
                                          slide5.mainPic.image = UIImage(named: "wiFiIllo")

                                          return [slide1, slide2, slide3, slide4, slide5]
                                          }

                                          func setupSlideScrollView(slides : [CaruselleTipsCard]) {
                                          scrollView.frame = CGRect(x: 0, y: 0, width: view.frame.width, height: view.frame.height)
                                          scrollView.contentSize = CGSize(width: view.frame.width * CGFloat(slides.count), height: view.frame.height)
                                          scrollView.isPagingEnabled = true

                                          for i in 0 ..< slides.count {
                                          slides[i].frame = CGRect(x: view.frame.width * CGFloat(i), y: 0, width: view.frame.width, height: view.frame.height)
                                          scrollView.addSubview(slides[i])
                                          }
                                          }


                                          //////

                                          /*
                                          * default function called when view is scrolled. In order to enable callback
                                          * when scrollview is scrolled, the below code needs to be called:
                                          * slideScrollView.delegate = self or
                                          */
                                          func scrollViewDidScroll(_ scrollView: UIScrollView) {
                                          let pageIndex = round(scrollView.contentOffset.x/view.frame.width)
                                          pageControl.currentPage = Int(pageIndex)

                                          let maximumHorizontalOffset: CGFloat = scrollView.contentSize.width - scrollView.frame.width
                                          let currentHorizontalOffset: CGFloat = scrollView.contentOffset.x

                                          // vertical
                                          let maximumVerticalOffset: CGFloat = scrollView.contentSize.height - scrollView.frame.height
                                          let currentVerticalOffset: CGFloat = scrollView.contentOffset.y

                                          let percentageHorizontalOffset: CGFloat = currentHorizontalOffset / maximumHorizontalOffset
                                          let percentageVerticalOffset: CGFloat = currentVerticalOffset / maximumVerticalOffset


                                          /*
                                          * below code changes the background color of view on paging the scrollview
                                          */
                                          // self.scrollView(scrollView, didScrollToPercentageOffset: percentageHorizontalOffset)


                                          /*
                                          * below code scales the imageview on paging the scrollview
                                          */
                                          let percentOffset: CGPoint = CGPoint(x: percentageHorizontalOffset, y: percentageVerticalOffset)

                                          if(percentOffset.x > 0 && percentOffset.x <= 0.25) {

                                          slides[0].mainPic.transform = CGAffineTransform(scaleX: (0.25-percentOffset.x)/0.25, y: (0.25-percentOffset.x)/0.25)
                                          slides[1].mainPic.transform = CGAffineTransform(scaleX: percentOffset.x/0.25, y: percentOffset.x/0.25)

                                          } else if(percentOffset.x > 0.25 && percentOffset.x <= 0.50) {
                                          slides[1].mainPic.transform = CGAffineTransform(scaleX: (0.50-percentOffset.x)/0.25, y: (0.50-percentOffset.x)/0.25)
                                          slides[2].mainPic.transform = CGAffineTransform(scaleX: percentOffset.x/0.50, y: percentOffset.x/0.50)

                                          } else if(percentOffset.x > 0.50 && percentOffset.x <= 0.75) {
                                          slides[2].mainPic.transform = CGAffineTransform(scaleX: (0.75-percentOffset.x)/0.25, y: (0.75-percentOffset.x)/0.25)
                                          slides[3].mainPic.transform = CGAffineTransform(scaleX: percentOffset.x/0.75, y: percentOffset.x/0.75)

                                          } else if(percentOffset.x > 0.75 && percentOffset.x <= 1) {
                                          slides[3].mainPic.transform = CGAffineTransform(scaleX: (1-percentOffset.x)/0.25, y: (1-percentOffset.x)/0.25)
                                          slides[4].mainPic.transform = CGAffineTransform(scaleX: percentOffset.x, y: percentOffset.x)
                                          }
                                          }

                                          override func prepare(for segue: UIStoryboardSegue, sender: Any?) {
                                          if segue.identifier == "findingClinitionSugue" {
                                          let destination = segue.destination as! FirstAvailableSearchViewController
                                          //destination.consumer = consumer
                                          }

                                          if (timer != nil) {
                                          timer?.invalidate()
                                          }
                                          }

                                          // protocol functions

                                          func initlizeSlides() {
                                          slides = createSlides()
                                          setupSlideScrollView(slides: slides)
                                          }

                                          func initlizeTimer() {
                                          scheduleTimer(5)
                                          }
                                          }





                                          share|improve this answer






























                                            0














                                            This turned out to be quite an interesting problem...



                                            While it is easy to lock UIScrollView scrolling to one axis only using the UIScrollViewDelegate, it is impossible to provide smooth scrolling while changing the scrolling programmatically (as you do with the Timer) at the same time.



                                            Below, you will find a DirectionLockingScrollView class I just wrote that should make things easier for you. It's a UIScrollView that you can initialize either programmatically, or via the Interface Builder.



                                            It features isHorizontalScrollingEnabled and isVerticalScrollingEnabled properties.



                                            HOW IT WORKS INTERNALLY



                                            It adds a second "control" UIScrollView that is identical to the main DirectionLockingScrollView and propagates to it all pan events intended for the main scroll view. Every time the "control" scroll view's bounds change, the change is propagated to the main scroll view BUT x and y are altered (based on isHorizontalScrollingEnabled and isVerticalScrollingEnabled) to disable scrolling on the requested axis.



                                            DirectionLockingScrollView.swift



                                            /// `UIScrollView` subclass that supports disabling scrolling on any direction
                                            /// while allowing the other direction to be changed programmatically (via
                                            /// `setContentOffset(_:animated)` or `scrollRectToVisible(_:animated)` or changing the
                                            /// bounds etc.
                                            ///
                                            /// Can be initialized programmatically or via the Interface Builder.
                                            class DirectionLockingScrollView: UIScrollView {
                                            var isHorizontalScrollingEnabled = true
                                            var isVerticalScrollingEnabled = true

                                            /// The control scrollview is added below the `DirectionLockingScrollView`
                                            /// and is used to implement all native scrollview behaviours (such as bouncing)
                                            /// based on user input.
                                            ///
                                            /// It is required to be able to change the bounds of the `DirectionLockingScrollView`
                                            /// while maintaining scrolling in only one direction and allowing for setting the contentOffset
                                            /// (changing scrolling for any axis - even the disabled ones) programmatically.
                                            private let _controlScrollView = UIScrollView(frame: .zero)

                                            required init?(coder aDecoder: NSCoder) {
                                            super.init(coder: aDecoder)
                                            installCustomScrollView()
                                            }

                                            override init(frame: CGRect) {
                                            super.init(frame: frame)
                                            installCustomScrollView()
                                            }

                                            override func layoutSubviews() {
                                            super.layoutSubviews()
                                            updateCustomScrollViewFrame()
                                            }

                                            override func didMoveToSuperview() {
                                            super.didMoveToSuperview()
                                            guard let superview = superview else {
                                            _controlScrollView.removeFromSuperview()
                                            return
                                            }

                                            superview.insertSubview(_controlScrollView, belowSubview: self)
                                            updateCustomScrollViewFrame()
                                            }

                                            // MARK: - UIEvent propagation

                                            func viewIgnoresEvents(_ view: UIView?) -> Bool {
                                            let viewIgnoresEvents =
                                            view == nil ||
                                            view == self ||
                                            !view!.isUserInteractionEnabled ||
                                            !(view is UIControl && (view!.gestureRecognizers ?? ).count == 0)

                                            return viewIgnoresEvents
                                            }

                                            override func hitTest(_ point: CGPoint, with event: UIEvent?) -> UIView? {
                                            let view = super.hitTest(point, with: event)
                                            if viewIgnoresEvents(view) {
                                            return _controlScrollView
                                            }

                                            return view
                                            }

                                            // MARK: - Main scrollview settings propagation to `controlScrollView`

                                            override var contentInset: UIEdgeInsets {
                                            didSet {
                                            _controlScrollView.contentInset = contentInset
                                            }
                                            }

                                            override var contentScaleFactor: CGFloat {
                                            didSet {
                                            _controlScrollView.contentScaleFactor = contentScaleFactor
                                            }
                                            }

                                            override var contentSize: CGSize {
                                            didSet {
                                            _controlScrollView.contentSize = contentSize
                                            }
                                            }

                                            override var bounces: Bool {
                                            didSet {
                                            _controlScrollView.bounces = bounces
                                            }
                                            }

                                            override var bouncesZoom: Bool {
                                            didSet {
                                            _controlScrollView.bouncesZoom = bouncesZoom
                                            }
                                            }
                                            }

                                            extension DirectionLockingScrollView: UIScrollViewDelegate {
                                            func scrollViewDidScroll(_ scrollView: UIScrollView) {
                                            updateBoundsFromCustomScrollView(scrollView)
                                            }
                                            }

                                            private extension DirectionLockingScrollView {
                                            /// Propagates `controlScrollView` bounds to the actual scrollview.
                                            /// - Parameter scrollView: If the scrollview provided is not the `controlScrollView`
                                            // the main scrollview bounds are not updated.
                                            func updateBoundsFromCustomScrollView(_ scrollView: UIScrollView) {
                                            if scrollView != _controlScrollView {
                                            return
                                            }

                                            var newBounds = scrollView.bounds.origin
                                            if !isHorizontalScrollingEnabled {
                                            newBounds.x = self.contentOffset.x
                                            }

                                            if !isVerticalScrollingEnabled {
                                            newBounds.y = self.contentOffset.y
                                            }

                                            bounds.origin = newBounds
                                            }

                                            func installCustomScrollView() {
                                            _controlScrollView.delegate = self
                                            _controlScrollView.contentSize = contentSize
                                            _controlScrollView.showsVerticalScrollIndicator = false
                                            _controlScrollView.showsHorizontalScrollIndicator = false

                                            // The panGestureRecognizer is removed because pan gestures might be triggered
                                            // on subviews of the scrollview which do not ignore touch events (determined
                                            // by `viewIgnoresEvents(_ view: UIView?)`). This can happen for example
                                            // if you tap and drag on a button inside the scroll view.
                                            removeGestureRecognizer(panGestureRecognizer)
                                            }

                                            func updateCustomScrollViewFrame() {
                                            if _controlScrollView.frame == frame { return }
                                            _controlScrollView.frame = frame
                                            }
                                            }


                                            USAGE



                                            After you've included the above class in your app, don't forget to change your scroll view's class to DirectionLockingScrollView in your .xib or .storyboard.



                                            Then update your code as below (only two lines changed, marked with // *****).



                                            class CaruselleScreenViewController: UIViewController, CaruselleScreenViewProtocol, UIScrollViewDelegate {
                                            var myPresenter: CaruselleScreenPresenterProtocol?

                                            @IBOutlet weak var pageControl: UIPageControl!
                                            @IBOutlet weak var scrollView: DirectionLockingScrollView! // *****

                                            var slides:[CaruselleTipsCard] = ;


                                            var timer:Timer?
                                            var currentPageMultiplayer = 0

                                            override func viewDidLoad() {
                                            super.viewDidLoad()

                                            myPresenter = CaruselleScreenPresenter(controller: self)

                                            //initlizes view
                                            pageControl.numberOfPages = slides.count
                                            pageControl.currentPage = 0
                                            view.bringSubview(toFront: pageControl)

                                            scrollView.isHorizontalScrollingEnabled = false // *****

                                            //delegates
                                            scrollView.delegate = self

                                            ////blocks vertical movement
                                            scrollView.showsVerticalScrollIndicator = false
                                            //scrollView.contentSize = CGSize(width: scrollView.contentSize.width, height: 0) //disable vertical
                                            }

                                            func scheduleTimer(_ timeInterval: TimeInterval){
                                            timer = Timer.scheduledTimer(timeInterval: timeInterval, target: self, selector: #selector(timerCall), userInfo: nil, repeats: false)
                                            }

                                            @objc func timerCall(){
                                            print("Timer executed")

                                            currentPageMultiplayer = currentPageMultiplayer + 1

                                            if (currentPageMultiplayer == 5) {
                                            currentPageMultiplayer = 0
                                            }
                                            pageControl.currentPage = currentPageMultiplayer
                                            scrollToPage(pageToMove: currentPageMultiplayer)

                                            scheduleTimer(5)
                                            }

                                            func scrollToPage(pageToMove: Int) {
                                            print ("new one")
                                            var frame: CGRect = scrollView.frame
                                            frame.origin.x = frame.size.width * CGFloat(pageToMove)
                                            frame.origin.y = -35
                                            scrollView.scrollRectToVisible(frame, animated: true)
                                            }


                                            func createSlides() -> [CaruselleTipsCard] {

                                            let slide1:CaruselleTipsCard = Bundle.main.loadNibNamed("CaruselleTipsCard", owner: self, options: nil)?.first as! CaruselleTipsCard
                                            slide1.mainPic.image = UIImage(named: "backlightingIllo")

                                            //
                                            let slide2:CaruselleTipsCard = Bundle.main.loadNibNamed("CaruselleTipsCard", owner: self, options: nil)?.first as! CaruselleTipsCard
                                            slide2.mainPic.image = UIImage(named: "comfortableIllo")

                                            //
                                            let slide3:CaruselleTipsCard = Bundle.main.loadNibNamed("CaruselleTipsCard", owner: self, options: nil)?.first as! CaruselleTipsCard
                                            slide3.mainPic.image = UIImage(named: "pharmacyIllo")

                                            //
                                            let slide4:CaruselleTipsCard = Bundle.main.loadNibNamed("CaruselleTipsCard", owner: self, options: nil)?.first as! CaruselleTipsCard
                                            slide4.mainPic.image = UIImage(named: "batteryIllo")

                                            //
                                            let slide5:CaruselleTipsCard = Bundle.main.loadNibNamed("CaruselleTipsCard", owner: self, options: nil)?.first as! CaruselleTipsCard
                                            slide5.mainPic.image = UIImage(named: "wiFiIllo")

                                            return [slide1, slide2, slide3, slide4, slide5]
                                            }

                                            func setupSlideScrollView(slides : [CaruselleTipsCard]) {
                                            scrollView.frame = CGRect(x: 0, y: 0, width: view.frame.width, height: view.frame.height)
                                            scrollView.contentSize = CGSize(width: view.frame.width * CGFloat(slides.count), height: view.frame.height)
                                            scrollView.isPagingEnabled = true

                                            for i in 0 ..< slides.count {
                                            slides[i].frame = CGRect(x: view.frame.width * CGFloat(i), y: 0, width: view.frame.width, height: view.frame.height)
                                            scrollView.addSubview(slides[i])
                                            }
                                            }


                                            //////

                                            /*
                                            * default function called when view is scrolled. In order to enable callback
                                            * when scrollview is scrolled, the below code needs to be called:
                                            * slideScrollView.delegate = self or
                                            */
                                            func scrollViewDidScroll(_ scrollView: UIScrollView) {
                                            let pageIndex = round(scrollView.contentOffset.x/view.frame.width)
                                            pageControl.currentPage = Int(pageIndex)

                                            let maximumHorizontalOffset: CGFloat = scrollView.contentSize.width - scrollView.frame.width
                                            let currentHorizontalOffset: CGFloat = scrollView.contentOffset.x

                                            // vertical
                                            let maximumVerticalOffset: CGFloat = scrollView.contentSize.height - scrollView.frame.height
                                            let currentVerticalOffset: CGFloat = scrollView.contentOffset.y

                                            let percentageHorizontalOffset: CGFloat = currentHorizontalOffset / maximumHorizontalOffset
                                            let percentageVerticalOffset: CGFloat = currentVerticalOffset / maximumVerticalOffset


                                            /*
                                            * below code changes the background color of view on paging the scrollview
                                            */
                                            // self.scrollView(scrollView, didScrollToPercentageOffset: percentageHorizontalOffset)


                                            /*
                                            * below code scales the imageview on paging the scrollview
                                            */
                                            let percentOffset: CGPoint = CGPoint(x: percentageHorizontalOffset, y: percentageVerticalOffset)

                                            if(percentOffset.x > 0 && percentOffset.x <= 0.25) {

                                            slides[0].mainPic.transform = CGAffineTransform(scaleX: (0.25-percentOffset.x)/0.25, y: (0.25-percentOffset.x)/0.25)
                                            slides[1].mainPic.transform = CGAffineTransform(scaleX: percentOffset.x/0.25, y: percentOffset.x/0.25)

                                            } else if(percentOffset.x > 0.25 && percentOffset.x <= 0.50) {
                                            slides[1].mainPic.transform = CGAffineTransform(scaleX: (0.50-percentOffset.x)/0.25, y: (0.50-percentOffset.x)/0.25)
                                            slides[2].mainPic.transform = CGAffineTransform(scaleX: percentOffset.x/0.50, y: percentOffset.x/0.50)

                                            } else if(percentOffset.x > 0.50 && percentOffset.x <= 0.75) {
                                            slides[2].mainPic.transform = CGAffineTransform(scaleX: (0.75-percentOffset.x)/0.25, y: (0.75-percentOffset.x)/0.25)
                                            slides[3].mainPic.transform = CGAffineTransform(scaleX: percentOffset.x/0.75, y: percentOffset.x/0.75)

                                            } else if(percentOffset.x > 0.75 && percentOffset.x <= 1) {
                                            slides[3].mainPic.transform = CGAffineTransform(scaleX: (1-percentOffset.x)/0.25, y: (1-percentOffset.x)/0.25)
                                            slides[4].mainPic.transform = CGAffineTransform(scaleX: percentOffset.x, y: percentOffset.x)
                                            }
                                            }

                                            override func prepare(for segue: UIStoryboardSegue, sender: Any?) {
                                            if segue.identifier == "findingClinitionSugue" {
                                            let destination = segue.destination as! FirstAvailableSearchViewController
                                            //destination.consumer = consumer
                                            }

                                            if (timer != nil) {
                                            timer?.invalidate()
                                            }
                                            }

                                            // protocol functions

                                            func initlizeSlides() {
                                            slides = createSlides()
                                            setupSlideScrollView(slides: slides)
                                            }

                                            func initlizeTimer() {
                                            scheduleTimer(5)
                                            }
                                            }





                                            share|improve this answer




























                                              0












                                              0








                                              0







                                              This turned out to be quite an interesting problem...



                                              While it is easy to lock UIScrollView scrolling to one axis only using the UIScrollViewDelegate, it is impossible to provide smooth scrolling while changing the scrolling programmatically (as you do with the Timer) at the same time.



                                              Below, you will find a DirectionLockingScrollView class I just wrote that should make things easier for you. It's a UIScrollView that you can initialize either programmatically, or via the Interface Builder.



                                              It features isHorizontalScrollingEnabled and isVerticalScrollingEnabled properties.



                                              HOW IT WORKS INTERNALLY



                                              It adds a second "control" UIScrollView that is identical to the main DirectionLockingScrollView and propagates to it all pan events intended for the main scroll view. Every time the "control" scroll view's bounds change, the change is propagated to the main scroll view BUT x and y are altered (based on isHorizontalScrollingEnabled and isVerticalScrollingEnabled) to disable scrolling on the requested axis.



                                              DirectionLockingScrollView.swift



                                              /// `UIScrollView` subclass that supports disabling scrolling on any direction
                                              /// while allowing the other direction to be changed programmatically (via
                                              /// `setContentOffset(_:animated)` or `scrollRectToVisible(_:animated)` or changing the
                                              /// bounds etc.
                                              ///
                                              /// Can be initialized programmatically or via the Interface Builder.
                                              class DirectionLockingScrollView: UIScrollView {
                                              var isHorizontalScrollingEnabled = true
                                              var isVerticalScrollingEnabled = true

                                              /// The control scrollview is added below the `DirectionLockingScrollView`
                                              /// and is used to implement all native scrollview behaviours (such as bouncing)
                                              /// based on user input.
                                              ///
                                              /// It is required to be able to change the bounds of the `DirectionLockingScrollView`
                                              /// while maintaining scrolling in only one direction and allowing for setting the contentOffset
                                              /// (changing scrolling for any axis - even the disabled ones) programmatically.
                                              private let _controlScrollView = UIScrollView(frame: .zero)

                                              required init?(coder aDecoder: NSCoder) {
                                              super.init(coder: aDecoder)
                                              installCustomScrollView()
                                              }

                                              override init(frame: CGRect) {
                                              super.init(frame: frame)
                                              installCustomScrollView()
                                              }

                                              override func layoutSubviews() {
                                              super.layoutSubviews()
                                              updateCustomScrollViewFrame()
                                              }

                                              override func didMoveToSuperview() {
                                              super.didMoveToSuperview()
                                              guard let superview = superview else {
                                              _controlScrollView.removeFromSuperview()
                                              return
                                              }

                                              superview.insertSubview(_controlScrollView, belowSubview: self)
                                              updateCustomScrollViewFrame()
                                              }

                                              // MARK: - UIEvent propagation

                                              func viewIgnoresEvents(_ view: UIView?) -> Bool {
                                              let viewIgnoresEvents =
                                              view == nil ||
                                              view == self ||
                                              !view!.isUserInteractionEnabled ||
                                              !(view is UIControl && (view!.gestureRecognizers ?? ).count == 0)

                                              return viewIgnoresEvents
                                              }

                                              override func hitTest(_ point: CGPoint, with event: UIEvent?) -> UIView? {
                                              let view = super.hitTest(point, with: event)
                                              if viewIgnoresEvents(view) {
                                              return _controlScrollView
                                              }

                                              return view
                                              }

                                              // MARK: - Main scrollview settings propagation to `controlScrollView`

                                              override var contentInset: UIEdgeInsets {
                                              didSet {
                                              _controlScrollView.contentInset = contentInset
                                              }
                                              }

                                              override var contentScaleFactor: CGFloat {
                                              didSet {
                                              _controlScrollView.contentScaleFactor = contentScaleFactor
                                              }
                                              }

                                              override var contentSize: CGSize {
                                              didSet {
                                              _controlScrollView.contentSize = contentSize
                                              }
                                              }

                                              override var bounces: Bool {
                                              didSet {
                                              _controlScrollView.bounces = bounces
                                              }
                                              }

                                              override var bouncesZoom: Bool {
                                              didSet {
                                              _controlScrollView.bouncesZoom = bouncesZoom
                                              }
                                              }
                                              }

                                              extension DirectionLockingScrollView: UIScrollViewDelegate {
                                              func scrollViewDidScroll(_ scrollView: UIScrollView) {
                                              updateBoundsFromCustomScrollView(scrollView)
                                              }
                                              }

                                              private extension DirectionLockingScrollView {
                                              /// Propagates `controlScrollView` bounds to the actual scrollview.
                                              /// - Parameter scrollView: If the scrollview provided is not the `controlScrollView`
                                              // the main scrollview bounds are not updated.
                                              func updateBoundsFromCustomScrollView(_ scrollView: UIScrollView) {
                                              if scrollView != _controlScrollView {
                                              return
                                              }

                                              var newBounds = scrollView.bounds.origin
                                              if !isHorizontalScrollingEnabled {
                                              newBounds.x = self.contentOffset.x
                                              }

                                              if !isVerticalScrollingEnabled {
                                              newBounds.y = self.contentOffset.y
                                              }

                                              bounds.origin = newBounds
                                              }

                                              func installCustomScrollView() {
                                              _controlScrollView.delegate = self
                                              _controlScrollView.contentSize = contentSize
                                              _controlScrollView.showsVerticalScrollIndicator = false
                                              _controlScrollView.showsHorizontalScrollIndicator = false

                                              // The panGestureRecognizer is removed because pan gestures might be triggered
                                              // on subviews of the scrollview which do not ignore touch events (determined
                                              // by `viewIgnoresEvents(_ view: UIView?)`). This can happen for example
                                              // if you tap and drag on a button inside the scroll view.
                                              removeGestureRecognizer(panGestureRecognizer)
                                              }

                                              func updateCustomScrollViewFrame() {
                                              if _controlScrollView.frame == frame { return }
                                              _controlScrollView.frame = frame
                                              }
                                              }


                                              USAGE



                                              After you've included the above class in your app, don't forget to change your scroll view's class to DirectionLockingScrollView in your .xib or .storyboard.



                                              Then update your code as below (only two lines changed, marked with // *****).



                                              class CaruselleScreenViewController: UIViewController, CaruselleScreenViewProtocol, UIScrollViewDelegate {
                                              var myPresenter: CaruselleScreenPresenterProtocol?

                                              @IBOutlet weak var pageControl: UIPageControl!
                                              @IBOutlet weak var scrollView: DirectionLockingScrollView! // *****

                                              var slides:[CaruselleTipsCard] = ;


                                              var timer:Timer?
                                              var currentPageMultiplayer = 0

                                              override func viewDidLoad() {
                                              super.viewDidLoad()

                                              myPresenter = CaruselleScreenPresenter(controller: self)

                                              //initlizes view
                                              pageControl.numberOfPages = slides.count
                                              pageControl.currentPage = 0
                                              view.bringSubview(toFront: pageControl)

                                              scrollView.isHorizontalScrollingEnabled = false // *****

                                              //delegates
                                              scrollView.delegate = self

                                              ////blocks vertical movement
                                              scrollView.showsVerticalScrollIndicator = false
                                              //scrollView.contentSize = CGSize(width: scrollView.contentSize.width, height: 0) //disable vertical
                                              }

                                              func scheduleTimer(_ timeInterval: TimeInterval){
                                              timer = Timer.scheduledTimer(timeInterval: timeInterval, target: self, selector: #selector(timerCall), userInfo: nil, repeats: false)
                                              }

                                              @objc func timerCall(){
                                              print("Timer executed")

                                              currentPageMultiplayer = currentPageMultiplayer + 1

                                              if (currentPageMultiplayer == 5) {
                                              currentPageMultiplayer = 0
                                              }
                                              pageControl.currentPage = currentPageMultiplayer
                                              scrollToPage(pageToMove: currentPageMultiplayer)

                                              scheduleTimer(5)
                                              }

                                              func scrollToPage(pageToMove: Int) {
                                              print ("new one")
                                              var frame: CGRect = scrollView.frame
                                              frame.origin.x = frame.size.width * CGFloat(pageToMove)
                                              frame.origin.y = -35
                                              scrollView.scrollRectToVisible(frame, animated: true)
                                              }


                                              func createSlides() -> [CaruselleTipsCard] {

                                              let slide1:CaruselleTipsCard = Bundle.main.loadNibNamed("CaruselleTipsCard", owner: self, options: nil)?.first as! CaruselleTipsCard
                                              slide1.mainPic.image = UIImage(named: "backlightingIllo")

                                              //
                                              let slide2:CaruselleTipsCard = Bundle.main.loadNibNamed("CaruselleTipsCard", owner: self, options: nil)?.first as! CaruselleTipsCard
                                              slide2.mainPic.image = UIImage(named: "comfortableIllo")

                                              //
                                              let slide3:CaruselleTipsCard = Bundle.main.loadNibNamed("CaruselleTipsCard", owner: self, options: nil)?.first as! CaruselleTipsCard
                                              slide3.mainPic.image = UIImage(named: "pharmacyIllo")

                                              //
                                              let slide4:CaruselleTipsCard = Bundle.main.loadNibNamed("CaruselleTipsCard", owner: self, options: nil)?.first as! CaruselleTipsCard
                                              slide4.mainPic.image = UIImage(named: "batteryIllo")

                                              //
                                              let slide5:CaruselleTipsCard = Bundle.main.loadNibNamed("CaruselleTipsCard", owner: self, options: nil)?.first as! CaruselleTipsCard
                                              slide5.mainPic.image = UIImage(named: "wiFiIllo")

                                              return [slide1, slide2, slide3, slide4, slide5]
                                              }

                                              func setupSlideScrollView(slides : [CaruselleTipsCard]) {
                                              scrollView.frame = CGRect(x: 0, y: 0, width: view.frame.width, height: view.frame.height)
                                              scrollView.contentSize = CGSize(width: view.frame.width * CGFloat(slides.count), height: view.frame.height)
                                              scrollView.isPagingEnabled = true

                                              for i in 0 ..< slides.count {
                                              slides[i].frame = CGRect(x: view.frame.width * CGFloat(i), y: 0, width: view.frame.width, height: view.frame.height)
                                              scrollView.addSubview(slides[i])
                                              }
                                              }


                                              //////

                                              /*
                                              * default function called when view is scrolled. In order to enable callback
                                              * when scrollview is scrolled, the below code needs to be called:
                                              * slideScrollView.delegate = self or
                                              */
                                              func scrollViewDidScroll(_ scrollView: UIScrollView) {
                                              let pageIndex = round(scrollView.contentOffset.x/view.frame.width)
                                              pageControl.currentPage = Int(pageIndex)

                                              let maximumHorizontalOffset: CGFloat = scrollView.contentSize.width - scrollView.frame.width
                                              let currentHorizontalOffset: CGFloat = scrollView.contentOffset.x

                                              // vertical
                                              let maximumVerticalOffset: CGFloat = scrollView.contentSize.height - scrollView.frame.height
                                              let currentVerticalOffset: CGFloat = scrollView.contentOffset.y

                                              let percentageHorizontalOffset: CGFloat = currentHorizontalOffset / maximumHorizontalOffset
                                              let percentageVerticalOffset: CGFloat = currentVerticalOffset / maximumVerticalOffset


                                              /*
                                              * below code changes the background color of view on paging the scrollview
                                              */
                                              // self.scrollView(scrollView, didScrollToPercentageOffset: percentageHorizontalOffset)


                                              /*
                                              * below code scales the imageview on paging the scrollview
                                              */
                                              let percentOffset: CGPoint = CGPoint(x: percentageHorizontalOffset, y: percentageVerticalOffset)

                                              if(percentOffset.x > 0 && percentOffset.x <= 0.25) {

                                              slides[0].mainPic.transform = CGAffineTransform(scaleX: (0.25-percentOffset.x)/0.25, y: (0.25-percentOffset.x)/0.25)
                                              slides[1].mainPic.transform = CGAffineTransform(scaleX: percentOffset.x/0.25, y: percentOffset.x/0.25)

                                              } else if(percentOffset.x > 0.25 && percentOffset.x <= 0.50) {
                                              slides[1].mainPic.transform = CGAffineTransform(scaleX: (0.50-percentOffset.x)/0.25, y: (0.50-percentOffset.x)/0.25)
                                              slides[2].mainPic.transform = CGAffineTransform(scaleX: percentOffset.x/0.50, y: percentOffset.x/0.50)

                                              } else if(percentOffset.x > 0.50 && percentOffset.x <= 0.75) {
                                              slides[2].mainPic.transform = CGAffineTransform(scaleX: (0.75-percentOffset.x)/0.25, y: (0.75-percentOffset.x)/0.25)
                                              slides[3].mainPic.transform = CGAffineTransform(scaleX: percentOffset.x/0.75, y: percentOffset.x/0.75)

                                              } else if(percentOffset.x > 0.75 && percentOffset.x <= 1) {
                                              slides[3].mainPic.transform = CGAffineTransform(scaleX: (1-percentOffset.x)/0.25, y: (1-percentOffset.x)/0.25)
                                              slides[4].mainPic.transform = CGAffineTransform(scaleX: percentOffset.x, y: percentOffset.x)
                                              }
                                              }

                                              override func prepare(for segue: UIStoryboardSegue, sender: Any?) {
                                              if segue.identifier == "findingClinitionSugue" {
                                              let destination = segue.destination as! FirstAvailableSearchViewController
                                              //destination.consumer = consumer
                                              }

                                              if (timer != nil) {
                                              timer?.invalidate()
                                              }
                                              }

                                              // protocol functions

                                              func initlizeSlides() {
                                              slides = createSlides()
                                              setupSlideScrollView(slides: slides)
                                              }

                                              func initlizeTimer() {
                                              scheduleTimer(5)
                                              }
                                              }





                                              share|improve this answer















                                              This turned out to be quite an interesting problem...



                                              While it is easy to lock UIScrollView scrolling to one axis only using the UIScrollViewDelegate, it is impossible to provide smooth scrolling while changing the scrolling programmatically (as you do with the Timer) at the same time.



                                              Below, you will find a DirectionLockingScrollView class I just wrote that should make things easier for you. It's a UIScrollView that you can initialize either programmatically, or via the Interface Builder.



                                              It features isHorizontalScrollingEnabled and isVerticalScrollingEnabled properties.



                                              HOW IT WORKS INTERNALLY



                                              It adds a second "control" UIScrollView that is identical to the main DirectionLockingScrollView and propagates to it all pan events intended for the main scroll view. Every time the "control" scroll view's bounds change, the change is propagated to the main scroll view BUT x and y are altered (based on isHorizontalScrollingEnabled and isVerticalScrollingEnabled) to disable scrolling on the requested axis.



                                              DirectionLockingScrollView.swift



                                              /// `UIScrollView` subclass that supports disabling scrolling on any direction
                                              /// while allowing the other direction to be changed programmatically (via
                                              /// `setContentOffset(_:animated)` or `scrollRectToVisible(_:animated)` or changing the
                                              /// bounds etc.
                                              ///
                                              /// Can be initialized programmatically or via the Interface Builder.
                                              class DirectionLockingScrollView: UIScrollView {
                                              var isHorizontalScrollingEnabled = true
                                              var isVerticalScrollingEnabled = true

                                              /// The control scrollview is added below the `DirectionLockingScrollView`
                                              /// and is used to implement all native scrollview behaviours (such as bouncing)
                                              /// based on user input.
                                              ///
                                              /// It is required to be able to change the bounds of the `DirectionLockingScrollView`
                                              /// while maintaining scrolling in only one direction and allowing for setting the contentOffset
                                              /// (changing scrolling for any axis - even the disabled ones) programmatically.
                                              private let _controlScrollView = UIScrollView(frame: .zero)

                                              required init?(coder aDecoder: NSCoder) {
                                              super.init(coder: aDecoder)
                                              installCustomScrollView()
                                              }

                                              override init(frame: CGRect) {
                                              super.init(frame: frame)
                                              installCustomScrollView()
                                              }

                                              override func layoutSubviews() {
                                              super.layoutSubviews()
                                              updateCustomScrollViewFrame()
                                              }

                                              override func didMoveToSuperview() {
                                              super.didMoveToSuperview()
                                              guard let superview = superview else {
                                              _controlScrollView.removeFromSuperview()
                                              return
                                              }

                                              superview.insertSubview(_controlScrollView, belowSubview: self)
                                              updateCustomScrollViewFrame()
                                              }

                                              // MARK: - UIEvent propagation

                                              func viewIgnoresEvents(_ view: UIView?) -> Bool {
                                              let viewIgnoresEvents =
                                              view == nil ||
                                              view == self ||
                                              !view!.isUserInteractionEnabled ||
                                              !(view is UIControl && (view!.gestureRecognizers ?? ).count == 0)

                                              return viewIgnoresEvents
                                              }

                                              override func hitTest(_ point: CGPoint, with event: UIEvent?) -> UIView? {
                                              let view = super.hitTest(point, with: event)
                                              if viewIgnoresEvents(view) {
                                              return _controlScrollView
                                              }

                                              return view
                                              }

                                              // MARK: - Main scrollview settings propagation to `controlScrollView`

                                              override var contentInset: UIEdgeInsets {
                                              didSet {
                                              _controlScrollView.contentInset = contentInset
                                              }
                                              }

                                              override var contentScaleFactor: CGFloat {
                                              didSet {
                                              _controlScrollView.contentScaleFactor = contentScaleFactor
                                              }
                                              }

                                              override var contentSize: CGSize {
                                              didSet {
                                              _controlScrollView.contentSize = contentSize
                                              }
                                              }

                                              override var bounces: Bool {
                                              didSet {
                                              _controlScrollView.bounces = bounces
                                              }
                                              }

                                              override var bouncesZoom: Bool {
                                              didSet {
                                              _controlScrollView.bouncesZoom = bouncesZoom
                                              }
                                              }
                                              }

                                              extension DirectionLockingScrollView: UIScrollViewDelegate {
                                              func scrollViewDidScroll(_ scrollView: UIScrollView) {
                                              updateBoundsFromCustomScrollView(scrollView)
                                              }
                                              }

                                              private extension DirectionLockingScrollView {
                                              /// Propagates `controlScrollView` bounds to the actual scrollview.
                                              /// - Parameter scrollView: If the scrollview provided is not the `controlScrollView`
                                              // the main scrollview bounds are not updated.
                                              func updateBoundsFromCustomScrollView(_ scrollView: UIScrollView) {
                                              if scrollView != _controlScrollView {
                                              return
                                              }

                                              var newBounds = scrollView.bounds.origin
                                              if !isHorizontalScrollingEnabled {
                                              newBounds.x = self.contentOffset.x
                                              }

                                              if !isVerticalScrollingEnabled {
                                              newBounds.y = self.contentOffset.y
                                              }

                                              bounds.origin = newBounds
                                              }

                                              func installCustomScrollView() {
                                              _controlScrollView.delegate = self
                                              _controlScrollView.contentSize = contentSize
                                              _controlScrollView.showsVerticalScrollIndicator = false
                                              _controlScrollView.showsHorizontalScrollIndicator = false

                                              // The panGestureRecognizer is removed because pan gestures might be triggered
                                              // on subviews of the scrollview which do not ignore touch events (determined
                                              // by `viewIgnoresEvents(_ view: UIView?)`). This can happen for example
                                              // if you tap and drag on a button inside the scroll view.
                                              removeGestureRecognizer(panGestureRecognizer)
                                              }

                                              func updateCustomScrollViewFrame() {
                                              if _controlScrollView.frame == frame { return }
                                              _controlScrollView.frame = frame
                                              }
                                              }


                                              USAGE



                                              After you've included the above class in your app, don't forget to change your scroll view's class to DirectionLockingScrollView in your .xib or .storyboard.



                                              Then update your code as below (only two lines changed, marked with // *****).



                                              class CaruselleScreenViewController: UIViewController, CaruselleScreenViewProtocol, UIScrollViewDelegate {
                                              var myPresenter: CaruselleScreenPresenterProtocol?

                                              @IBOutlet weak var pageControl: UIPageControl!
                                              @IBOutlet weak var scrollView: DirectionLockingScrollView! // *****

                                              var slides:[CaruselleTipsCard] = ;


                                              var timer:Timer?
                                              var currentPageMultiplayer = 0

                                              override func viewDidLoad() {
                                              super.viewDidLoad()

                                              myPresenter = CaruselleScreenPresenter(controller: self)

                                              //initlizes view
                                              pageControl.numberOfPages = slides.count
                                              pageControl.currentPage = 0
                                              view.bringSubview(toFront: pageControl)

                                              scrollView.isHorizontalScrollingEnabled = false // *****

                                              //delegates
                                              scrollView.delegate = self

                                              ////blocks vertical movement
                                              scrollView.showsVerticalScrollIndicator = false
                                              //scrollView.contentSize = CGSize(width: scrollView.contentSize.width, height: 0) //disable vertical
                                              }

                                              func scheduleTimer(_ timeInterval: TimeInterval){
                                              timer = Timer.scheduledTimer(timeInterval: timeInterval, target: self, selector: #selector(timerCall), userInfo: nil, repeats: false)
                                              }

                                              @objc func timerCall(){
                                              print("Timer executed")

                                              currentPageMultiplayer = currentPageMultiplayer + 1

                                              if (currentPageMultiplayer == 5) {
                                              currentPageMultiplayer = 0
                                              }
                                              pageControl.currentPage = currentPageMultiplayer
                                              scrollToPage(pageToMove: currentPageMultiplayer)

                                              scheduleTimer(5)
                                              }

                                              func scrollToPage(pageToMove: Int) {
                                              print ("new one")
                                              var frame: CGRect = scrollView.frame
                                              frame.origin.x = frame.size.width * CGFloat(pageToMove)
                                              frame.origin.y = -35
                                              scrollView.scrollRectToVisible(frame, animated: true)
                                              }


                                              func createSlides() -> [CaruselleTipsCard] {

                                              let slide1:CaruselleTipsCard = Bundle.main.loadNibNamed("CaruselleTipsCard", owner: self, options: nil)?.first as! CaruselleTipsCard
                                              slide1.mainPic.image = UIImage(named: "backlightingIllo")

                                              //
                                              let slide2:CaruselleTipsCard = Bundle.main.loadNibNamed("CaruselleTipsCard", owner: self, options: nil)?.first as! CaruselleTipsCard
                                              slide2.mainPic.image = UIImage(named: "comfortableIllo")

                                              //
                                              let slide3:CaruselleTipsCard = Bundle.main.loadNibNamed("CaruselleTipsCard", owner: self, options: nil)?.first as! CaruselleTipsCard
                                              slide3.mainPic.image = UIImage(named: "pharmacyIllo")

                                              //
                                              let slide4:CaruselleTipsCard = Bundle.main.loadNibNamed("CaruselleTipsCard", owner: self, options: nil)?.first as! CaruselleTipsCard
                                              slide4.mainPic.image = UIImage(named: "batteryIllo")

                                              //
                                              let slide5:CaruselleTipsCard = Bundle.main.loadNibNamed("CaruselleTipsCard", owner: self, options: nil)?.first as! CaruselleTipsCard
                                              slide5.mainPic.image = UIImage(named: "wiFiIllo")

                                              return [slide1, slide2, slide3, slide4, slide5]
                                              }

                                              func setupSlideScrollView(slides : [CaruselleTipsCard]) {
                                              scrollView.frame = CGRect(x: 0, y: 0, width: view.frame.width, height: view.frame.height)
                                              scrollView.contentSize = CGSize(width: view.frame.width * CGFloat(slides.count), height: view.frame.height)
                                              scrollView.isPagingEnabled = true

                                              for i in 0 ..< slides.count {
                                              slides[i].frame = CGRect(x: view.frame.width * CGFloat(i), y: 0, width: view.frame.width, height: view.frame.height)
                                              scrollView.addSubview(slides[i])
                                              }
                                              }


                                              //////

                                              /*
                                              * default function called when view is scrolled. In order to enable callback
                                              * when scrollview is scrolled, the below code needs to be called:
                                              * slideScrollView.delegate = self or
                                              */
                                              func scrollViewDidScroll(_ scrollView: UIScrollView) {
                                              let pageIndex = round(scrollView.contentOffset.x/view.frame.width)
                                              pageControl.currentPage = Int(pageIndex)

                                              let maximumHorizontalOffset: CGFloat = scrollView.contentSize.width - scrollView.frame.width
                                              let currentHorizontalOffset: CGFloat = scrollView.contentOffset.x

                                              // vertical
                                              let maximumVerticalOffset: CGFloat = scrollView.contentSize.height - scrollView.frame.height
                                              let currentVerticalOffset: CGFloat = scrollView.contentOffset.y

                                              let percentageHorizontalOffset: CGFloat = currentHorizontalOffset / maximumHorizontalOffset
                                              let percentageVerticalOffset: CGFloat = currentVerticalOffset / maximumVerticalOffset


                                              /*
                                              * below code changes the background color of view on paging the scrollview
                                              */
                                              // self.scrollView(scrollView, didScrollToPercentageOffset: percentageHorizontalOffset)


                                              /*
                                              * below code scales the imageview on paging the scrollview
                                              */
                                              let percentOffset: CGPoint = CGPoint(x: percentageHorizontalOffset, y: percentageVerticalOffset)

                                              if(percentOffset.x > 0 && percentOffset.x <= 0.25) {

                                              slides[0].mainPic.transform = CGAffineTransform(scaleX: (0.25-percentOffset.x)/0.25, y: (0.25-percentOffset.x)/0.25)
                                              slides[1].mainPic.transform = CGAffineTransform(scaleX: percentOffset.x/0.25, y: percentOffset.x/0.25)

                                              } else if(percentOffset.x > 0.25 && percentOffset.x <= 0.50) {
                                              slides[1].mainPic.transform = CGAffineTransform(scaleX: (0.50-percentOffset.x)/0.25, y: (0.50-percentOffset.x)/0.25)
                                              slides[2].mainPic.transform = CGAffineTransform(scaleX: percentOffset.x/0.50, y: percentOffset.x/0.50)

                                              } else if(percentOffset.x > 0.50 && percentOffset.x <= 0.75) {
                                              slides[2].mainPic.transform = CGAffineTransform(scaleX: (0.75-percentOffset.x)/0.25, y: (0.75-percentOffset.x)/0.25)
                                              slides[3].mainPic.transform = CGAffineTransform(scaleX: percentOffset.x/0.75, y: percentOffset.x/0.75)

                                              } else if(percentOffset.x > 0.75 && percentOffset.x <= 1) {
                                              slides[3].mainPic.transform = CGAffineTransform(scaleX: (1-percentOffset.x)/0.25, y: (1-percentOffset.x)/0.25)
                                              slides[4].mainPic.transform = CGAffineTransform(scaleX: percentOffset.x, y: percentOffset.x)
                                              }
                                              }

                                              override func prepare(for segue: UIStoryboardSegue, sender: Any?) {
                                              if segue.identifier == "findingClinitionSugue" {
                                              let destination = segue.destination as! FirstAvailableSearchViewController
                                              //destination.consumer = consumer
                                              }

                                              if (timer != nil) {
                                              timer?.invalidate()
                                              }
                                              }

                                              // protocol functions

                                              func initlizeSlides() {
                                              slides = createSlides()
                                              setupSlideScrollView(slides: slides)
                                              }

                                              func initlizeTimer() {
                                              scheduleTimer(5)
                                              }
                                              }






                                              share|improve this answer














                                              share|improve this answer



                                              share|improve this answer








                                              edited Jan 23 at 2:37









                                              Cœur

                                              18k9108148




                                              18k9108148










                                              answered Jan 9 at 2:07









                                              m_katsifarakism_katsifarakis

                                              598614




                                              598614






























                                                  draft saved

                                                  draft discarded




















































                                                  Thanks for contributing an answer to Stack Overflow!


                                                  • Please be sure to answer the question. Provide details and share your research!

                                                  But avoid



                                                  • Asking for help, clarification, or responding to other answers.

                                                  • Making statements based on opinion; back them up with references or personal experience.


                                                  To learn more, see our tips on writing great answers.




                                                  draft saved


                                                  draft discarded














                                                  StackExchange.ready(
                                                  function () {
                                                  StackExchange.openid.initPostLogin('.new-post-login', 'https%3a%2f%2fstackoverflow.com%2fquestions%2f53985780%2fissue-in-blocking-vertical-scroll-on-uiscrollview-in-swift-4-0%23new-answer', 'question_page');
                                                  }
                                                  );

                                                  Post as a guest















                                                  Required, but never shown





















































                                                  Required, but never shown














                                                  Required, but never shown












                                                  Required, but never shown







                                                  Required, but never shown

































                                                  Required, but never shown














                                                  Required, but never shown












                                                  Required, but never shown







                                                  Required, but never shown







                                                  Popular posts from this blog

                                                  Monofisismo

                                                  Angular Downloading a file using contenturl with Basic Authentication

                                                  Olmecas