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.
Related
I am trying to learn the basics of IOS development and Ive been experimenting with different views.
I tried to make a scroll view that display an array of images which scrolls properly but none of the images appear?
import UIKit
class ViewController: UIViewController {
var imagesArray = [UIImage]()
let scrollView: UIScrollView = {
let scroll = UIScrollView()
scroll.isPagingEnabled = true
scroll.showsVerticalScrollIndicator = false
scroll.showsHorizontalScrollIndicator = false
scroll.frame = CGRect(x: 0, y: 0, width: UIScreen.main.bounds.width, height: UIScreen.main.bounds.height)
return scroll
}()
override func viewDidLoad() {
super.viewDidLoad()
setScrollView()
}
func setScrollView(){
self.view.addSubview(scrollView)
imagesArray = [UIImage(named:"gamerrr"),UIImage(named:"family"),UIImage(named:"gamerrr"),UIImage(named:"family"),UIImage(named:"family")] as! [UIImage]
setUpImages(imagesArray)
}
func setUpImages(_ images:[UIImage]){
for i in 0..<images.count {
// container of each image
let imageView = UIImageView()
// shifting to next image
let xPos = UIScreen.main.bounds.width * CGFloat(i)
// width and height of the screen
imageView.frame = CGRect(x: xPos, y: 0, width: scrollView.frame.width, height: scrollView.frame.height)
imageView.contentMode = .scaleAspectFit
// shifting to next image
scrollView.contentSize.width = scrollView.frame.width * CGFloat(i+1)
scrollView.addSubview(imageView)
}
}
}
You may need to set the image
let imageView = UIImageView(image:images[i])
i have a scrollview wich load a image to zoom in and zoom out , the problem is that i want the image to be loaded full like this
http://www.capital.cl/wp-content/uploads/2015/04/avengers.jpg
so the user can see the complete image first
but it looks like this
this is the code
import UIKit
class Paso2: UIViewController, UIScrollViewDelegate {
#IBOutlet weak var scrollView: UIScrollView!
#IBOutlet weak var noCheckBox2: CheckBox!
#IBOutlet weak var siCheckBox2: CheckBox!
var imageView = UIImageView()
override func viewDidLoad() {
super.viewDidLoad()
scrollView.delegate = self
// imageView.contentMode = UIViewContentMode.ScaleAspectFill
// imageView.clipsToBounds = true
imageView.image = UIImage(named: "avengers.jpg")
let imagee = UIImage(named: "avengers.jpg")
let size = imagee?.size
imageView.frame = CGRectMake(0, 0, size!.width, size!.height)
imageView.contentMode = .Top
scrollView.addSubview(imageView)
scrollView.contentSize = size!
let scrollViewFrame = scrollView.frame
let scaleWidth = scrollViewFrame.size.width / scrollView.contentSize.width
let scaleHeight = scrollViewFrame.size.height / scrollView.contentSize.height
let minScale = min(scaleHeight, scaleWidth)
scrollView.minimumZoomScale = 1
scrollView.maximumZoomScale = 4
scrollView.zoomScale = minScale
centerScrollViewContents()
}
func centerScrollViewContents(){
let boundsSize = scrollView.bounds.size
var contentsFrame = imageView.frame
if contentsFrame.size.width < boundsSize.width {
contentsFrame.origin.x = (boundsSize.width - contentsFrame.size.width) / 2
}
else {
contentsFrame.origin.x = 0
}
if contentsFrame.size.height < boundsSize.height {
contentsFrame.origin.y = (boundsSize.height - contentsFrame.size.height) / 2
}
else {
contentsFrame.origin.y = 0
}
imageView.frame = contentsFrame
// scrollView.frame = contentsFrame
}
func scrollViewDidZoom(scrollView: UIScrollView) {
centerScrollViewContents()
}
func viewForZoomingInScrollView(scrollView: UIScrollView) -> UIView? {
return imageView
}
Help plz
Just change this.
imageView.contentMode = .ScaleAspectFit
without zoom
with zoom
You should use .contentMode property of the UIImageView for the proper representation of the image.
This is small comparison of the content modes.
You want to display full image without scrolling or you want to display scrollable image?
Try this code for fast start:
class ViewController: UIViewController {
#IBOutlet weak var scrollView: UIScrollView!
var imageView = UIImageView()
private var imageViewOriginalSize = CGRect ()
override func viewDidLoad() {
super.viewDidLoad()
imageView.image = UIImage(named: "avengers.jpg")
imageView.contentMode = .ScaleAspectFit
let size = UIScreen.mainScreen().bounds
imageViewOriginalSize = size
imageView.frame = CGRectMake(0, 0, size.width, size.height)
scrollView.addSubview(imageView)
let pinch = UIPinchGestureRecognizer(target: self, action: #selector(ViewController.pinchGestureRecognizerAction))
self.scrollView.addGestureRecognizer(pinch)
}
func pinchGestureRecognizerAction(gestureRecoginzer: UIPinchGestureRecognizer) {
imageView.frame.size.height = imageViewOriginalSize.height*gestureRecoginzer.scale
imageView.frame.size.width = imageViewOriginalSize.width*gestureRecoginzer.scale
imageView.frame.origin.x = imageViewOriginalSize.origin.x*gestureRecoginzer.scale
imageView.frame.origin.y = imageViewOriginalSize.origin.y*gestureRecoginzer.scale
scrollView.contentSize = imageView.frame.size
}}
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.
I am trying to implement a scroll view with page control to display images in iOS using Swift, to get an output like this:
The scroll view here is a part of another view controller.
I googled but got no help to get the required output.
Can anyone please help me?
The answer is a bit late. So, may be helpful for someone else:
Swift 3x:
First of all, give the delegation like this:
class YOUR_VIEW_CONTROLLER: UIViewController, UIScrollViewDelegate
Now connect the outlets of UIScrollView and UIPageControl like this:
#IBOutlet weak var scrollView: UIScrollView!
#IBOutlet weak var pageControl: UIPageControl!
NOTE:I'm using colours array. You can use image array instead.
var colors:[UIColor] = [UIColor.red, UIColor.blue, UIColor.green, UIColor.yellow]
var frame: CGRect = CGRect(x:0, y:0, width:0, height:0)
Now just copy and paste the below code in your class:
override func viewDidLoad() {
super.viewDidLoad()
// Do any additional setup after loading the view, typically from a nib.
configurePageControl()
self.view.bringSubview(toFront: pageControl)
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.layer.zPosition = 1
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)
}
The comparison is between this:
let viewController = storyboard!.instantiateViewControllerWithIdentifier("ViewController") as! AViewController
versus this:
let viewController = AViewController()
Unfortunately, this question is not able to answer my question.
I've created this view controller:
final class ImageVC: UIViewController {
var imageView: UIImageView!
var scrollView: UIScrollView!
var originLabel: UILabel!
var image: UIImage?
override func viewDidLoad() {
super.viewDidLoad()
guard let image = image else { fatalError() }
imageView = UIImageView(image: image)
scrollView = UIScrollView(frame: view.bounds)
scrollView.autoresizingMask = [.FlexibleWidth, .FlexibleHeight]
scrollView.backgroundColor = UIColor.blackColor()
scrollView.contentSize = imageView.bounds.size
scrollView.addSubview(imageView)
view.addSubview(scrollView)
originLabel = UILabel(frame: CGRect(x: 20, y: 30, width: 0, height: 0))
originLabel.backgroundColor = UIColor.blackColor()
originLabel.textColor = UIColor.whiteColor()
view.addSubview(originLabel)
scrollView.delegate = self
setZoomParametersForSize(scrollView.bounds.size)
}
override func viewWillLayoutSubviews() {
print("layout")
setZoomParametersForSize(scrollView.bounds.size)
}
func setZoomParametersForSize(scrollViewSize: CGSize) {
let imageSize = imageView.bounds.size
let widthScale = scrollViewSize.width / imageSize.width
let heightScale = scrollViewSize.height / imageSize.height
let minScale = min(widthScale, heightScale)
scrollView.minimumZoomScale = minScale
scrollView.maximumZoomScale = 3.0
scrollView.zoomScale = minScale
}
}
extension ImageVC: UIScrollViewDelegate {
func viewForZoomingInScrollView(scrollView: UIScrollView) -> UIView? {
return imageView
}
func scrollViewDidScroll(scrollView: UIScrollView) {
originLabel.text = "\(scrollView.contentOffset)"
originLabel.sizeToFit()
}
}
This is meant to take an image, and when presented, will allow the user to zoom/pan through the image.
When I instantiate this VC using the first method (by instantiating from storyboard with identifier), it behaves fine.
However, when instantiating it the second way; let viewController = ImageVC(), viewWillLayoutSubviews will be triggered whenever scrollView detects movement, disallowing the ability to zoom in and out.
Advice appreciated.