Image Slider using UIScrollView and Auto Layout - swift

I am trying to implement a image slider using scrollView and pageControl, with the images being appended to the scrollView programmatically using the .addSubView method. The code is as follows:
#IBOutlet weak var sliderScrollView: UIScrollView!
#IBOutlet weak var sliderPageControl: UIPageControl!
var images: [String] = ["0", "1", "2"]
func updateSlider() {
sliderPageControl.numberOfPages = images.count
for index in 0..<images.count {
frame.origin.x = sliderScrollView.frame.size.width * CGFloat(index)
print(sliderScrollView.frame.size.width)
frame.size = sliderScrollView.frame.size
let image = UIImageView(frame: frame)
image.contentMode = .scaleAspectFill
image.image = UIImage(named: cafeObject.images[index])
sliderScrollView.addSubview(image)
}
sliderScrollView.contentSize = CGSize(width: sliderScrollView.frame.size.width * CGFloat(cafeObject.images.count), height: sliderScrollView.frame.size.height)
sliderScrollView.delegate = self
sliderPageControl.currentPage = 0
}
override func scrollViewDidScroll(_ scrollView: UIScrollView) {
let pageNumber = scrollView.contentOffset.x / scrollView.frame.size.width
switch scrollView {
case sliderScrollView:
sliderPageControl.currentPage = Int(pageNumber)
default:
break
}
}
As I designed the storyboard on iPhone 8 layout, the above code works nicely for iPhone 8. However, once I run the code in iPhone 8 Plus, the photo does not adapt the new size of the scrollView. I have added constraints to the scrollView such that the top, leading, trailing and bottom are equal to the super view's top, leading, trailing and bottom. When debugging, I realized that the UIImageView's frame is still using the old width as on iPhone 8.
Any workaround for this either programatically or using interface builder? Thanks!

Okay I managed to get this fixed by placing the updateSlider() function under viewDidLayoutSubviews() instead!

Related

UIScrollview constraints for different devices

Currently, I have the following codes to make UIScrollView work for iPhone that I have set it up in the main storyboard.
var images: [String] = ["image1", "image2"]
var frame = CGRect(x:0,y:0,width:0,height:0)
override func viewDidLoad() {
super.viewDidLoad()
// Do any additional setup after loading the view.
pageControl.numberOfPages = images.count
for index in 0..<images.count {
frame.origin.x = scrollView.frame.size.width * CGFloat(index)
frame.size = scrollView.frame.size
let imgView = UIImageView(frame: frame)
imgView.image = UIImage(named: images[index])
self.scrollView.addSubview(imgView)
}
scrollView.contentSize = CGSize(width: (scrollView.frame.size.width * CGFloat(images.count)), height: scrollView.frame.size.height)
scrollView.delegate = self
}
I am trying to make a horizontal scrollview in xcode but when I run the project on iPad, the scrollview changes to the screen size but not the images. I looked up solutions online by adding views to the scroll view but it does not work. I am trying to make the images resize accordingly to the scrollview size.
Quick fact: Images are stored in Assets.xcassets.
Any help would be very much appreciated. Thanks!

Is there a way to auto layout an image in a scroll view combined with page control?

This is my first entry. I am new in app designing and from Germany, but I still hope you can understand my problem. I used Xcode 11 and Swift 5.
I am using a page control and scroll view to switch between images in one screen. It looks good on the iPhone 11 but on the iPhone 8 the width and height of the images is too great, which is why part of the first image can still be seen when the page control is on the second segment. The same happens for the with the second image and the third segment.This hopefully shows the problem.
Is there a way to fit the images to the screen size?
This is my code:
```
import UIKit
class ViewController: UIViewController, UIScrollViewDelegate {
#IBOutlet weak var scrollView: UIScrollView!
#IBOutlet weak var pageControl: UIPageControl!
var Pages: [String] = ["Page1","Page2","Page3"]
var frame = CGRect.zero
override func viewDidLoad() {
super.viewDidLoad()
// Do any additional setup after loading the view.
pageControl.numberOfPages = Pages.count //
setupScreens()
scrollView.showsHorizontalScrollIndicator = false
scrollView.showsVerticalScrollIndicator = false
scrollView.isPagingEnabled = true
scrollView.delegate = self
}
func setupScreens() {
for index in 0..<Pages.count {
// 1.
frame.origin.x = scrollView.frame.size.width * CGFloat(index)
frame.size = scrollView.frame.size
// 2.
let imageView = UIImageView(frame: frame)
imageView.image = UIImage(named: Pages[index])
self.scrollView.addSubview(imageView) }
// 3.
scrollView.contentSize = CGSize(width: (scrollView.frame.size.width * CGFloat(Pages.count)), height: scrollView.frame.size.height)
scrollView.delegate = self
}
func scrollViewDidEndDecelerating(_ scrollView: UIScrollView) {
let pageNumber = scrollView.contentOffset.x / scrollView.frame.size.width
pageControl.currentPage = Int(pageNumber)
}
}
```
Your code is totally working fine except calling setupScreens() method in viewDidLoad().
call that method in viewDidLayoutSubviews so that it will get proper frame of scrollView.
override func viewDidLayoutSubviews() {
setupScreens()
}
Download demo from here

