Disabling Horizontal Scrolling from UIScrollView Swift - ios

Scroll View
I have a UIScrollView, with constraints left: 0, top: 0, right: 0, bottom: 0
Inside Scroll View
At the top of this UIScrollView is a UIImageView with constraints left: 0, top: 0, right: 0, height: 200
Underneath this I have a UITextView with constraints left: 0, top: 0, right: 0, bottom: 0
This means the UITextView will resize with respect to its content, and I set the scrollingEnabled to false for the UITextView.
So, when I run, it almost works perfectly.
The one problem is the UIImageView takes up about 10% more than the actual screen width. Hence, horizontal scrolling is enabled.
I have tried adding the lines
imageView.frame = CGRect(0, 0, screenSize.width, 200)
scrlView.contentSize.width = screenSize.width
but this makes no difference. I can still scroll horizontally and the Image View still takes up around 10% more than the actual screen width.
Note, I have not set imageView screen width in storyboard, only programatically.
Any ideas?

Like this,
Swift 4.0
func scrollViewDidScroll(scrollView: UIScrollView) {
if scrollView.contentOffset.x>0 {
scrollView.contentOffset.x = 0
}
}
And, you can set this property:
scrollImg.isDirectionalLockEnabled = true

Swift 4
Horizontal Scroll Lock
func scrollViewDidScroll(_ scrollView: UIScrollView) {
if scrollView.contentOffset.x != 0 {
scrollView.contentOffset.x = 0
}
}
You can change the x to y for vertical scrolling.
Make sure to add UIScrollViewDelegate like this:
class MyViewController: UIViewController, UIScrollViewDelegate {
#IBOutlet var scrollView: UIScrollView!
...
}
And set the delegate for the ScrollView
scrollView.delegate = self

I changed this so that it just returns 0. No need to check at all if you want scroll off.
func scrollViewDidScroll(scrollView: UIScrollView) {
scrollView.contentOffset.x = 0
}
No need for the directional lock.

func scrollViewDidScroll(_ scrollView: UIScrollView) {
scrollView.contentOffset.x = 0
}
This stops the scrollview from scrolling towards the leading edge too.

If you are using storyboard and autolayout, then you should consider how ScrollView work in Storyboard with autolayout.
Consider the following.
Add a single view on your scrollView with constrains
left, right, top, bottom, height, width,
Make the outlet of the width and height
Add your subViews to the view you added in the scrollView
update the width to the screenSize eg: 320 for iPhone5 or 4.
self.viewWidth = SCREEN_WIDTH;
[self.view updateConstraints];

You can use
func scrollViewDidScroll(_ scrollView: UIScrollView) {
scrollView.contentOffset.x = 0
}
Do not use scrollView.contentOffset.x < 0 or > 0 like others have mentioned because it will only stop scroll to one side horizontally and not both.

Related

How to make UIView automatically scroll with screen when NavBar scrolls past it?

