scrollview autolayout issue xcode 8 with constraints - ios

I am adding my intro screens in a scrollview.So I have to scroll horizontally only.I have set constraints for scrollview(top, bottom.leading, trailing).I have added subviews like the following
for i in 0..<self.arrIntro.count{
let view = IntroScreenView.instanceFromNib()
let x = CGFloat(i) * self.scrollIntro.frame.size.width
view.frame = CGRect(x: x, y: 0, width: self.scrollIntro.frame.size.width, height: self.scrollIntro.frame.size.height)
print(view,self.scrollIntro)
view.imgIntro.image = UIImage(named: "image-1")//UIImage(contentsOfFile: self.arrIntro[i]["Link"] as! String)
print(self.arrIntro[i]["Link"] as! String)
self.scrollIntro.addSubview(view)
}
self.scrollIntro.contentSize = CGSize(width: (CGFloat(self.arrIntro.count) * self.scrollIntro.frame.size.width ) , height: self.scrollIntro.frame.size.height)
but my scrollview is vertically scrolling little bit.How should I avoid this.Any autolayout issue?

You're not adding any constraints to your views. Add height and width constraints to each item, constraints between the views and constraints from the views to the scroll view. Note that the constraints between the Su views and the scroll view will set the content size for you.

Scroll view scrolls vertically, when contentSize.height is greater than the scrollView height.
Just make sure, your contentSize.height is not greater than the scrollView.frame.size.height.
One reason, that I could guess is that, you might be setting contentSize a point after which the frames of the scroll view changes. You should move setting you contentSize in viewDidLayoutSubviews()
Sample : This code makes vertical scroll
class ViewController: UIViewController, UIScrollViewDelegate {
#IBOutlet var scrollView: UIScrollView!
override func viewDidLoad() {
super.viewDidLoad()
scrollView.contentSize = CGSize(width: self.scrollView.bounds.width*5, height: self.scrollView.frame.height)
}
}
And this does not
class ViewController: UIViewController, UIScrollViewDelegate {
#IBOutlet var scrollView: UIScrollView!
override func viewDidLayoutSubviews() {
scrollView.contentSize = CGSize(width: self.scrollView.bounds.width*5, height: self.scrollView.frame.height)
}
}

Related

Horizontal UIScrollView is not centering the current page

I would like to have a horizontal scroll layout which displays images. It works fine if setup 0, 0, 0 and 0 the constraints of the UIScrollView. The problem is exactly when I change the constraints to make margins surrounded the UIScrollView. This is what happens:
First image in the UIScrollView
Second image in the UIScrollView
Third image in the UIScrollView
As you can see, each time you scroll, more off-center the current page is.
I have tried to subtract trailing and leading constrains constants to the width of the scrollLayout, play with frames and bouds but without success.
If I run this example in a smaller display like iphone 5S, the problem is more pointed.
class ViewController: UIViewController, UIScrollViewDelegate {
#IBOutlet weak var pageController: UIPageControl!
#IBOutlet weak var scrollView: UIScrollView!
let imagesArray = ["b_1", "b_2", "b_3", "b_4", "b_5"]
override func viewDidLoad() {
super.viewDidLoad()
self.scrollView.isPagingEnabled = true
self.pageController.numberOfPages = imagesArray.count
self.pageController.pageIndicatorTintColor = UIColor.blue
self.pageController.currentPageIndicatorTintColor = UIColor.gray
for i in 0...imagesArray.count - 1{
let imageView = UIImageView()
imageView.contentMode = .scaleToFill
imageView.image = UIImage(named: self.imagesArray[i])
let xPos = CGFloat(i)*self.view.bounds.size.width
imageView.frame = CGRect(x: xPos, y: 0, width: view.frame.size.width, height: self.scrollView.frame.size.height )
self.scrollView.contentSize.width = view.frame.size.width*CGFloat(i+1)
self.scrollView.addSubview(imageView)
}
}
func scrollViewDidScroll(_ scrollView: UIScrollView) {
let page = scrollView.contentOffset.x/scrollView.frame.width
self.pageController.currentPage = Int(page)
}
}
So, I would like to know how to always obtain the current image centered.
Thank you
EDITED with Rajesh results and view debug:
I would recommend using a UICollectionView in place of a UIScrollView - otherwise you will be building a lot of the basics from scratch. You can use a collection view that centers the images, make sure paging is enabled and you should get the interface you're looking for. Make sure to adopt / conform to the UICollectionViewDelegate & UICollectionViewDelegateFlowLayout protocols with your view controller & set those delegates on your collection view. Hope that helps! Best of luck.