Change height and width of view according to scrollview scroll horizontally using auto layout

Container View hierarchy:-
Container View
Scrollview
view left
view center
view right
FloatingBottomView
I need to change height and width constrain of FloatingBottomView according to scrollview scroll horizontally.
Initial Outlet:-
#IBOutlet weak var constantFloatingBottomViewWidth: NSLayoutConstraint! // 300
#IBOutlet weak var constantFloatingBottomViewHeight: NSLayoutConstraint! // 70
override func viewWillAppear(_ animated: Bool) {
self.scrollView.contentOffset.x = self.view.bounds.width
// view center in scrollview
}
func scrollViewDidScroll(_ scrollView: UIScrollView) {
if scrollView.contentOffset.x < self.view.bounds.width {
// when scrollview move view center to view left, constantFloatingBottomViewWidth and height goes to down at some point
}
else if scrollView.contentOffset.x > self.view.bounds.width {
// when scrollview move view left to view center, constantFloatingBottomViewWidth & height goes up to same point range while it down and back to original constantFloatingBottomViewWidth and height
}
}
i have tried using this way to get some scale in scrollViewDidScroll method.
scroll quick left to right or vice-versa did not get exactly out-put
let scale = abs(scrollView.contentOffset.x / self.view.bounds.width)
print("scale:=\(scale)")
I think you need to give button animation like this
For this you have nothing to do just add animation to button like follow
call setupButtonanimation in viewDidLoad
func setupButtonAnimation()
{
let animation = CABasicAnimation.init(keyPath: "transform.scale")
animation.fromValue = 1.0
animation.toValue = 0.45
animation.duration = 1.0
//Set the speed of the layer to 0 so it doesn't animate until we tell it to
self.btn1.layer.speed = 0.0;
self.btn1.layer.add(animation, forKey: "transform");
}
func scrollViewDidScroll(_ scrollView: UIScrollView)
{
let screenSize = self.view.bounds.size
if let btn = self.btn1
{
var factor:CGFloat = 1.0
factor = scrollView.contentOffset.x / screenSize.width
if factor > 1
{
factor = 2 - factor
}
print(factor)
//This will change the size
let timeOffset = CFTimeInterval(1-factor)
btn.layer.timeOffset = timeOffset
}
}

Swift - Visual constraints not working