How can I make a certain element on my screen scroll with the screen (e.i. have a fixed position relative to the screen) when my navbar scrolls past it?
In other words, I have an element that isn't at the top of my screen and you need to scroll down to its position before it starts scrolling with the screen. Then, when you scroll back up to the top of the screen, the item goes back to its original position and stays there.
I am currently using a UIScrollView to scroll across my screen. My original plan was to get certain dimensions and basically do something like this when a isScrolling() method is called (pseudocode):
if scrolledPositionOnScreen > positionOfUIView {
scrollUIViewWithRestOfScreen()
} else {
putUIViewInOriginalPosition()
}
However, this doesn't work well when I use different size screens even though I am getting these variables dynamically with respect to screen size.
Is there a delegate or something that will do what I am trying to do/is there an easier, more consistent way?
Thanks!
Yes, there is the UIScrollViewDelegate delegate from which you can use the scrollViewDidScroll method:
class ViewController : UIViewController, UIScrollViewDelegate {
let scrollView = UIScrollView()
let frame = CGRect(origin: .init(x: 0, y: 100), size: .init(width: 200, height: 200))
lazy var v = UIView(frame: frame)
override func viewDidLoad() {
super.viewDidLoad()
self.scrollView.delegate = self
self.view.addSubview(scrollView)
self.scrollView.contentSize = CGSize(width: self.view.bounds.width, height: UIScreen.main.bounds.height + 1000)
self.scrollView.translatesAutoresizingMaskIntoConstraints = false
self.scrollView.addSubview(v)
self.v.backgroundColor = .red
NSLayoutConstraint.activate([
self.scrollView.topAnchor.constraint(equalTo: self.view.topAnchor),
self.scrollView.bottomAnchor.constraint(equalTo: self.view.bottomAnchor),
self.scrollView.leadingAnchor.constraint(equalTo: self.view.leadingAnchor),
self.scrollView.trailingAnchor.constraint(equalTo: self.view.trailingAnchor),
])
}
func scrollViewDidScroll(_ scrollView: UIScrollView) {
if scrollView.contentOffset.y > frame.origin.y {
v.center.y = scrollView.contentOffset.y + (v.bounds.height/2)
}
}
}

Define correctly height for UIScrollView

I'm creating a application using Swift3, and i have difficult to define correctly height for UIScrollView, i'm using autolayout and create this structure:
UIScrollView
UIView // The container view
UIImageView // Constraint Top Edges = 20 in relation to UIView
UITextView // Constraint Top Edges = 40 in relation to UIImageView
UITextView // Constraint Top Edges = 20 in relation to UITextView
UIButton // Constraint Top Edges 30 in relation to UITextView
Currently, i'm using this logic to calculate UIScrollView height
override func viewDidLayoutSubviews() {
var scrollHeight : CGFloat = 0.0
for view in self.containerView.subviews {
view.layoutIfNeeded()
scrollHeight += view.frame.size.height
}
// Adding height for scrollview, according to the sum of all child views
self.scrollView.contentSize.height = scrollHeight
}
But, i can only get the views height, and them not consider the Constraints "margins", i would like know any way to calculate correct height for UIScrollView, adjusted according their content.
Close! Let's add the top margin for each view:
override func viewDidLayoutSubviews() {
var scrollHeight : CGFloat = 0.0
for view in self.containerView.subviews {
view.layoutIfNeeded()
scrollHeight += view.frame.size.height
//Add the margins as well to the scrollHeight
scrollHeight += view.layoutMargins.top
}
// Adding height for scrollview, according to the sum of all child views
self.scrollView.contentSize = CGRect(x: self.scrollView.contentSize.width, y: scrollHeight)
}
self.scrollview.contentsize.height = containerview.height;

A bug of UIScrollView contentOffset?

