Scrolling ScrollView even when ContentView has the same size - swift

I have a ScrollView defined with autolayout : it has a contentView, in which there's some elements. The scrollView has constraints with other views to set it's size, and 4 constraints with the contentView (up, down, left, right, each with constant = 0). The contentView has a defined size, the same size as the scrollView.
I want my scrollView to scroll and bounce (I overrided the scrollViewDidScroll method), but the problem is the scrollView is not scrolling if the contentView has the same size as it (which is logic, since there's no content to scroll, but I want it to bounce).
How can I make my scrollView scrolling ?

Try setting to your scrollView:
scrollView.alwaysBounceHorizontal = true
scrollView.alwaysBounceVertical = true
or in Interface Builder, make sure you've checked options:

Related

How to get a custom scrollingStackView's height

I have a custom view, it's a scrolling view with a stack view in it. And I added 3 container views inside this stack view to stack and scroll vertically. Inside each container view I add either a UIImage or a UILabel view.
I don't want my scrollview to scroll if all the views are already visible on screen.
For this I need to know the height of my scrollingStackView, so I can compare it with the current screen size.
Here is how I set them up in viewDidLoad:
setupScrollingSV()
setupContainer1()
setupContainer2()
setupContainer3()
setupImageViewInContainer1()
setupImageViewInContainer2()
setupLabelViewInContainer3()
My custom scrolling stack view doesn't have a size, I lay it out programmatically giving left, right, top anchors.
scrollingSV.leftAnchor.constraint(equalTo: stackView.leftAnchor).isActive = true
scrollingSV.rightAnchor.constraint(equalTo: stackView.rightAnchor).isActive = true
scrollingSV.topAnchor.constraint(equalTo: stackView.topAnchor).isActive = true
And there is another stack view that is in safe area of my view, which has this scrolling stack view and another container view ContainerView4.
I layout ContainerView4 like this:
ContainerView4.leftAnchor.constraint(equalTo: stackView.leftAnchor).isActive = true
ContainerView4.rightAnchor.constraint(equalTo: stackView.rightAnchor).isActive = true
ContainerView4.topAnchor.constraint(equalTo: scrollingSV.bottomAnchor).isActive = true
ContainerView4.bottomAnchor.constraint(equalTo: stackView.bottomAnchor).isActive = true
ContainerView4.heightAnchor.constraint(equalToConstant: 100.0).isActive = true
Lastly, when I use debug view hierarchy I do see the height and width for my scrollingSV, and the views inside the containers.
Here is the code I am trying to get a size for the scrollingSV, which returns 0:
print("Scrollview height: \(scrollingSV.contentSize.height )")
I already tried to get the content size by using union as told in this stackoverflow answer: How do I auto size a UIScrollView to fit its content
But this also returns 0.
How can I get this scrolling stack view's size?
Or is it not calculated yet in viewDidLoad?
Thank you
Apparently in viewDidLoad the views were not finished with laying out their subviews. So the height was not meaningful yet.
When I did this check in viewDidAppear, the problem is fixed and I could reach the scrolling stack view's contentSize and frame height.
override func viewDidAppear(_ animated: Bool) {
super.viewDidAppear(animated)
scrollingSV.isScrollEnabled = scrollingSV.contentSize.height > scrollingSV.frame.height
}

Controls at the bottom of UIScrollView not working

The UIButton in the scrollView is visible, but not accessible. I am using Constraints.
My UI structure is this:
- UIView
- scrollView: UIScrollView
- contentView: UIView
- UIButton
- UIButton
- UIButton
- ....
- UIButton
I've already tried to set the contentSize of the scrollView. And the height of the contentView. Next to that I've tried to uncheck the checkbox Adjust Scroll View Insets in the storyboard of that ViewController without any luck. I've also set the priority of the Align Center Y to 250, and the priority bottom space to 250 of the contentView.
func updateScrollViewSize() {
var contentRect = CGRect.zero
for view in contentView.subviews {
contentRect = contentRect.union(view.frame)
}
contentRect.size = CGSize(width: scrollView.contentSize.width, height: contentRect.height + 50)
scrollView.contentSize = contentRect.size
contentView.frame.size = contentRect.size
contentView.layoutIfNeeded()
}
The button I try to reach has a Y value of: 1030.0
The height of the contentView is: 871.0
Step-by-step:
Add a scroll view to your view, background color red, constrain it 20-pts on each side:
Add a UIView as your "content view" to the scroll view (green background to make it easy to see), constrain it 0-pts on each side, constrain equal width and equal height to the scroll view. Important: change the Priority of the Height constraint to 250!
Add a UILabel to the contentView, constrain it 30-pts from the top, centered horizontally:
Add another label to the contentView, constrain it 300-pts from the first label, centered horizontally:
Add a UIButton to the contentView, constrain it 30-pts from the bottom, centered horizontally:
Now add a vertical constraint from the bottom of the second label to the top of the button, and set it to 400-pts:
As you see, this pushes the button off-screen past the bottom of the scroll view.
Run the app. You will be able to scroll down to see the button, and you'll be able to tap it.
Absolutely no code needed!
If you use AutoLayout, you don't needed to install frames manually.
You can try install constraints properly and content size will be right in this case and you won't have to install content size manually.
If you achieve this, I guess everything will work correctly.
You can follow this or this guide

Programatically changing the ContentInset of a UIScrollView doesn't actually change anything

I have a UIScrollView created in Interface builder, now in that UIScrollView there's a UITextField. When the keyboard opens, I'd like to change the ContentInset of the UIScrollView to fit the keyboard.
I've done this previously through a package called RXKeyboard, which reactively gives me the height of the keyboard:
RxKeyboard.instance.visibleHeight
.drive(onNext: { height in
self.scrollView.contentInset.bottom = height
print("offset", self.scrollView.contentInset)
}).disposed(by: disposeBag)
Now the ContentInset of the UIScrollView does change (shown through the print), however, nothing actually changes, and the bottom part of my UIScrollViewis hidden by the keyboard...
Am I missing something here? I tried moving this into viewDidLayoutSubviews, I tried layoutSubviews() after setting the inset, but I can't get this to work.
Does anyone know a solution to this?
Thanks!
That's right you've set your scrollView's insets to be keyboard's height but as the keyboard comes up you want to make your scrollView Content to come up to keyboard's height.
You have to scroll your scrollView to keyboard height by adjusting it's contentOffset property.
RxKeyboard.instance.willShowVisibleHeight
.drive(onNext: { keyboardVisibleHeight in
self.scrollView.contentOffset.y += keyboardVisibleHeight
})
.disposed(by: disposebag)
As the documentation says,
The point at which the origin of the content view is offset from the origin of the scroll view.
By setting contentOffset.y to keyboard's height, you are telling scrollView to move/scroll to that height.

My ScrollView is not scrolling vertically

I'm writing an app in Xcode 9 with Swift 4 and I've added a UIScrollview to a view which is intended to show a jPeg which is 3030 pixels in height. I've added the scrollview to my view and assigned the delegate in Outlets in IB. I've attached the IBOutlet called scrollView to the UIScrollview and added a UIImageView with the jPeg to the UIScrollview. I've set the size of the UIScrollView to 375W and 620H and then set the UIImageView to 375W and 3030H. this should complete the work in Interface builder.
In the Controller I've added UIScrollViewDelegate to the Class and added the code below to ViewDidLoad
//scrollView.delegate = self
scrollView.contentSize = CGSize(width: 375, height: 3040)
I've commented out the delegate line as I've done that in IB. When I run the app, the screen comes upon with the image but when I try to scroll it barely scrolls more than one screen. What have I missed?
You need to add a UIView inside your scrollview and then add that view top/bottom/leading/trailing 0 to scrollview then add your image view inside view and add image view bottom constraint to that view, So your scroll view will work properly.
Please refer below image for more details.
You have to place your scroll view inside a UIView and another UIView inside your scroll view.
Outer view Constraints: Leading,trailing,top and bottom - 0
Scroll view Constraints: Leading,trailing,top and bottom - 0
Inner view Constraints: Leading,trailling and top to Superview, Equal width to Outer view , Bottom space to -250 and Height equals 900(Height of your content)
Set your contentsize now.
You can implement as below image screen shots
//Height Constant of image
#IBOutlet weak var ConstHeight: NSLayoutConstraint!
override func viewDidLoad() {
super.viewDidLoad()
if #available(iOS 11.0, *) {
self.scrollView.contentInsetAdjustmentBehavior = .never
}else{
self.automaticallyAdjustsScrollViewInsets = false
}
//You can change height on here too
self.ConstHeight.constant = 800
}