Paging with ScrollView using directly storyboard instead of creating .xib files

Sorry in advance, this is a long question but I wanted to explain as good as I can.
I need to implement a walkthrough(first time launch guide) for the project, which will only be shown to user for the first time they launch the app.
I've implemented it by creating a .xib file, where I was just creating a view for each item I need to implement for the walkthrough by creating objects referring to .xib model.
But now I'm required to implement it without using .xib files, where I need to do it via storyboard. This time I've inserted a scrollView, and then I put another view inside it with the objects I'm going to need such as (labels,imageViews,buttons etc.) But it doesn't work, even though I can create all the objects by copying the view right under the scrollView. When I try to expand the width of the scrollView with all the views created so I can do paging, it doesn't create each view next to each other but only shows me the last object(view) in the simulator as they add up vertically, and I can't do no paging.
Now I provide some sample code to show how I try to implement this:
import UIKit
class DenemeViewController: UIViewController, UIScrollViewDelegate {
#IBOutlet weak var scrollView: UIScrollView!
#IBOutlet weak var pageControl: UIPageControl!
#IBOutlet weak var repeatingView: UIView!
var viewArray = [UIView]()
override func viewDidLoad() {
super.viewDidLoad()
let temporaryView = repeatingView
temporaryView?.backgroundColor = .black
viewArray.append(temporaryView!)
let temporaryViewTwo = repeatingView
temporaryViewTwo?.backgroundColor = .blue
viewArray.append(temporaryViewTwo!)
pageControl.numberOfPages = viewArray.count
pageControl.currentPage = 0
view.bringSubview(toFront: pageControl)
setupScrollView(items: viewArray)
}
func setupScrollView(items: [UIView]) {
scrollView.frame = CGRect(x: 0, y: 0, width: view.frame.width, height: view.frame.height)
scrollView.contentSize = CGSize(width: view.frame.width * CGFloat(items.count), height: view.frame.height)
scrollView.isPagingEnabled = true
for i in 0..<items.count {
items[i].frame = CGRect(x: view.frame.width * CGFloat(i), y: 0, width: view.frame.width, height: view.frame.height)
scrollView.addSubview(items[i])
}
}
func scrollViewDidScroll(_ scrollView: UIScrollView) {
let pageIndex = round(scrollView.contentOffset.x/view.frame.width)
pageControl.currentPage = Int(pageIndex)
}
}
As you can see I first create two different views in viewDidLoad by referring to "repeatingView" which is the outlet of the view inside scrollView on the storyboard. Then I return them in an array and try to implement scrollView's subviews with views.
I was expecting to see the scrollView starting with the view with black background and as I do the paging through right then the view with blue background should appear.
When I run this what I see is only the blue view, and I'm unable to do any paging or scrolling.

Update constraints swift layoutIfNeeded doesn't work

I need to update constraints (height of my CollectionView) when request is done and I have images from server, so height of View also will change.
Result screen
what I need screen
My code:
DispatchQueue.main.async {
self.cvActivity.alpha = 0
self.collectionView.reloadData()
self.collectionView.heightAnchor.constraint(equalToConstant: self.cellWidth * 2).isActive = true
self.collectionView.setNeedsUpdateConstraints()
self.collectionView.setNeedsLayout()
self.view.layoutIfNeeded()
}
Well, basic idea by #J. Doe is correct, here some code explanation (for simplicity i used UIView, not UICollectionView):
import UIKit
class ViewController: UIViewController {
#IBOutlet var heightConstraint: NSLayoutConstraint! // link the height constraint to your collectionView
private var height: CGFloat = 100 // you should keep constraint height for different view states somewhere
override func updateViewConstraints() {
heightConstraint.constant = height // set the correct height
super.updateViewConstraints()
}
// update height by button press with animation
#IBAction func increaseHight(_ sender: UIButton) {
height *= 2
UIView.animate(withDuration: 0.3) {
self.view.setNeedsUpdateConstraints()
self.view.layoutIfNeeded() // if you call `layoutIfNeeded` on your collectionView, animation doesn't work
}
}
}
Result:
Define a height for your collectionView, create an outlet from that constraint and increase the constant of that constraint and call layoutifneeded in an animation block
You need to make object of your Height constraint from storyboard
#IBOutlet weak var YourHeightConstraintName: NSLayoutConstraint!
YourConstraintName.constant = valueYouWantToGive
---------OR--------
collectionViewOutlet.view.frame = CGRect(x:
collectionViewOutlet.frame.origin.x , y:
collectionViewOutlet.frame.origin.y, width:
collectionViewOutlet.frame.width, height:
yourheightValue)