I set the property isPagingEnabled of a scrollView to true, like this:
let scrollView = UIScrollView(frame: view.bounds)
scrollView.contentSize = CGSize(width: view.bounds.width * 2, height: 0)
scrollView.delegate = self
scrollView.isPagingEnabled = true
view.addSubview(scrollView)
and delegate method:
func scrollViewDidScroll(_ scrollView: UIScrollView) {
print(scrollView.contentOffset.x)
}
When scrolling the view to the boundary, the console print, as shown in:
and
The values in the red box should not be printed out, right?
But, if setting isPagingEnabled to false, the console print is normal. Is this a bug of UIScrollView?
Your Content offset is showing wrong because your are using content size in viewdidload use content size in this method than print your content off set
override func viewDidLayoutSubviews()
{
scrollView.contentSize = CGSize(width: view.bounds.width * 2, height: 0)
}
As far as i Know, Its working correctly, when you are setting contentSize to your scrollview, that will respond to their delegate at first time itself.
func scrollViewDidScroll(_ scrollView: UIScrollView)
Whenever user try to scroll or drag, the above delegate will call recursively, Here your contentSize of width is double of Your view bounds width(so there is two page, the contentOffset.x will start with 0 and current position of scroll, if it is in second page, that will give your view width * n ), and you set isPagingEnabled to true.
Check this https://developer.apple.com/reference/uikit/uiscrollview/1619404-contentoffset
The default value is CGPoint​Zero.
Actually contentOffset will tell you that current scroll position.
Whenever UIScrollView make scrolling, this method scrollViewDidScroll(_ scrollView: UIScrollView) invokes. Any of the direction if you scroll you will get these types of output.
However if you want like a pagination approach then instead of this method you can use:
func scrollViewDidEndDecelerating(_ scrollView: UIScrollView) {
let pageNumber = round(scrollView.contentOffset.x / scrollView.frame.size.width)
print("pageNumber = \(pageNumber)")
}
By this method you will get the exact page no of UIScrollView.
Please use frame instead of bounds .
The bounds of an UIView is the rectangle, expressed as a location (x,y) and size (width,height) relative to its own coordinate system (0,0).The frame of an UIView is the rectangle, expressed as a location (x,y) and size (width,height) relative to the superview it is contained within.
let scrollView = UIScrollView(frame: view.frame.size)
scrollView.contentSize = CGSize(width: view.frame.size.width * 2,
height: 0)
scrollView.delegate = self
scrollView.isPagingEnabled = true
view.addSubview(scrollView)

UIScrollView didn't scroll

I've some problem with ScrollView.
I'm trying to create a scrollview and add to it dynamically some buttons.
So i create a scrollView in my main storyboard with some constraints. (0 to left, 0 to right, 0 to botton and 1/10 height).
Now, i want to add some button.
#IBOutlet var scrollView: UIScrollView!
override func viewDidLoad() {
super.viewDidLoad()
for index in 0..<12 {
let frame1 = CGRect(x: 0 + (index * 60), y: 0, width: 45, height: 45 )
let button = UIButton(frame: frame1)
button.setTitle("toto", forState: .Normal)
button.backgroundColor = UIColor.green()
scrollView.addSubview(button)
}
}
So now the problem is : my buttons are present but i can't scroll. The scroll is enabled in the storyBoard. I tried to enabled it in the code but nothing changed..
set the contentSize of your scrollView
self. scrollView.contentSize = CGSizeMake(required_width, required_height)
for example
self. scrollView.contentSize = CGSizeMake(500, 74) // custtomize ur self
You have to set the contentSize of the scrollView
The height to set is probably the origin.y + the size.height of the last button.
use this code to set scrollview height
scrollview.contentInset = UIEdgeInsetsMake(0, 0, 50, 0)
//50 is the height of scroll view you can change it to the height you want
scrollview.bounces = false
or you can also change content inset from here
by changing the values of content inset (height or width)

UIScrollView Content Size with Autolayout

I am using UIScrollView with Auto-layout to change contentSenter code hereize value as following :
UIView
ScrollView
UIView (contentView)
In run time I am adding UITextView & UIImageView to conentView with constraint(Top,Bottom,Left,Right)
but the contentView size is not changing and UIScrollView contentSize also.
So what could be the problem ?
In run time I am adding UITextView & UIImageView to conentView with constraint(Top,Bottom,Left,Right)
Maybe you should add constraint (Top, Left, Height, Width),or (Top, Left, Right, Height)
If you persist in (Top,Bottom,Left,Right), ScrollView will keep the old content size, and make your UITextView & UIImageView (Height = 0, Width = 0).
Here's a neat way of updating scroll view's content size. It's Swift so you'll need a bridging header if you're working in Objective C.
extension UIScrollView {
func updateContentViewSize() {
var newHeight: CGFloat = 0
for view in subviews {
let ref = view.frame.origin.y + view.frame.height
if ref > newHeight {
newHeight = ref
}
}
let oldSize = contentSize
let newSize = CGSize(width: oldSize.width, height: newHeight + 20)
contentSize = newSize
}
}
Just call it on your scroll view's object whenever you add a child view to your scroll view.

Resources