How to make a stretchable image view by scroll view - swift

I have a scroll view and an imageView at the top, I want to pin and make a stretchable image view but if I add this image view to the view the image won't disappear when the user scroll down the view and if I add the image to the scroll view this won't be pinned at the top when the user scroll down.
So how can I pin the image at the top and then when the user scroll down the image will disappear.
Like that: http://blog.enabled.com.au/stretchy-layouts-on-ios/ but not with his framework.
class LocalsVC: UIViewController, UIScrollViewDelegate {
#IBOutlet weak var imageView: UIImageView!
#IBOutlet weak var scrollView: UIScrollView!
override func viewDidLoad() {
super.viewDidLoad()
setNavBarSettings()
scrollView.delegate = self
imageView.contentMode = .scaleAspectFill
imageView.clipsToBounds = true
view.addSubview(imageView)
}
func scrollViewDidScroll(_ scrollView: UIScrollView) {
let y = 300 - (scrollView.contentOffset.y + 300)
let height = min(max(y, 60), 400)
imageView.frame = CGRect(x: 0, y: 0, width: UIScreen.main.bounds.size.width, height: height)
}

Add the image to the scrollView and not to the view: scrollView.addSubview(imageView).

Related

Center ImageView in ScrollView with paging enabled - Swift

I need to create a paging ScrollView which shows a sequence of images.
I created a ScrollView in the main view of the Storyboard and set this constraints (to center the ScrollView in the view):
Constraint
Then I activated paging and disabled the "Content layout guides" option.
Next, in the view class I set up the UIScrollViewDelegate delegate and I wrote the following code to show 3 images (they are 3 colored squares):
class ViewController: UIViewController, UIScrollViewDelegate {
// Outlet
#IBOutlet weak var scrollview: UIScrollView!
override func viewDidLoad() {
super.viewDidLoad()
scrollview.delegate = self;
let infoArray = ["01", "02", "03"];
for i in 0..<infoArray.count {
let imageView = UIImageView();
imageView.contentMode = .scaleToFill;
imageView.image = UIImage(named: infoArray[i]);
let xPos = CGFloat(i) * scrollview.bounds.size.width;
imageView.frame = CGRect(x: xPos, y: 0, width: scrollview.bounds.size.width, height: scrollview.bounds.size.height);
imageView.layer.borderWidth = 1;
scrollview.contentSize.width = scrollview.frame.size.width * CGFloat(i+1);
scrollview.contentSize.height = scrollview.frame.size.height;
scrollview.addSubview(imageView);
}
scrollview.layer.borderWidth = 1;
}
}
I have set that the images must have the same width and height as the scrollview. But these are larger in the simulator (and in my iPhone 11) and therefore the display is incorrect. I show you the sequence of the 3 squares:
Page 1
Page 2
Page 3
Page 4
I can't understand where I'm wrong. Why don't the 3 images take the size of the scrollview?
Why are there 4 pages?
Thanks for your help
Okay, here is how you do it:
Your scrollview is created in storyboard and its layout is set. Make sure content layout guides is unchecked in the size inspector and paging is checked in the attribute inspector.
Add a stackview as a subview to your scrollview (this will act as the content view). Pin your stackView to all 4 edges of the scrollView.
Set Height and Width Equal to the scrollView height and width. Set the Width priority to 250. (that indicates that the scrollview will scroll horizontally)
Set the stackView to horizontal axis, fill alignment and fillEqually distribution.
Now, go back to viewDidLoad and add the following code below. ScrollViewContentView is the stackView that acts as a contentView for the scrollView. Note that since stackView is set to fillEqually, you only need set one of the image's width constraint.
scrollViewContentView.addArrangedSubview(image1)
scrollViewContentView.addArrangedSubview(image2)
scrollViewContentView.addArrangedSubview(image3)
image1.translatesAutoresizingMaskIntoConstraints = false
image2.translatesAutoresizingMaskIntoConstraints = false
image3.translatesAutoresizingMaskIntoConstraints = false
image1.backgroundColor = .blue
image2.backgroundColor = .yellow
image3.backgroundColor = .red
image1.widthAnchor.constraint(equalTo: scrollView.widthAnchor).isActive = true
I think you need to state the frame of the scrollview before you declare the imageViews x positions or widths.
class ViewController: UIViewController, UIScrollViewDelegate {
// Outlet
#IBOutlet weak var scrollview: UIScrollView!
override func viewDidLoad() {
super.viewDidLoad()
scrollview.frame = view.frame // declared here
scrollview.delegate = self;
let infoArray = ["01", "02", "03"];
for i in 0..<infoArray.count {
let imageView = UIImageView();
imageView.contentMode = .scaleToFill;
imageView.image = UIImage(named: infoArray[i]);
let xPos = CGFloat(i) * scrollview.bounds.size.width;
imageView.frame = CGRect(x: xPos, y: 0, width: scrollview.bounds.size.width, height: scrollview.bounds.size.height);
imageView.layer.borderWidth = 1;
scrollview.contentSize.width = scrollview.frame.size.width * CGFloat(i+1);
scrollview.contentSize.height = scrollview.frame.size.height;
scrollview.addSubview(imageView);
}
scrollview.layer.borderWidth = 1;
}
}

UIViewController not adjusting correctly in UIScrollView for all iPhones

I am trying to replicate a Tinder like menu, with the 3 UIViewControllers in a UIScrollView and a custom menu tab on the top, with a button for each UIViewController. I am facing an interesting problem where the UIViewControllers views fit perfectly in the scrollView.frame, but only for iPhone 8. In contrast, for iPhone SE, it leaves a white margin and for iPhone 8+, it seems to overlap the views within the scrollView.view. Could someone explain why this is happening and how I can fix it?
Here's my code where I'm adjusting setting up my UIViewControllers in my UIScrollView:
import UIKit
class MainViewController: UIViewController {
#IBOutlet weak var scrollView: UIScrollView!
#IBOutlet weak var navigationView: UIView!
override func viewDidLoad() {
super.viewDidLoad()
setUpHorizontalScrollViews()
}
func setUpHorizontalScrollViews(){
let view = (
x: self.view.bounds.origin.x,
y: self.view.bounds.origin.y,
width: self.view.bounds.width,
height: self.view.bounds.height
)
let scrollWidth = 3 * view.width
let scrollHeight = view.height
scrollView.contentSize = CGSize(width: scrollWidth, height: scrollHeight)
scrollView.contentOffset.x = view.x
if let messagesView = self.storyboard?.instantiateViewController(withIdentifier: "MessagesVC") as UIViewController! {
self.addChildViewController(messagesView)
self.scrollView.addSubview(messagesView.view)
messagesView.didMove(toParentViewController: self)
messagesView.view.frame = CGRect(x: 0,
y: 0,
width: view.width,
height: view.height
)
}
if let friendsView = self.storyboard?.instantiateViewController(withIdentifier: "FriendsVC") as UIViewController! {
self.addChildViewController(friendsView)
self.scrollView.addSubview(friendsView.view)
friendsView.didMove(toParentViewController: self)
friendsView.view.frame = CGRect(x: view.width,
y: 0,
width: view.width,
height: view.height
)
}
if let settingsView = self.storyboard?.instantiateViewController(withIdentifier: "SettingsVC") as UIViewController! {
self.addChildViewController(settingsView)
self.scrollView.addSubview(settingsView.view)
settingsView.didMove(toParentViewController: self)
settingsView.view.frame = CGRect(x: 2 * view.width,
y: 0,
width: view.width,
height: view.height
)
}
// offset to the second view
self.scrollView.contentOffset.x = view.width
}
override var shouldAutorotate: Bool {
return false
}
override func didReceiveMemoryWarning() {
super.didReceiveMemoryWarning()
// Dispose of any resources that can be recreated.
}
}
This is what my Setup looks like. the top is the MainViewController, containing the UIScrollView and on bottom are the 3 viewcontrollers that are supposed to go into the scrollView.
This is what I want it to look like, and the way it sets up in iPhone 8:
This is what it looks like on iPhone SE and where my problem is:
The problem is that since you are calling the setUpHorizontalScrollViews method in the viewDidLoad(), the UIViewController has yet to layout the subview, and also calculate their final size.
It is working in an iPhone 8 because most provably it has the same screen size you used in the interface builder.
Solution 1
In order to solve the problem, you can move your code to the viewDidAppear() method. However, this will cause an ugly effect once you open the UIViewController (unless you add a full screen loading).
Solution 2
Add view.layourIfNeeded() like this:
override func viewDidLoad() {
super.viewDidLoad()
view.layourIfNeeded()
setUpHorizontalScrollViews()
}

How to fix AutoLayout for my ScrollView?

I have a view controller that has a UIView(ParentView) and then UIScrollview(ScrollView). The ParentView is anchored to the leading, trailing, top and bottom of the ViewController. The ScrollView is anchored to the leading, trailing, top and bottom of the ParentView. The structure is like this:
-UIView
--ParentView
---ScrollView
Then I created a xib file that has an image and a label. The xib will be added dynamically to the ScrollView. The xib frame height and width are equal to the ScrollView height and width.
When I run the simulator on iphone 6 plus the scroll works perfectly; the width of the xib is exactly the width of the screen. But when i run the simulator with iphone 6, the width of the xib is the same size of the screen, there is an extra space when scrolling to the next item. What should I do to removed it!?
This is a screen shot for iphone 6 plus
This is a screen shot for iphone 6. Notice the extra space of the second screen
And here is my code:
import UIKit
class ViewController: UIViewController {
#IBOutlet weak var ParentView: UIView!
#IBOutlet weak var ScrollView: UIScrollView!
override func viewDidLoad() {
super.viewDidLoad()
// Do any additional setup after loading the view, typically from a nib.
let photos = ["joe", "john"]
let userNames = ["joe", "john"]
self.ScrollView.frame = CGRectMake(0, 0, self.ParentView.frame.size.width, self.ParentView.frame.size.height)
self.ScrollView.contentSize = CGSizeMake(self.ParentView.frame.size.width * CGFloat(photos.count), self.ParentView.frame.size.height)
self.ScrollView.pagingEnabled = true
var i: Int = 0
while i < 2 {
if let userXib = NSBundle.mainBundle().loadNibNamed("User", owner: self, options: nil)[0] as? User {
userXib.frame = CGRect(x: self.ScrollView.frame.size.width * CGFloat(i), y: 0, width: self.ScrollView.frame.size.width, height: userXib.frame.size.height)
userXib.assignValues(photos[i], myName: userNames[i])
self.ScrollView.addSubview(userXib)
}
i = i + 1
}
}
override func didReceiveMemoryWarning() {
super.didReceiveMemoryWarning()
// Dispose of any resources that can be recreated.
}
}
UPDATE #1 - Coder1000 solution:
I tried implementing #3 & #4 in your answer by adding the UIView layer inside the scroll. I called it ScrollMainView. In the storyboard, I set its leading, trailing, top and bottom to fill its superview: Scrollview and then in the loop added those elements to it instead of the scrollview. But now the scroll doesn't scroll! My code and final display look like this:
import UIKit
class ViewController: UIViewController {
#IBOutlet weak var ParentView: UIView!
#IBOutlet weak var ScrollView: UIScrollView!
#IBOutlet weak var ScrollMainView: UIView!
override func viewDidLoad() {
super.viewDidLoad()
let photos = ["joe", "john"]
let userNames = ["joe", "john"]
self.ScrollView.frame = CGRectMake(0, 0, self.ParentView.frame.size.width, self.ParentView.frame.size.height)
self.ScrollView.contentSize = CGSizeMake(self.ParentView.frame.size.width * CGFloat(photos.count), self.ParentView.frame.size.height)
self.ScrollView.pagingEnabled = true
self.ScrollMainView.frame = CGRectMake(0, 0, self.ScrollView.frame.size.width, self.ScrollView.frame.size.height)
print("the frame for parentview is: \(self.ParentView.frame)")
var i: Int = 0
while i < 2 {
if let userXib = NSBundle.mainBundle().loadNibNamed("User", owner: self, options: nil)[0] as? User {
userXib.frame = CGRect(x: self.ScrollMainView.frame.size.width * CGFloat(i), y: 0, width: self.ScrollMainView.frame.size.width, height: userXib.frame.size.height)
userXib.assignValues(photos[i], myName: userNames[i])
self.ScrollMainView.addSubview(userXib)
}
i = i + 1
}
self.ScrollView.addSubview(ScrollMainView)
}
override func didReceiveMemoryWarning() {
super.didReceiveMemoryWarning()
}
}
There are several solutions, in viewDidLoad the frame is not set correctly, so when you ask it, it is wrong.
The parentView and your scrollView are adjusted by the autolayout constraint later, but you User view is not...
A simple solution may be to put the code in:
override func viewDidLayoutSubviews() {
super.viewDidLayoutSubviews()
self.ScrollView.frame = CGRectMake(0, 0, self.ParentView.frame.size.width, self.ParentView.frame.size.height)
self.ScrollView.contentSize = CGSizeMake(self.ParentView.frame.size.width * CGFloat(photos.count), self.ParentView.frame.size.height)
self.ScrollView.pagingEnabled = true
for subView: UIView in self.ScrollView.subviews {
if subView is User { subView.removeFromSuperview()
}
var i: Int = 0
while i < 2 {
if let userXib = NSBundle.mainBundle().loadNibNamed("User", owner: self, options: nil)[0] as? User {
userXib.frame = CGRect(x: self.ScrollView.frame.size.width * CGFloat(i), y: 0, width: self.ScrollView.frame.size.width, height: userXib.frame.size.height)
userXib.assignValues(photos[i], myName: userNames[i])
self.ScrollView.addSubview(userXib)
}
i = i + 1
}
}
Or you can add constraints to your custom xib programmatically.
Or you can keep an array of your costom xibs and just adjust their frames, AND THE SCROLLVIEW CONTENTSIZE, in viewDidLayoutSubviews()
Or you can put the code in viewDidAppear()

Cocoa NSScrollView not scrolling

I try to create a scrollview. Created a scrollview via Xib, programmatically added scrolledView (a NSView that contains all subview in scrollView).
The following code shows the subviews but the scrollView not scroll. Why?
class LevelScrollController: NSViewController {
#IBOutlet var scrollView: NSScrollView!
override func viewDidLoad() {
super.viewDidLoad()
let scrolledView = NSView(frame: NSRect(x: 0, y: 0, width: scrollView.frame.size.width, height: 300))
// Inserisco pulsanti di esempio
for i in 1 ... 10{
scrolledView.addSubview(NSButton(frame: NSRect(x: 0, y: i*30, width: 100, height: 30)))
}
scrollView.addSubview(scrolledView)
}
Putting the code in viewDidLayout instead of viewDidLoad not change the result: not scroll
Instead of add scrolledView to subview of scrollView, set it as documentView.
Replace scrollView.addSubview(scrolledView) with scrollView.documentView = scrolledView

Swift: Embed a scrollView in a custom UITableViewCell

I am working on this UITableViewCell customization to get something similar to a Facebook feed look.
I need a cell to contain 2 labels followed by a scroll view(to display some images). I have tried with having these 3 elements inside a uiView as such,
-Cell
--contentView
---UIView
----Label
----Label
----ScrollView
#IBOutlet weak var dateLabel: UILabel!
#IBOutlet weak var contentLabel: UILabel!
#IBOutlet weak var scrollView: UIScrollView!
#IBOutlet weak var cardView: UIView!
I need the cells to adjust the height based on the length of the text.
Where I am stuck at is where the cell adjusts the height based on the text, but the scrollview that is displayed, is split into two cells.
Needless to say I am new to swift. This is the basic flow of what I have so far in cellForRowAtIndexPath
cell.dateLabel.text = somedatelabel
cell.contentLabel.text = someContent
let width = cell.scrollView.frame.width
let height = cell.scrollView.frame.height
var mainCardView = UIView(frame: CGRectMake(cell.frame.origin.x, cell.frame.origin.y, cell.frame.width, cell.frame.height))
var scrollview = UIScrollView(frame: CGRectMake(cell.contentLabel.frame.origin.x, cell.contentLabel.frame.origin.y+cell.contentLabel.frame.height, width, height))
scrollview.contentSize = CGSizeMake(width*2, height)
var imageOne = UIImageView(frame: CGRectMake(0, 0, width , height))
var imageTwo = UIImageView(frame: CGRectMake(width, 0, width, height))
imageOne.image = UIImage(named: "one.jpg")
imageTwo.image = UIImage(named: "two.jpg")
scrollview.addSubview(imageOne)
scrollview.addSubview(imageTwo)
scrollview.contentSize = CGSizeMake(width*2, height)
scrollview.contentMode = UIViewContentMode.ScaleAspectFit
mainCardView.addSubview(scrollview)
cell.cardView = mainCardView
cell.contentView.addSubview(mainCardView)
cell.layoutSubviews()
cell.layoutIfNeeded()
I also added this in viewDidLoad
tableView.estimatedRowHeight = 150.0
tableView.rowHeight = UITableViewAutomaticDimension
Any suggestions on how to size the cell so that scrollView is part of the contentView?