Scroll in UIScrollView with tvOS

I stuck with scrolling content inside UIScrollView in my tvOS app.
I have scrollView with height = 400 and width = 400. Inside this scrollview I have non-scrollable UITextView with height = 800 and width = 400. So I want to scroll this text.
But my scroll view is not scrolled, I don't see any scrolling indicators and also my scrollView have isFocused value = false. How can I solve this problem?
p.s. update I created separate ViewController (image below).
It have black ScrollView and white view with big height with label in the middle of it. ScrollView has fixed width and height and there is no scrolling for some reason! I even didn't connect any separate class - just created it from Interface builder.
UIView isn't focusable by default (and as such in tvOS it can't be scrolled) . You have to subclass it to override canBecomeFocused:
class myUIView: UIView {
override var canBecomeFocused: Bool {
return true
}
}
Then in your example use the class myUIView instead of UIView for your long white view. Setting the right constraints you wouldn't need to design the views out of the controller view boundaries in IB either. Check this answer with the linked gist to see how to build the constraints.
I think you can use the
func gestureRecognizer (_ gestureRecognizer: UIGestureRecognizer, shouldReceive touch: UITouch) -> Bool
method to judge the view and scroll it
According to the view you touch to do something to intercept
There is some way to fix your problem.
Please check your scrollview in storyboard, is your scrolling or vertical indicator is checked?
U can make your textview scrollable if u just want to scroll the textview content
There is problem in your constraint, you need to cleary add the height, vertical space top, vertical space bottom from your textview to your scrollview.
Hope these advice can help you
So you have to set the scrollview's content size larger than the scrollview bounds, so you should set contentsize to (400, 800), probaly in you xib