I have a scrollView which I instantiate programaticaly. What I want to do is to add constraints so it will look good in both horizontal and vertical orientation. The problem that constraints not working
How it looks vertically - good
How it looks horizontally - not good
Code is following
class FAPhoto: UIViewController, UIScrollViewDelegate {
var imageURLsArray = [String]()
var imageViews:[UIImageView] = []
var arrayOfPhotos = [Photo]()
var scrollView = UIScrollView()
override func viewDidLoad() {
super.viewDidLoad()
scrollView = UIScrollView(frame: self.view.frame)
view.addSubview(scrollView)
scrollView.contentSize = CGSizeMake(view.frame.size.width * CGFloat(arrayOfPhotos.count), scrollView.frame.size.height)
scrollView.pagingEnabled = true
for (var i = 0; i < arrayOfPhotos.count; i++) {
var imageView = UIImageView()
imageView.frame = CGRectMake(CGFloat(i) * view.frame.size.width, scrollView.frame.origin.y, scrollView.frame.size.width, scrollView.frame.size.height)
imageView.contentMode = .ScaleAspectFit
let image = imageView.hnk_setImageFromURL(NSURL(string: arrayOfPhotos[i].url!)!)
scrollView.addSubview(imageView)
}
}
override func viewWillAppear(animated: Bool) {
}
override func viewWillLayoutSubviews() {
let bindings = Dictionary(dictionaryLiteral: ("scrollView", self.scrollView))
let horizontalConstraints =
NSLayoutConstraint.constraintsWithVisualFormat(
"H:|-0-[scrollView]-0-|",
options: [],
metrics: nil,
views: bindings)
self.view.addConstraints(horizontalConstraints)
let verticalConstraints =
NSLayoutConstraint.constraintsWithVisualFormat(
"V:|-0-[scrollView]-0-|",
options: [],
metrics: nil,
views: bindings)
self.view.addConstraints(verticalConstraints)
}
}
The problem is that you set contentSize of scrollView and imageView's frames in viewDidLoad. This is OK for portrait mode, but when view rotates to landscape, it's frame also changes, so you have to update these values accordingly. I think you have 3 opportunities here.
Track rotation events and update contentSize of scrollView and imageView's frames, when view rotates.
Use Autolayout for scrollView. You will not have to calculate contentSize or set imageView's frames, just set constraints once in viewDidLoad. Here you can find some examples https://stackoverflow.com/a/20232911/4757335.
Use UICollectionView instead of UIScrollView. It handles rotation much easier.

adding NSImageView to NSScrollView

I have an image with a dimension of about 200x2000 pixels. I want to display the image centered in a 200x200 rectangle but I want to be able to move it up and down. Best I can figure I need to add an NSImageView to an NSScrollView but I can't figure out how or even if this is the best way. This is my first day of OS X development...
After some googling I found this from which I was able to come up with this
class MasterViewController: NSViewController {
var Photo: NSImageView!
#IBOutlet var scroll: NSScrollView!
override func viewDidLoad() {
super.viewDidLoad()
var imageRect: NSRect
self.Photo = NSImageView.init()
self.Photo.image = NSImage.init(named:"horizon")
imageRect = NSMakeRect(0.0, 0.0, self.Photo.image!.size.width, self.Photo.image!.size.height)
print("image size", imageRect)
self.Photo = NSImageView(frame: imageRect)
self.Photo.setBoundsSize(NSSize(width: imageRect.width, height: imageRect.height))
self.Photo.imageScaling = NSImageScaling.ScaleNone
self.scroll.setFrameSize(NSSize(width: imageRect.width,height: imageRect.width))
self.scroll.hasVerticalScroller = true
self.scroll.hasHorizontalScroller = true
self.Photo.setFrameSize(CGSize(width: imageRect.width,height: imageRect.width))
self.scroll.documentView = self.Photo
//print(self.scroll.documentView?.frame)
//self.scroll.setC contentSize = NSSize(width: 200, height: 2000)
//self.Photo.image = NSImage.init(named:"bezel")
//self.scroll.addSubview(self.Photo)
}
but I can't get the image to show up inside the scrollview
#lusher00: in your example, you initialize twice self.Photo, first with an init() and then with (frame: imageRect), this probably explains why image don't show up.
You could set the imageView as the documentView of the NSScrollView, as below:
#IBOutlet var scrollView: NSScrollView!
var imageRect: NSRect
// Initialize below the imageView image with appropriate content (to adapt)
imageView.image = NSImage.init(named:"horizon")
imageRect = NSMakeRect(0.0, 0.0, imageView.image!.size.width, imageView.image!.size.height)
imageView.setFrameSize(CGSize(width: imageRect.width, height: imageRect.height))
imageView.imageScaling = NSImageScaling.ScaleNone
scrollView.documentView = imageView
scrollView.hasVerticalScroller = true
scrollView.hasHorizontalScroller = true
Just add the image view as a subview of the scrollview.
scrollView.addSubview(imageView)
You can set the position of the imageview, which will position it inside the scrollview.
The scrollview needs to know how large its content size is to enable scrolling of that area. So dont forget to update the contentSize property of the scrollview.
E.g. adding the imageView of 200x200 to the scrollView with a frame of 200x200. Setting the contentSize to 400x400 and calling imageView.center = scrollView.center, will center the image and allow some scrolling around the image, within the 200x200 visible frame of the scrollview.
You can also get the current offset of the scrollView by checking contentOffset.
If you need to track as the user scrolls, you can use scrollViewDidScroll. Check the docs for the scrollview for some other options.