UIScrollView pages content not working properly - iOS - ios

I've been trying for one whole day to make it work right. I tried different tutos and made adjustments (searching in here) but it doesnt work properly.
On iphone 5s, it almost works right, excepts for the last page that it seems to add "half" of a page on scroll view. The green part is the background color of the scroll view and it doesn't bounce back.
On iphone 6, the content is all messed up and instead of having 5 images, it has only 4 and a half (i cant scroll it anymore and it doesn't bounce back).
If I press continue, it works perfectly on both screen sizes. It is only the swipe option that is not working properly.
Here is the code where I put the images inside the scroll view.
func loadContent() {
var frame = CGRect(x: 0, y: 0, width: 0, height: 0)
for i in 0..<imageArr.count { // is 5
frame.origin.x = scrollView.frame.size.width * CGFloat(i)
frame.size = self.scrollView.frame.size
let imageView = UIImageView(frame: frame)
let image = UIImage(named: imageArr[i])
imageView.autoresizingMask = [.flexibleWidth, .flexibleHeight, .flexibleBottomMargin, .flexibleRightMargin, .flexibleLeftMargin, .flexibleTopMargin]
imageView.contentMode = .scaleAspectFit
imageView.clipsToBounds = true
imageView.backgroundColor = UIColor.red
imageView.image = image
scrollView.addSubview(imageView)
self.scrollView.contentSize.width = self.scrollView.frame.width * CGFloat(i)
}
}
///Function of Continue button
#IBAction func nextImage(_ sender: Any) {
UIView.animate(withDuration: 0.3) {
self.scrollView.contentOffset.x = self.scrollView.frame.width * CGFloat(self.pageControl.currentPage+1)
}
}
I've been searching for 4 hours for a solution but nothing seems to work.
[Edit]: With the answer of TheFuquan I could solve the problem.
[Obs:] if you searching about the messed content, these lines of code can help you. All the tutos that I saw didn't have these lines and the content just wouldnt align perfect and this solved:
imageView.autoresizingMask = [.flexibleWidth, .flexibleHeight, .flexibleBottomMargin, .flexibleRightMargin, .flexibleLeftMargin, .flexibleTopMargin]
imageView.contentMode = .scaleAspectFit
imageView.clipsToBounds = true

Why is the following line in your for loop:
self.scrollView.contentSize.width = self.scrollView.frame.width * CGFloat(i)
You should do this before the for loop like this:
self.scrollView.contentSize.width = self.scrollView.frame.width * imageArr.count

this is a typical problem that i face each time i try to load some dynamic content inside a view.
If you re calling your function loadContent from viewDidLoad, then you should call your loadContent inside viewDidLayoutSubviews
Be aware that unlike viewDidLoad, viewDidLayoutSubviews may get called multiple times, so have a flag to ensure that your loadContent gets invoked only once.
override func viewDidLayoutSubviews() {
super.viewDidLayoutSubviews()
guard self.didLoadContent == false else {
return
}
self.didLoadContent = true
loadContent()
}
this way you let the view loaded from your storyboard to resize the iPhone's size.

Related

UI freezes for a second when returning to the previous ViewController in Navigation Stack

I'm having some trouble figuring out what's causing the UI to freeze for a second when I press the back button. It started happening after I added a background image to the viewController that I'm transitioning from. If I'm just using "white" as my backgroundColor, the transition doesn't freeze, it only freezes once I add the image.
Here is a gif of what it looks like...
https://gfycat.com/waryagileichidna
Here is the extension that I'm calling in my viewDidLoad to set the background image...
extension UIView {
func addBackground(image:String) {
self.backgroundColor = .white
// screen width and height:
let width = UIScreen.main.bounds.size.width
let height = UIScreen.main.bounds.size.height
let imageViewBackground = UIImageView(frame: CGRect(x: 0, y: 0, width: width, height: height))
imageViewBackground.image = UIImage(named: "\(image)")
imageViewBackground.alpha = 0.5
// you can change the content mode:
imageViewBackground.contentMode = UIView.ContentMode.scaleAspectFill
self.addSubview(imageViewBackground)
self.sendSubviewToBack(imageViewBackground)
}
}
Could you try adding the below line to your addBackground method which you call in viewDidLoad.
imageViewBackground.clipsToBounds = true
I have a feeling this should solve it. That doesn't look like a freeze.

UIView unable to get transparent property

