Paging UIScrollView seems to place content off centre - ios

I have a UIScrollView that I want to have paging functionality (think an initial splash screen). I want that content (a UILabel and a UIImageView) to be placed centrally in each paging view on the scrollView. My problem is is that it is always slightly off centre ().
Here is the complete code:
var splashScreenObjects = [SplashScreenObject]()
var imageViewArray = [UIImageView]()
var subtitleViewArray = [UILabel]()
#IBOutlet var scrollView: UIScrollView!
#IBOutlet var pageControl: UIPageControl!
override func viewDidLoad() {
super.viewDidLoad()
createSplashScreenObjects()
configurePageControl()
configureScrollView()
}
func createSplashScreenObjects() {
let firstScreen: SplashScreenObject = SplashScreenObject(subtitle: "Medication reminders on your phone. Never miss your next dose", image: UIImage(named: "splashScreen1")!)
let secondScreen: SplashScreenObject = SplashScreenObject(subtitle: "Track how good you have been with your medication", image: UIImage(named: "splashScreen2")!)
let thirdScreen: SplashScreenObject = SplashScreenObject(subtitle: "The better you are with your medication, the more points you'll earn!", image: UIImage(named: "splashScreen3")!)
splashScreenObjects.append(firstScreen)
splashScreenObjects.append(secondScreen)
splashScreenObjects.append(thirdScreen)
}
func configureScrollView() {
self.scrollView.layoutIfNeeded()
self.scrollView.showsHorizontalScrollIndicator = false
self.scrollView.showsVerticalScrollIndicator = false
self.scrollView.pagingEnabled = true
self.scrollView.delegate = self
let width = view.frame.size.width
for index in 0..<splashScreenObjects.count {
let subtitle = UILabel(frame: CGRectMake((width * CGFloat(index)) + 25, self.scrollView.frame.size.height-75, width-50, 75))
subtitle.text = splashScreenObjects[index].subtitle
subtitle.textAlignment = NSTextAlignment.Center
subtitle.textColor = UIColor.whiteColor()
subtitle.font = UIFont(name:"Ubuntu", size: 16)
subtitle.numberOfLines = 2
subtitle.backgroundColor = UIColor.clearColor()
self.scrollView.addSubview(subtitle)
self.subtitleViewArray.append(subtitle)
subtitle.alpha = 0
let mainImage = UIImageView(frame: CGRectMake((width * CGFloat(index)), 50, width, self.scrollView.frame.size.height-150))
mainImage.image = splashScreenObjects[index].image
mainImage.contentMode = UIViewContentMode.ScaleAspectFit
self.scrollView.addSubview(mainImage)
self.imageViewArray.append(mainImage)
mainImage.alpha = 0
}
self.scrollView.contentSize = CGSizeMake(width * CGFloat(splashScreenObjects.count), self.scrollView.frame.size.height-50)
animateViews(Int(0))
}
func configurePageControl() {
self.pageControl.numberOfPages = splashScreenObjects.count
self.pageControl.currentPage = 0
self.view.addSubview(pageControl)
pageControl.addTarget(self, action: #selector(SplashViewController.changePage(_:)), forControlEvents: UIControlEvents.ValueChanged)
}
func changePage(sender: AnyObject) -> () {
let x = CGFloat(pageControl.currentPage) * self.view.frame.size.width
scrollView.setContentOffset(CGPointMake(x, 0), animated: true)
}
func scrollViewDidEndDecelerating(scrollView: UIScrollView) {
let pageNumber = round(scrollView.contentOffset.x / self.view.frame.size.width)
pageControl.currentPage = Int(pageNumber)
animateViews(Int(pageNumber))
}
func animateViews(pageNumber: Int) {
UIView.animateWithDuration(0.5, animations: {
self.imageViewArray[pageNumber].alpha = 1.0
self.subtitleViewArray[pageNumber].alpha = 1.0
})
}
Here are my auto layout constraints for the UIScrollView:

Your leading and trailing spaces are both -20, which means that the scroll view is 40 points wider than its superview. Change these to 0.

You should replace
self.scrollView.layoutIfNeeded()
to
self.view.layoutIfNeeded()
because layoutIfNeeded layout caller subviews, not itself. So, scrollView, when you add subtitle and mainImage on it, has wrong frame.

Related

UIPageControl and UIScrollView not scrolling

I'm having a relatively simple UIViewController with a UIScrollView that's taking relatively half the screen and a UIImageView placed inside the UIScrollView that's the exact same size as the UIScrollView.
On top of the UIImageView there's a UIPageControl. The point is have a horizontal scrolling and present an image like a slider based on the amount of images in an array. The problem is that the scroll view is not scrolling and I don't know why.
#IBOutlet weak var scrollView: UIScrollView!
#IBOutlet weak var imageView: UIImageView!
#IBOutlet weak var pageControl: UIPageControl!
let imagelist = ["3.jpg", "1.jpg", "2.png", "4.png", "5.png"]
override func viewDidLoad() {
super.viewDidLoad()
scrollView.delegate = self
configurePageControl()
for i in stride(from: 0, to: imagelist.count, by: 1) {
var frame = CGRect.zero
frame.origin.x = self.scrollView.frame.size.width * CGFloat(i)
frame.origin.y = 0
frame.size = self.scrollView.frame.size
scrollView.isPagingEnabled = true
scrollView.isScrollEnabled = true
let myImage:UIImage = UIImage(named: imagelist[i])!
let bgColorFromImage = myImage.averageColor
imageView.image = myImage
imageView.contentMode = UIViewContentMode.scaleAspectFit
imageView.frame = frame
scrollView.backgroundColor = bgColorFromImage
scrollView.addSubview(imageView)
}
self.scrollView.contentSize = CGSize(width: self.scrollView.frame.size.width * CGFloat(imagelist.count), height: self.scrollView.frame.size.height)
pageControl.addTarget(self, action: #selector(changePage), for: UIControlEvents.valueChanged)
}
func configurePageControl() {
self.pageControl.numberOfPages = imagelist.count
self.pageControl.currentPage = 0
self.pageControl.tintColor = UIColor.red
self.pageControl.pageIndicatorTintColor = UIColor.black
self.pageControl.currentPageIndicatorTintColor = UIColor.green
self.imageView.addSubview(pageControl)
}
#objc func changePage() {
let x = CGFloat(pageControl.currentPage) * scrollView.frame.size.width
scrollView.setContentOffset(CGPoint(x: x,y :0), animated: true)
}
func scrollViewDidEndDecelerating(_ scrollView: UIScrollView) {
let pageNumber = round(scrollView.contentOffset.x / scrollView.frame.size.width)
pageControl.currentPage = Int(pageNumber)
}
This is what the UIStoryboard looks like:
Inside the for loop you use the same object of imageView , you only set the frame and the image
imageView.frame = frame
imageView.image = myImage
but you have to create a new instance of the UIImageView
//
Suppose you have a scrollView in IB with top , leading and trailing constraints to the superView , and a height of say 200 , you can add imageViews dynamically like this
class ViewController: UIViewController {
#IBOutlet weak var scrollView: UIScrollView!
override func viewDidLoad() {
super.viewDidLoad()
for i in 0..<10 {
let f = CGRect(x: CGFloat(i) * scrollView.frame.width, y: 0, width: scrollView.frame.width, height: scrollView.frame.height)
let imgV = UIImageView(frame: f)
imgV.image = UIImage(named: "re-fuel.png")
scrollView.addSubview(imgV)
}
scrollView.contentSize = CGSize(width: CGFloat(10) * scrollView.frame.width, height: scrollView.frame.height)
}
}
Result
The problem is that the scroll view itself is positioned with autolayout. Once you do that, you cannot set the contentSize to make the scroll view scrollable. You must use internal constraints to configure the content size.

Infinite loop scrolling using UIScrollView in Swift

I am trying to make an infinite loop image gallery app. I did it by setting up a UIScrollView inside which I inserted UIImageViews.
I am able to load 4 images and swipe between them, but the problem I have is how to implement the infinite scroll, so that after the last image, the first one appears and opposite.
As I am newbie in Swift, I don't know how to handle this problem nor where to start. I will appreciate any suggestion, example or link on how to solve this problem.
Thanks in advance!
Here is the peace of my code:
class FirstViewController: UIViewController {
#IBOutlet weak var scrollView: UIScrollView!
override func viewDidLoad() {
super.viewDidLoad()
self.scrollView.frame = CGRectMake(0, 0, self.view.frame.width, self.view.frame.height)
let scrollViewWidth: CGFloat = self.scrollView.frame.width
let scrollViewHeight: CGFloat = self.scrollView.frame.height
let numPics: Int = 3
let imgOne = UIImageView()
let imgTwo = UIImageView()
let imgThree = UIImageView()
let imgFour = UIImageView()
var arrPics = [imgOne, imgTwo, imgThree, imgFour]
var arrSlide = ["slide1.png", "slide2.png", "slide3.png", "slide4.png"]
for i in 0...numPics {
arrPics[i] = UIImageView(frame: CGRectMake(0,scrollViewHeight * CGFloat(i),scrollViewWidth, scrollViewHeight))
arrPics[i].image = UIImage(named: arrSlide[i])
self.scrollView.addSubview(arrPics[i])
}
self.scrollView.contentSize = CGSizeMake(self.scrollView.frame.width, self.scrollView.frame.height*4)
}
Don't use a scroll view but either a table view or a collection view.
The delegates of both classes want a cell count from you. Then give the delegates an insane number of cells, a number so high that it is totally unlikely that any human being will ever scroll to reach the end. Something like 9999999 cells. This is no problem for such classes because in the background implementation they do not create really this high number of cells but only maximal the number of cells which could be visible at the same time on the screen. The cells in fact are reused. So when cells are falling out at the bottom those cells are going to be reused at the top and vice versa. As a last point is: set the starting point in the middle of such a high number, something like 5555555. I think that is the easiest solution if you are not going to implement a full image recycling algorithm like they did.
#IBOutlet weak var scrollView: UIScrollView!
var scrollViewHeight: CGFloat!
let numPics: Int = 4
override func viewDidLoad()
{
super.viewDidLoad()
scrollView.delegate = self
self.scrollView.frame = CGRectMake(0, 0, self.view.frame.width, self.view.frame.height)
let scrollViewWidth: CGFloat = self.scrollView.frame.width
scrollViewHeight = self.scrollView.frame.height
let imgOne = UIImageView()
let imgTwo = UIImageView()
let imgThree = UIImageView()
let imgFour = UIImageView()
let imgFive = UIImageView()
var arrPics = [imgOne, imgTwo, imgThree, imgFour,imgFive]
var arrSlide = ["slide1.jpeg", "slide1.jpeg", "slide1.jpeg", "slide1.jpeg","slide1.jpeg"]
for i in 0...numPics {
arrPics[i] = UIImageView(frame: CGRectMake(0,scrollViewHeight * CGFloat(i),scrollViewWidth, scrollViewHeight))
arrPics[i].image = UIImage(named: arrSlide[i])
self.scrollView.addSubview(arrPics[i])
}
self.scrollView.contentSize = CGSizeMake(self.scrollView.frame.width, self.scrollView.frame.height * CGFloat(numPics+1))
}
func scrollViewDidScroll(scrollView: UIScrollView)
{
scrollViewHeight = self.scrollView.frame.height
self.scrollView.contentSize = CGSizeMake(self.scrollView.frame.width, self.scrollView.frame.height * scrollViewHeight )
}
Using Timer you can use infinite scrolling like below
func showview() {
if(videosimageslider.isEmpty) {
// print("Empty Array")
} else {
// print("Not Empty ")
// print(videosimageslider.count)
for var index=0; index<videosimageslider.count; index++ {
if let url = NSURL(string: videosimageslider[index]) {
if let data = NSData(contentsOfURL: url){
if let imageUrl = UIImage(data: data) {
let myimageview:UIImageView = UIImageView()
// myimageview.image = imageUrl
let block: SDWebImageCompletionBlock! = {(image: UIImage!, error: NSError!, cacheType: SDImageCacheType, imageUrl: NSURL!) -> Void in
//println(self)
}
// let url = NSURL(string: "http://yikaobang-test.u.qiniudn.com/FnZTPYbldNXZi7cQ5EJHmKkRDTkj")
myimageview.sd_setImageWithURL(url, completed: block)
myimageview.frame.size.width = imagewidth
myimageview.frame.size.height = imageheight
myimageview.contentMode = UIViewContentMode.ScaleToFill
myimageview.frame.origin.x = xscrollpos
myimageview.frame.origin.y = 5
scrollview!.addSubview(myimageview)
xscrollpos += imagewidth
scrollviewcontentSize += imagewidth
scrollview.contentSize = CGSize(width: scrollviewcontentSize, height: imageheight)
}
}
}
}
scrollingTimer = NSTimer.scheduledTimerWithTimeInterval(0.5, target: self, selector: "newStartScrolling", userInfo: nil, repeats: true)
scrollingTimer.fire()
}
}
// call the timer function //
func newStartScrolling() {
var currentOffset = scrollview.contentOffset
currentOffset = CGPointMake(currentOffset.x+3, currentOffset.y )
if(currentOffset.x < scrollview.contentSize.width - 500) {
scrollview.setContentOffset(currentOffset, animated: false)
currentOffset = CGPointMake(0, currentOffset.y )
//scrollview.contentSize = CGSize(width: 0, height: 0);
} else {
scrollingTimer.invalidate()
showview()
}
}
This is what will solve your problem, just adjust the controller to go in vertical slide view and load the resources at your will.
Link

Swift UIScrollView snap to subview width without pagingEnabled

How can i implement UIScrollView when swiping snap to its subviews width. I need it to behave like pagingEnabled but i cant enable paging because i need my entire view can be swipe to scroll. if i do pagingEnable its impossible because scrollview bounds will be change to subviews width.
is there any possible way to do this.
please check the image for more details
import UIKit
class ViewController: UIViewController{
var navigationScroller: UIScrollView!
var contentScroller: UIScrollView!
var navContainer: UIView!
var contentContainer: UIView!
var selfWidth:CGFloat?
var navigationLabels = ["EVENTS", "MEMBERS", "SECTORS", "ORGANIZATIONS", "SEARCH", "EVENTS", "MEMBERS"]
private var buttonsTextFontAndSize: UIFont = UIFont(name: "HelveticaNeue-Light", size: 14)!
override func viewDidLoad() {
super.viewDidLoad()
selfWidth = self.view.frame.width
let frameWidth = self.view.frame.width
let frameHeight = self.view.frame.height
//let navscrollPosition = CGFloat( (frameWidth/2) - (75.0/2) )
navContainer = UIView(frame: CGRectMake(0.0, 75.0, frameWidth, 40.0))
navContainer.backgroundColor = UIColor(red:0, green:0.302, blue:0.522, alpha:1)
navigationScroller = UIScrollView(frame: CGRectMake(0.0, 0.0, frameWidth, 40.0))
navigationScroller.backgroundColor = UIColor.clearColor()
navigationScroller.pagingEnabled = false
navigationScroller.showsHorizontalScrollIndicator = false
navigationScroller.showsVerticalScrollIndicator = false
navigationScroller.clipsToBounds = false
navigationScroller.contentInset = UIEdgeInsetsZero
//navigationScroller.userInteractionEnabled = false
//navigationScroller.
addNavigationLabels(navigationScroller)
self.view.addSubview(navContainer)
navContainer.addSubview(navigationScroller)
navigationScroller.contentSize = CGSize(width: 150.0 * CGFloat(navigationLabels.count),height: 40.0)
navigationScroller.contentOffset = CGPoint(x: 170.0, y:0.0)
contentContainer = UIView(frame: CGRectMake(0.0, 115.0, frameWidth, frameHeight-115.0))
contentContainer.backgroundColor = UIColor.clearColor()
contentScroller = UIScrollView(frame: CGRectMake(0.0, 0.0, frameWidth, frameHeight-115.0))
contentScroller.backgroundColor = UIColor.clearColor()
contentScroller.pagingEnabled = true
contentScroller.showsHorizontalScrollIndicator = false
contentScroller.showsVerticalScrollIndicator = false
contentScroller.clipsToBounds = true
contentScroller.contentInset = UIEdgeInsetsZero
//contentScroller.addSubview(navContainer)
addContents(contentScroller)
self.view.addSubview(contentContainer)
contentContainer.addSubview(contentScroller)
contentScroller.contentSize = CGSize(width: frameWidth * CGFloat(navigationLabels.count),
height: frameHeight-115.0)
//contentScroller.delegate = self
navigationScroller.delegate = self
}
//MARK: -View Appeared function
override func viewDidAppear(animated: Bool) {
super.viewDidAppear(true)
}
override func didReceiveMemoryWarning() {
super.didReceiveMemoryWarning()
}
// MARK: -Adding navigation labels fron navigation labels array
private func addNavigationLabels(navScrollView:UIScrollView){
var buttonsXPosition: CGFloat = 0
var buttonNumber = 0
for navLabel in navigationLabels {
var navButton: UIButton!
let red = CGFloat(buttonNumber) - 0.9
let frameWidth = self.view.frame.width
navButton = UIButton(frame: CGRectMake(buttonsXPosition, 0, frameWidth/3, 40.0))
navButton.titleLabel!.font = buttonsTextFontAndSize
navButton.contentHorizontalAlignment = .Center
navButton.backgroundColor = UIColor(red:red , green:0.114, blue:0.286, alpha:1)
navButton.setTitle(navLabel, forState: UIControlState.Normal)
navButton.addTarget(self, action: "buttonAction:", forControlEvents: UIControlEvents.TouchUpInside)
navScrollView.addSubview(navButton)
buttonsXPosition = frameWidth/3 + buttonsXPosition
buttonNumber++
}
}
func buttonAction(sender:UIButton!){
print("pressed")
}
// MARK: -Adding navigation labels fron navigation labels array
private func addContents(contentScroller:UIScrollView){
var buttonsXPosition: CGFloat = 0
var buttonNumber = 0
let frameWidth = self.view.frame.width
let frameHeight = self.view.frame.height
for navLabel in navigationLabels {
var navButton: UIButton!
navButton = UIButton(frame: CGRectMake(buttonsXPosition, 40.0, frameWidth, frameHeight-155))
navButton.titleLabel!.font = buttonsTextFontAndSize
navButton.contentHorizontalAlignment = .Center
navButton.backgroundColor = UIColor.darkGrayColor()
navButton.setTitle(navLabel, forState: UIControlState.Normal)
contentScroller.addSubview(navButton)
buttonsXPosition = frameWidth + buttonsXPosition
buttonNumber++
}
}
}
app view
You can implement UIScrollViewDelegate's method scrollViewWillEndDragging:withVelocity:targetContentOffset: and modify the offset at it will finish decelerating to match the width that you wish.
Something like this:
class ScrollSample: NSObject, UIScrollViewDelegate {
func scrollViewWillEndDragging(scrollView: UIScrollView, withVelocity velocity: CGPoint, targetContentOffset: UnsafeMutablePointer<CGPoint>) {
let targetOffset = targetContentOffset.memory.x
// Round the offset to be a multiple of scrollview width
let roundedOffset = round(targetOffset / scrollView.frame.width) * scrollView.frame.width
targetContentOffset.memory = CGPoint(x: roundedOffset, y: 0)
}
}

How to create a Scroll View with a page control using swift? [closed]

Closed. This question does not meet Stack Overflow guidelines. It is not currently accepting answers.
We don’t allow questions seeking recommendations for books, tools, software libraries, and more. You can edit the question so it can be answered with facts and citations.
Closed 4 years ago.
Improve this question
I am trying to create a Page View controller with numbers of view. I want a simple code sample that will use UIPageViewController.
import UIKit
class DummyVC: UIViewController, UIScrollViewDelegate {
let scrollView = UIScrollView(frame: CGRect(x:0, y:0, width:320,height: 300))
var colors:[UIColor] = [UIColor.red, UIColor.blue, UIColor.green, UIColor.yellow]
var frame: CGRect = CGRect(x:0, y:0, width:0, height:0)
var pageControl : UIPageControl = UIPageControl(frame: CGRect(x:50,y: 300, width:200, height:50))
override func viewDidLoad() {
super.viewDidLoad()
configurePageControl()
scrollView.delegate = self
scrollView.isPagingEnabled = true
self.view.addSubview(scrollView)
for index in 0..<4 {
frame.origin.x = self.scrollView.frame.size.width * CGFloat(index)
frame.size = self.scrollView.frame.size
let subView = UIView(frame: frame)
subView.backgroundColor = colors[index]
self.scrollView .addSubview(subView)
}
self.scrollView.contentSize = CGSize(width:self.scrollView.frame.size.width * 4,height: self.scrollView.frame.size.height)
pageControl.addTarget(self, action: #selector(self.changePage(sender:)), for: UIControlEvents.valueChanged)
}
func configurePageControl() {
// The total number of pages that are available is based on how many available colors we have.
self.pageControl.numberOfPages = colors.count
self.pageControl.currentPage = 0
self.pageControl.tintColor = UIColor.red
self.pageControl.pageIndicatorTintColor = UIColor.black
self.pageControl.currentPageIndicatorTintColor = UIColor.green
self.view.addSubview(pageControl)
}
// MARK : TO CHANGE WHILE CLICKING ON PAGE CONTROL
func changePage(sender: AnyObject) -> () {
let x = CGFloat(pageControl.currentPage) * scrollView.frame.size.width
scrollView.setContentOffset(CGPoint(x:x, y:0), animated: true)
}
func scrollViewDidEndDecelerating(_ scrollView: UIScrollView) {
let pageNumber = round(scrollView.contentOffset.x / scrollView.frame.size.width)
pageControl.currentPage = Int(pageNumber)
}
}
For lazy coder this is the Swift 3 implementation based on That lazy iOS Guy 웃's answer
import UIKit
class ViewController: UIViewController,UIScrollViewDelegate {
let scrollView = UIScrollView(frame: CGRect(x: 0, y: 0, width: 320, height: 300))
var colors:[UIColor] = [UIColor.red, UIColor.blue, UIColor.green, UIColor.yellow]
var frame: CGRect = CGRect(x: 0, y: 0, width: 0, height: 0)
var pageControl : UIPageControl = UIPageControl(frame:CGRect(x: 50, y: 300, width: 200, height: 50))
override func viewDidLoad() {
super.viewDidLoad()
// Do any additional setup after loading the view, typically from a nib.
configurePageControl()
scrollView.delegate = self
self.view.addSubview(scrollView)
for index in 0..<4 {
frame.origin.x = self.scrollView.frame.size.width * CGFloat(index)
frame.size = self.scrollView.frame.size
let subView = UIView(frame: frame)
subView.backgroundColor = colors[index]
self.scrollView .addSubview(subView)
}
self.scrollView.isPagingEnabled = true
self.scrollView.contentSize = CGSize(width: self.scrollView.frame.size.width * 4, height: self.scrollView.frame.size.height)
pageControl.addTarget(self, action: #selector(self.changePage(sender:)), for: UIControlEvents.valueChanged)
}
func configurePageControl() {
// The total number of pages that are available is based on how many available colors we have.
self.pageControl.numberOfPages = colors.count
self.pageControl.currentPage = 0
self.pageControl.tintColor = UIColor.red
self.pageControl.pageIndicatorTintColor = UIColor.black
self.pageControl.currentPageIndicatorTintColor = UIColor.green
self.view.addSubview(pageControl)
}
// MARK : TO CHANGE WHILE CLICKING ON PAGE CONTROL
func changePage(sender: AnyObject) -> () {
let x = CGFloat(pageControl.currentPage) * scrollView.frame.size.width
scrollView.setContentOffset(CGPoint(x: x,y :0), animated: true)
}
func scrollViewDidEndDecelerating(_ scrollView: UIScrollView) {
let pageNumber = round(scrollView.contentOffset.x / scrollView.frame.size.width)
pageControl.currentPage = Int(pageNumber)
}
override func didReceiveMemoryWarning() {
super.didReceiveMemoryWarning()
// Dispose of any resources that can be recreated.
}
}
Swift 3 - Horizontal image scroll
import UIKit
class pageenabled: UIViewController,UIScrollViewDelegate
{
let imagelist = ["img1.jpg", "photo1.jpg", "photo3.jpg", "photo4.jpg", "photo5.jpg"]
var scrollView = UIScrollView()
var pageControl : UIPageControl = UIPageControl(frame:CGRect(x: 50, y: 300, width: 200, height: 50))
var yPosition:CGFloat = 0
var scrollViewContentSize:CGFloat=0;
override func viewDidLoad() {
super.viewDidLoad()
scrollView = UIScrollView(frame: CGRect(x: 0, y: 0, width: self.view.frame.width, height: 300))
configurePageControl()
scrollView.delegate = self
self.view.addSubview(scrollView)
for i in stride(from: 0, to: imagelist.count, by: 1) {
var frame = CGRect.zero
frame.origin.x = self.scrollView.frame.size.width * CGFloat(i)
frame.origin.y = 0
frame.size = self.scrollView.frame.size
self.scrollView.isPagingEnabled = true
let myImage:UIImage = UIImage(named: imagelist[i])!
let myImageView:UIImageView = UIImageView()
myImageView.image = myImage
myImageView.contentMode = UIViewContentMode.scaleAspectFit
myImageView.frame = frame
scrollView.addSubview(myImageView)
}
self.scrollView.contentSize = CGSize(width: self.scrollView.frame.size.width * CGFloat(imagelist.count), height: self.scrollView.frame.size.height)
pageControl.addTarget(self, action: Selector(("changePage:")), for: UIControlEvents.valueChanged)
// Do any additional setup after loading the view.
}
func configurePageControl() {
// The total number of pages that are available is based on how many available colors we have.
self.pageControl.numberOfPages = imagelist.count
self.pageControl.currentPage = 0
self.pageControl.tintColor = UIColor.red
self.pageControl.pageIndicatorTintColor = UIColor.black
self.pageControl.currentPageIndicatorTintColor = UIColor.green
self.view.addSubview(pageControl)
}
// MARK : TO CHANGE WHILE CLICKING ON PAGE CONTROL
func changePage(sender: AnyObject) -> () {
let x = CGFloat(pageControl.currentPage) * scrollView.frame.size.width
scrollView.setContentOffset(CGPoint(x: x,y :0), animated: true)
}
func scrollViewDidEndDecelerating(_ scrollView: UIScrollView) {
let pageNumber = round(scrollView.contentOffset.x / scrollView.frame.size.width)
pageControl.currentPage = Int(pageNumber)
}
override func didReceiveMemoryWarning() {
super.didReceiveMemoryWarning()
// Dispose of any resources that can be recreated.
}
}
In Swift 3.0
craeate iboutlets through story board for scrollview and pagecontroller.
#IBOutlet weak var imgScrollView: UIScrollView!
#IBOutlet weak var imgPageController: UIPageControl!
var sliderImagesArray = NSMutableArray()
in viewdidload method write this code
sliderImagesArray = ["https://images.unsplash.com/photo-1432679963831-2dab49187847?w=1080","https://images.unsplash.com/photo-1447746249824-4be4e1b76d66?w=1080", "https://images.unsplash.com/photo-1463595373836-6e0b0a8ee322?w=1080"]
imgScrollView.delegate = self
for i in 0..<sliderImagesArray.count {
var imageView : UIImageView
let xOrigin = self.imgScrollView.frame.size.width * CGFloat(i)
imageView = UIImageView(frame: CGRect(x: xOrigin, y: 0, width: self.imgScrollView.frame.size.width, height: self.imgScrollView.frame.size.height))
imageView.isUserInteractionEnabled = true
let urlStr = sliderImagesArray.object(at: i)
print(imgScrollView,imageView, urlStr)
imageView.sd_setImage(with: URL(string: urlStr as! String), placeholderImage: UIImage(named: "placeholder.png"))
imageView .contentMode = UIViewContentMode.scaleToFill
self.imgScrollView.addSubview(imageView)
}
self.imgScrollView.isPagingEnabled = true
self.imgScrollView.bounces = false
self.imgScrollView.showsVerticalScrollIndicator = false
self.imgScrollView.showsHorizontalScrollIndicator = false
self.imgScrollView.contentSize = CGSize(width:
self.imgScrollView.frame.size.width * CGFloat(sliderImagesArray.count), height: self.imgScrollView.frame.size.height)
imgPageController.addTarget(self, action: #selector(self.changePage(sender:)), for: UIControlEvents.valueChanged)
self.imgPageController.numberOfPages = sliderImagesArray.count
self.imgPageController.currentPage = 0
self.imgPageController.tintColor = UIColor.red
self.imgPageController.pageIndicatorTintColor = UIColor.black
self.imgPageController.currentPageIndicatorTintColor = UIColor.blue
after that implement scrollview delegate methods
func changePage(sender: AnyObject) -> () {
let x = CGFloat(imgPageController.currentPage) * imgScrollView.frame.size.width
imgScrollView.setContentOffset(CGPoint(x: x,y :0), animated: true)
}
func scrollViewDidEndDecelerating(_ scrollView: UIScrollView) {
let pageNumber = round(imgScrollView.contentOffset.x / imgScrollView.frame.size.width)
imgPageController.currentPage = Int(pageNumber)
}
#IBOutlet weak var scrollView: UIScrollView!
#IBOutlet weak var imageViewBottomConstraint: NSLayoutConstraint!
#IBOutlet weak var imageViewLeadingConstraint: NSLayoutConstraint!
#IBOutlet weak var imageViewTopConstraint: NSLayoutConstraint!
#IBOutlet weak var imageViewTrailingConstraint: NSLayoutConstraint!
extension ZoomedPhotoViewController: UIScrollViewDelegate {
func viewForZoomingInScrollView(scrollView: UIScrollView) -> UIView? {
return imageView
}
}
private func updateMinZoomScaleForSize(size: CGSize) {
let widthScale = size.width / imageView.bounds.width
let heightScale = size.height / imageView.bounds.height
let minScale = min(widthScale, heightScale)
scrollView.minimumZoomScale = minScale
scrollView.zoomScale = minScale
}
override func viewDidLayoutSubviews() {
super.viewDidLayoutSubviews()
updateMinZoomScaleForSize(view.bounds.size)
}
private func updateConstraintsForSize(size: CGSize) {
let yOffset = max(0, (size.height - imageView.frame.height) / 2)
imageViewTopConstraint.constant = yOffset
imageViewBottomConstraint.constant = yOffset
let xOffset = max(0, (size.width - imageView.frame.width) / 2)
imageViewLeadingConstraint.constant = xOffset
imageViewTrailingConstraint.constant = xOffset
view.layoutIfNeeded()
}
func scrollViewDidZoom(scrollView: UIScrollView) {
updateConstraintsForSize(view.bounds.size)
}
import UIKit
public class PhotoCommentViewController: UIViewController {
#IBOutlet weak var imageView: UIImageView!
#IBOutlet weak var scrollView: UIScrollView!
#IBOutlet weak var nameTextField: UITextField!
public var photoName: String!
override public func viewDidLoad() {
super.viewDidLoad()
if let photoName = photoName {
self.imageView.image = UIImage(named: photoName)
}
}
}
override func prepareForSegue(segue: UIStoryboardSegue, sender: AnyObject?) {
if let cell = sender as? UICollectionViewCell,
indexPath = collectionView?.indexPathForCell(cell),
photoCommentViewController = segue.destinationViewController as? PhotoCommentViewController {
photoCommentViewController.photoName = "photo\(indexPath.row + 1)"
}
}
NSNotificationCenter.defaultCenter().addObserver(
self,
selector: #selector(PhotoCommentViewController.keyboardWillShow(_:)),
name: UIKeyboardWillShowNotification,
object: nil
)
NSNotificationCenter.defaultCenter().addObserver(
self,
selector: #selector(PhotoCommentViewController.keyboardWillHide(_:)),
name: UIKeyboardWillHideNotification,
object: nil
)
deinit {
NSNotificationCenter.defaultCenter().removeObserver(self)
}
func adjustInsetForKeyboardShow(show: Bool, notification: NSNotification) {
guard let value = notification.userInfo?[UIKeyboardFrameBeginUserInfoKey] as? NSValue else { return }
let keyboardFrame = value.CGRectValue()
let adjustmentHeight = (CGRectGetHeight(keyboardFrame) + 20) * (show ? 1 : -1)
scrollView.contentInset.bottom += adjustmentHeight
scrollView.scrollIndicatorInsets.bottom += adjustmentHeight
}
func keyboardWillShow(notification: NSNotification) {
adjustInsetForKeyboardShow(true, notification: notification)
}
func keyboardWillHide(notification: NSNotification) {
adjustInsetForKeyboardShow(false, notification: notification)
}
#IBAction func hideKeyboard(sender: AnyObject) {
nameTextField.endEditing(true)
}
public var photoIndex: Int!
import UIKit
class ManagePageViewController: UIPageViewController {
var photos = ["photo1", "photo2", "photo3", "photo4", "photo5"]
var currentIndex: Int!
override func viewDidLoad() {
super.viewDidLoad()
dataSource = self
// 1
if let viewController = viewPhotoCommentController(currentIndex ?? 0) {
let viewControllers = [viewController]
// 2
setViewControllers(
viewControllers,
direction: .Forward,
animated: false,
completion: nil
)
}
}
func viewPhotoCommentController(index: Int) -> PhotoCommentViewController? {
if let storyboard = storyboard,
page = storyboard.instantiateViewControllerWithIdentifier("PhotoCommentViewController")
as? PhotoCommentViewController {
page.photoName = photos[index]
page.photoIndex = index
return page
}
return nil
}
}

Horizontal scrolling with parallax background for ios

I'm facing a challenge of creating an introduction view, something like the "Cleanio" app (https://itunes.apple.com/fr/app/cleanio-pressing-la-demande/id885856031?mt=8).
Here is how it looks like:
So, the background and the overlay are moving independently and not in the same speed.
Does anyone have a start point how to realize that?
Yep.
What you need is two UIScrollViews. These should both be subviews of the main view (not contained in each other.
The bottom one has your image in it and the top one has the content.
Call them imageScrollView and contentScrollView.
Become the delegate of contentScrollView.
The contents will look something like this...
contents: [---page 1---][---page 2---][---page 3---][---page 4---]
image: [------------the image------------]
screen: [---screen---]
Key is that image is smaller than all the pages and bigger than the screen.
The frames of the scrollviews are the same width as the screen. This diagram is just to show the content widths not the frame widths.
So, the screen stays where it is and the two scroll views move over it.
Now the parallax part...
- (CGFloat)maxOffsetForScrollView:(UIScrollView *)scrollView
{
CGFloat contentWidth = scrollView.contentSize.width;
CGFloat frameWidth = CGRectGetWidth(scrollView.frame);
return contentWidth - frameWidth;
}
- (void)scrollViewDidScroll:(UIScrollView *)scrollView
{
// this is the delegate method for the content scroll view.
// I'm only doing horizontal stuff here, you can do vertical too if you want
CGFloat maximumContentOffset = [self maximumOffsetForScrollView:self.contentScrollView];
CGFloat currentOffset = self.contentScrollView.contentOffset.x;
CGFloat percentageOffset = currentOffset/maximumContentOffset;
CGFloat maximumImageOffset = [self maximumContentOffsetForScrollView:self.imageScrollView];
CGFloat actualImageOffset = maximumImageOffset * percentageOffset;
[self.imageScrollView setContentOffset:CGPointMake(actualImageOffset, 0)];
}
This takes the percentage offset from the content view and offsets the image view by the same percentage offset.
The result is a parallax effect. You can make it faster or slower by changing the relative sizes of the image and the content. More pages (or smaller image) = slower parallax.
I had been struggling with this parallax effect for a little while. I wouldn't have done it without #Fogmeister instructions, though I still had to figure out a couple of things by myself.
Anyway, here is a Swift 2.0 version, (hopefully a bit more complete):
import UIKit
class ViewController: UIViewController, UIScrollViewDelegate {
var backgroundScrollView: UIScrollView!
var contentScrollView: UIScrollView!
var imageView: UIImageView!
var contentView: UIView!
var maxContentOffset: CGFloat!
var maxBackgroundOffset: CGFloat!
var cvbw: CGFloat!
var page: Int = 1
override func viewDidLoad() {
super.viewDidLoad()
self.createBackground()
self.createContent()
}
func createBackground() {
self.imageView = UIImageView(image: UIImage(named: "ParalaxMaterial.jpg")) //ParalaxMaterial.jpg is of size: 2500 x 2668px
self.imageView.frame = CGRectMake(0, 0, ((self.view.bounds.height/2668) * 2500), self.view.bounds.height)
self.backgroundScrollView = UIScrollView(frame: view.bounds)
self.backgroundScrollView.backgroundColor = UIColor.redColor()
self.backgroundScrollView.contentSize = imageView.bounds.size
self.backgroundScrollView.addSubview(self.imageView)
self.view.addSubview(self.backgroundScrollView)
self.maxBackgroundOffset = self.maxOffsetForScrollView(self.backgroundScrollView)
}
func createContent() {
self.contentView = UIView(frame: CGRectMake(0, 0, (self.view.bounds.width * 3), self.view.bounds.height))
self.contentScrollView = UIScrollView(frame: view.bounds)
self.contentScrollView.backgroundColor = UIColor.clearColor()
self.contentScrollView.contentSize = self.contentView.bounds.size
self.contentScrollView.delegate = self
let firstButton = UIButton()
firstButton.frame = CGRectMake(((self.contentView.bounds.width / 6) - 150), 300, 300, 100)
firstButton.setTitle("START", forState: UIControlState.Normal)
firstButton.titleLabel?.font = UIFont(name: "Arial", size: 18)
firstButton.addTarget(self, action: "firstAction:", forControlEvents: UIControlEvents.TouchUpInside)
self.contentView.addSubview(firstButton)
let firstLabel = UILabel()
firstLabel.frame = CGRectMake(((self.contentView.bounds.width / 6) - 100), 0, 200, 200)
firstLabel.text = "#BrusselsLockDown"
firstLabel.textAlignment = NSTextAlignment.Center
self.contentView.addSubview(firstLabel)
let secondLabel = UILabel()
secondLabel.frame = CGRectMake(((self.contentView.bounds.width / 2) - 100), 0, 200, 200)
secondLabel.text = "#LolCats"
secondLabel.textAlignment = NSTextAlignment.Center
self.contentView.addSubview(secondLabel)
let thirdLabel = UILabel()
thirdLabel.frame = CGRectMake((((self.contentView.bounds.width / 6) * 5) - 100), 0, 200, 200)
thirdLabel.text = "#Final"
thirdLabel.textAlignment = NSTextAlignment.Center
self.contentView.addSubview(thirdLabel)
self.contentScrollView.addSubview(self.contentView)
self.view.addSubview(self.contentScrollView)
self.maxContentOffset = self.maxOffsetForScrollView(self.contentScrollView)
self.cvbw = self.contentView.bounds.width
}
func scrollViewWillBeginDecelerating(scrollView: UIScrollView) {
if self.page == 1 {
if scrollView.contentOffset.x > 0 {
scrollView.setContentOffset(CGPointMake((self.cvbw / 3), 0), animated: true)
}
} else if self.page == 2 {
if scrollView.contentOffset.x < (self.cvbw * 4/12) {
scrollView.setContentOffset(CGPointMake(0, 0), animated: true)
} else if scrollView.contentOffset.x > (self.cvbw * 4/12) {
scrollView.setContentOffset(CGPointMake(((self.cvbw / 3) * 2), 0), animated: true)
}
} else if self.page == 3 {
if scrollView.contentOffset.x < (self.cvbw * 8/12) {
scrollView.setContentOffset(CGPointMake((self.cvbw / 3), 0), animated: true)
}
} else {
print("self.page messed up")
}
}
func scrollViewDidScroll(scrollView: UIScrollView) {
if scrollView == self.contentScrollView {
let percentageOffset: CGFloat = self.contentScrollView.contentOffset.x / self.maxContentOffset
let currentBackgroundOffsetPoint: CGPoint = CGPointMake(((self.maxBackgroundOffset * percentageOffset) + 50), 0) self.backgroundScrollView.setContentOffset(currentBackgroundOffsetPoint, animated: false)
}
if self.contentScrollView.contentOffset.x == 0 {
print("page 1")
self.page = 1
} else if self.contentScrollView.contentOffset.x == 320 {
print("page 2")
self.page = 2
} else if self.contentScrollView.contentOffset.x == 640 {
print("page 3")
self.page = 3
}
}
func maxOffsetForScrollView(scrollView: UIScrollView) -> CGFloat {
let contentWidth: CGFloat = scrollView.contentSize.width - 100
let frameWidth: CGFloat = CGRectGetWidth(scrollView.frame)
return contentWidth - frameWidth
}
func firstAction (sender: UIButton) {
print("firstAction")
self.contentScrollView.setContentOffset(CGPointMake((self.cvbw / 3), 0), animated: true)
}
}

Resources