how to get current size of a subview when device size changes in swift?

I have to view: view_1 and view_2 . view_1 height is proportional to the main view controller height and I am adding view_2 programmatically as a subview of view_1 with a proportional height.
Problem
when the device size changes say from iPhone 6 to iPhone 5, the view_1 adjust correctly but its height I am passing to a function to draw its subview view_2 is still what was set in interface builder and so it is out of bounds in iPhone 4 moving from iPhone 6
Thus I want to know how can I get the correct size of a view that what resize automatically to fit the current device?
The size of the view isn't established until Auto Layout runs. Your first opportunity to get the correct size is in viewDidLayoutSubviews:
override func viewDidLayoutSubviews() {
super.viewDidLayoutSubviews()
// access view size here
}
Here's a complete example that adds a second view as a subview of the first view. The red view was added in the Storyboard; it is centered horizontally and vertically and it's height/width is 50% of its superview.
The yellow view is added programmatically. It's frame is computed from the frame of the red view to be 50% of the width of the red view.
import UIKit
class ViewController: UIViewController {
#IBOutlet weak var view1: UIView!
var view2: UIView?
override func viewDidLayoutSubviews() {
super.viewDidLayoutSubviews()
if view2 == nil {
view2 = UIView()
view2?.backgroundColor = .yellowColor()
view1.addSubview(view2!)
}
let width = view1.frame.size.width
let height = view1.frame.size.height
let frame = CGRect(x: width * 0.25, y: height * 0.25, width: width * 0.5, height: height * 0.5)
view2?.frame = frame
}
}
Not that viewDidLayoutSubviews gets called multiple times, so you must take care not to add view2 every time it is called. That is why the code checks to see if view2 has been added.
Try this,you can find the screen size of device.
let screenSize: CGRect = UIScreen.mainScreen().bounds
let screenWidth = screenSize.width
let screenHeight = screenSize.height
Try to do this in Viewdidload
First you need to set view one frame
view_1.frame = CGRectMake(0 , 0, self.view.frame.width, self.view.frame.height)
then set frame of view_2
view_2.frame = CGRectMake(0 , 0, view_1.frame.width, view_1.frame.height)

UIScrollView containing CGRect line graph not scrolling (Swift)

I'm trying to make a line graph drawn using a CGRect scrollable by the user. I've set its container view to be scrollable (i want a horizontal scroll so the line can extend past the screen), but it doesn't appear to be having any effect. Here's the code in my actual view controller:
#IBOutlet weak var containerView: UIScrollView!
#IBOutlet weak var graphView: GraphView!
override func viewDidLoad() {
super.viewDidLoad()
logWeightButton.enabled = false
logWeightField.delegate = self
logWeightField.keyboardType = .NumberPad
self.view.addSubview(containerView)
containerView.addSubview(graphView)
containerView.contentSize = graphView.rectDisplay.size
pageLoad()
}
and here's the code declaring the CGRect(within a UIView class)
override func drawRect(rect: CGRect) {
if dataPoints.count == 0 {
return
} else {
self.drawLine(dataPoints, rect: rect, xCoordinates: nil, color: UIColor.blackColor())
if xCoordinates.count != 0 {
self.drawLine(actualPoints, rect: rect, xCoordinates: xCoordinates, color: UIColor.redColor())
}
rectDisplay = rect
}
}
Figured out that I needed to turn off auto-layout in the storyboard file inspector - if it's not disabled, it can overwrite scroll views.
I also made sure to enable scroll with
containerView.scrollEnabled = true
and set the containerView frame to
self.view.frame
I don't have enough reputation to post an image, so here it is:
http://i.stack.imgur.com/ZOBJp.png
The graph now scrolls, but my whole display is a mess (I believe because of setting the container frame to the size of the view), so the cycle continues.
FINAL UPDATE:
Learned that the frame of the scroll view has to be smaller than its content for it to scroll (which is why setting it to the view frame worked - the width of the view was less than the width of the line graph), so I set my frame to
containerView.frame = CGRect(x: 43.0, y: 147.0, width: 300.0, height: 117.0)
And everything works now. Hope this is helpful for someone else!

Resources