I am trying to add a subview to the window (for using it as side menu). It has a child view which is transparent view. However I am unable to get the transparent property when it runs in simulator.
I am using the following code:
override func viewWillAppear(_ animated: Bool) {
frame = CGRect(x: 0, y:0, width:0, height:0)
frame.size.height = UIScreen.main.bounds.height
frame.size.width = UIScreen.main.bounds.width
sideMenuView.frame = frame
sideMenuTransparentView.isOpaque = false
sideMenuTransparentView.backgroundColor = UIColor.gray.withAlphaComponent(0.5)
UIApplication.shared.keyWindow?.addSubview(sideMenuView)
}
However I am seeing no effect of this to make the view as transparent. What's possibly wrong here and how should I proceed rectifying this?
The weird thing here is that when I replace the lines
sideMenuTransparentView.isOpaque = false
sideMenuTransparentView.backgroundColor = UIColor.gray.withAlphaComponent(0.5)
with
sideMenuView.isOpaque = false
sideMenuView.backgroundColor = UIColor.gray.withAlphaComponent(0.5)
I can see the effect. I am unable to understand what's going in here and how should I correct this.
You seem to have forgotten to add the transparent view to the main sideMenuView.
override func viewWillAppear(_ animated: Bool) {
super.viewWillAppear(animated) // You need to call super when overriding
frame = CGRect(x: 0, y:0, width:0, height:0)
frame.size.height = UIScreen.main.bounds.height
frame.size.width = UIScreen.main.bounds.width
sideMenuView.frame = frame
sideMenuTransaparentView.frame = yourFrame // required frame
sideMenuTransparentView.isOpaque = false
sideMenuTransparentView.backgroundColor = UIColor.gray.withAlphaComponent(0.5) // 100% transparency
sideMenuView.addSubview(view: sideMenuTransparentView)
UIApplication.shared.keyWindow?.addSubview(sideMenuView)
}
Also, you forgot to call super.

Embedding UINavigationController in scrollView

I'm trying to do an application with 3 startup views, which you can swipe between. Pretty much Snapchat like.
I've got this going pretty well, but when I try to embed one of the 3 View Controller, it gets resized to a small part of the screen.
Here's my code:
override func viewDidLoad() {
super.viewDidLoad()
let accCtrl = AccountViewController()
let feedCtrl = UINavigationController(rootViewController: HomeViewController())
let hashsCtrl = AccountViewController()
self.addChildViewController(hashsCtrl)
self.scrollView!.addSubview(hashsCtrl.view)
hashsCtrl.didMoveToParentViewController(self)
self.addChildViewController(feedCtrl)
self.scrollView!.addSubview(feedCtrl.view)
feedCtrl.didMoveToParentViewController(self)
self.addChildViewController(accCtrl)
self.scrollView!.addSubview(accCtrl.view)
accCtrl.didMoveToParentViewController(self)
accCtrl.view.frame = view.frame
// feedCtrl.view.autoresizesSubviews = false
feedCtrl.view.frame = CGRectMake(view.frame.width, 0, view.frame.width, view.frame.height)
feedCtrl.setNavigationBarHidden(true, animated: false)
feedCtrl.view.setNeedsLayout()
hashsCtrl.view.frame = CGRectMake(view.frame.width * 2, 0, view.frame.width, view.frame.height)
scrollView.contentSize = CGSizeMake(view.frame.width * 3, view.frame.height)
scrollView.pagingEnabled = true
scrollView.showsHorizontalScrollIndicator = false
scrollView.showsVerticalScrollIndicator = false
scrollView.contentOffset = CGPointMake(view.frame.width, 0)
}
I've noticed that the resulting width of the view on-screen is pretty much x - 280. If I set the feedCtrl.view.frame to a width, the resulting width is 1.0 point. As it is actually - aka the screen width -, it results in a 40.0 point width.
I've also noticed that if I uncomment the line where I put the feedCtrl.view.autoresizeSubviews boolean to false, the width on-screen is correct, but I can't get user-interaction on the view.
Any ideas ?
I had a similar problem. In viewDidLoad, try to add (that worked for me):
self.ScrollView.frame = (UIApplication.sharedApplication().delegate?.window!.frame)!

Why does my UITableViewFooter jump to the top?

self.tableView.tableFooterView = PromptInviteView.instantiateFromNib()
I've tried putting this in viewWillAppear and viewDidLoad.
Great, everything shows up and displays correctly.
However, if:
I push HOME and open 4-5 other apps, then return back to my app, the footer will "jump" to the top, covering the first row.
If I perform other actions inside the app (navigating back and forth), and then finally going back to his vc, then it will jump to the top also.
When I pull to refresh, all is good again. But if I don't do anything...the footer stays at the top (replacing the top row + is not clickable)
Does anyone know why this behavior is occurring, and how I can solve it?
Update: I realize that "drawRect" in my xib gets called when I open the app after 4-5 other apps. And this is why the problem is happening.
In my drawRect code, I have this:
override func drawRect(rect: CGRect) {
super.drawRect(rect)
inviteLabel.textColor = UIColor(hex: 0x404040)
inviteLabel.text = STRINGS["PromptInviteLabelText"]
inviteLabel.numberOfLines = 0
inviteLabel.sizeToFit()
inviteButton.setTitle(STRINGS["PromptInviteButtonText"], forState: UIControlState.Normal)
inviteButton.backgroundColor = FlatWatermelon()
inviteButton.setTitleColor(UIColor.whiteColor(), forState: UIControlState.Normal)
inviteButton.setTitleColor(UIColor(hex: 0xcccccc), forState: UIControlState.Selected)
inviteButton.layer.cornerRadius = 2.0
inviteButton.clipsToBounds = true
super.layoutSubviews() //this will allow the view's frame to be set.
var padding = CGFloat(20.0)
self.frame = CGRectMake(0, 0, screenWidth, CGRectGetMaxY(inviteButton.frame) + padding )
var topBorder = UIView()
topBorder.frame = CGRectMake(0, 0, screenWidth, 0.5)
topBorder.backgroundColor = UIColor(hex: 0xededed)
self.addSubview(topBorder)
var bottomBorder = UIView()
bottomBorder.frame = CGRectMake(0, self.frame.size.height, screenWidth, 0.5)
bottomBorder.backgroundColor = UIColor(hex: 0xededed)
self.addSubview(bottomBorder)
}
How can I remove my code (especially the layoutSubview part) and put it somewhere else?
Is there another location where I should put the code? Is there a didLayoutSubviews() equivalent?

Image overlaps previous view when tapping/swiping back

I have a UIScrollView which covers one of my views entirely. I have added a background image to this same view which scrolls at a slightly different rate to the actual UIScrollView. This works absolutely fine unless I use the back swipe gesture or tap the 'Back' button. What happens is the image covers the view for about 0.5 seconds before disappearing, and it looks pretty bad.
This is what I mean:
As you can see, that is mid way through the gesture, and rather than being able to see the previous view, you just see the part of the image that is off to the left. It doesn't happen on the first page of the UIScrollView so I guess it's because the image is overlapping the previous view.
Here is my code:
override func viewDidLoad() {
let pagesScrollViewSize = scrollView.frame.size
scrollView.contentSize = CGSize(width: pagesScrollViewSize.width * CGFloat(images.count), height: pagesScrollViewSize.height)
backgroundImageView.frame = CGRect(x: 0, y: 0, width: 2484, height: 736)
backgroundImageView.image = UIImage(named: "SF.png")
var visualEffectView = UIVisualEffectView(effect: UIBlurEffect(style: .Light)) as UIVisualEffectView
visualEffectView.frame = backgroundImageView.bounds
backgroundImageView.addSubview(visualEffectView)
view.addSubview(backgroundImageView)
view.sendSubviewToBack(backgroundImageView)
scrollView.backgroundColor = UIColor.clearColor()
}
func scrollViewDidScroll(scrollView: UIScrollView) {
loadVisiblePages()
var factor = scrollView.contentOffset.x / (scrollView.contentSize.width - 414);
if factor < 0 {
factor = 0
}
if factor > 1 {
factor = 1
}
var frame: CGRect = backgroundImageView.frame
frame.origin.x = factor * (414 - backgroundImageView.frame.size.width)
backgroundImageView.frame = frame
}
Anyone have any suggestions?
You have to add the following in your viewDidLoad function:
self.view.clipsToBounds = true or scrollView.clipsToBounds = true if you just want to clip the subviews in your UIScrollView.
Setting this value to true causes subviews to be clipped to the bounds of the receiver. If set to false, subviews whose frames extend beyond the visible bounds of the receiver are not clipped. The default value is false.
From Apple' doc : https://developer.apple.com/library/ios/documentation/UIKit/Reference/UIView_Class/index.html#//apple_ref/occ/instp/UIView/clipsToBounds

Resources