How to edit UIScrollView size? - ios

I'm trying to build this:
But instead, I have this:
I haven't started working on background color or changing the slide's background color when selected yet.
My error right now is that I can't get the sizes right (you can tell that when I scroll to the end, it stops at slide 2).
How do I make the frame and slides fit correctly? (each slide is 188 width and 153 height).
Here's my code:
func setupSlideScrollView(slides : [Slide]) {
scrollView.frame = CGRect(x: 0, y: 0, width: 200, height: 160)
scrollView.contentSize = CGSize(width: 188 * CGFloat(slides.count), height: 153)
scrollView.isPagingEnabled = true
for i in 0 ..< 3 {
slides[i].frame = CGRect(x: view.frame.width * CGFloat(i), y: 0, width: 188, height: 153)
slides[i].backgroundColor = UIColor.red
scrollView.addSubview(slides[i])
}
}
For all the code, I'm following this tutorial (except Step 10+ since I don't need animation): https://medium.com/#anitaa_1990/create-a-horizontal-paging-uiscrollview-with-uipagecontrol-swift-4-xcode-9-a3dddc845e92

You are not giving the correct frame to the cells or tickets inside the scrollview.
var lastCellMaxX: CGFloat = 0
var constantSpacingBetweenCell: CGFloat = 10
for i in 0 ..< 3 {
slides[i].frame = CGRect(x: lastCellMaxX, y: 0, width: 188, height: 153)
slides[i].backgroundColor = UIColor.red
scrollView.addSubview(slides[i])
lastCellMaxX += 188 + constantSpacingBetweenCell
}
I didn't get what is view.frame and I think that is also of no use in your case.
Store the lastcellMaxX which is cell.origin.x + cellwidth + spacingBetweenCell,
That will be the x while giving frame to the next view

You have to add the space between two slides in the width parameter of scrollview.
In scrollview the content size is the total size of the content you are adding. so, if there is a space between two slides or if you have leading and trailing space then you have to add that total space in content size of scrollview.
For example, If the space between two slides is 10 then, the modified content size of scrollView is as below.
scrollView.contentSize = CGSize(width: 188 * CGFloat(slides.count) + CGFloat((slides.count - 1) * 10), height: 153)

Related

UITableView header align with cell bounds

I am generating a custom header view for my UITableView which has two horizontal lines up & down and a UILabel in between.
let lineWidth = tableView.bounds.width //This is not correct, will never align with UITableViewCell
let offset = (tableView.bounds.width - lineWidth)/2 //This will always yield 0, but my question is to compute line width that aligns with UITableViewCell as shown in the image attached to this question.
let topLine = UIView(frame: CGRect(x: offset, y: 0, width: lineWidth, height: 1))
topLine.backgroundColor = UIColor.white
let bottomLine = UIView(frame: CGRect(x: offset, y: 49.0, width: lineWidth, height: 1))
bottomLine.backgroundColor = UIColor.white
let label = UILabel(frame: CGRect(x: 0, y: 1.0, width: tableView.bounds.width, height: 48.0))
label.textColor = UIColor.white
let headerView = UIView(frame: CGRect(x: 0, y: 0, width: tableView.bounds.width, height: 50))
headerView.addSubview(topLine)
headerView.addSubview(label)
headerView.addSubview(bottomLine)
Problem: I need the top & bottom lines to align with UITableViewCell bounds in the section as shown in the picture below. What I get with the code above is horizontal lines that cover the entire width of UITableView. How do I achieve it?
EDIT: Some answers here describe an arbitrary offset value, but the heart of the problem is how to compute offset that aligns with UITableViewCell bounds in the section? In other words, I need exact width of UITableViewCell's that go into the section.
Your Offset will be practically zero as you are subtracting the same things
let lineWidth = tableView.bounds.width
let offset = (tableView.bounds.width - lineWidth)/2
let topLine = UIView(frame: CGRect(x: offset, y: 0, width: lineWidth, height: 1)) // this line gonna give offset as zero and width of full tableview width
Change this to the below code and try
let lineWidth = tableView.bounds.width - 20
let topLine = UIView(frame: CGRect(x: 10, y: 0, width: lineWidth, height: 1))
It seems the issue with the position of your top & bottom lines. As per the calculation of offset it always set to 0 for top & bottom lines. So it would be better to remove that offset calculation and you can add some desired static value as a x for CGRect of top & bottom lines.
As far as we are going to move the position of x for the top & bottom line don't forget to remove the added value for x position from the width of the top & bottom lines.
let yourLine = UIView(frame: CGRect(x: some_value, y: 0, width: Int(lineWidth - (some_value * 2)), height: 1))
The best practice is you can use some variables to achieve this.

Why doesn't view change when I change bounds?

If I change a UIView's bounds from...
v2.bounds = CGRect(0, 0, 70, 70)
to...
v2.bounds = CGRect(-2000, 0, 70, 70)
... nothing happens - the dimensions stay the same upon rendering. Why is this?
To help understand what bounds does, run this sample code in a view controller's viewDidLoad method:
let newView = UIView(frame: CGRect(x: 50, y: 100, width: 30, height: 30))
newView.backgroundColor = UIColor.blue
let secondView = UIView(frame: CGRect(x: 0, y: 0, width: 20, height: 20))
secondView.backgroundColor = UIColor.red
newView.addSubview(secondView)
view.addSubview(newView)
DispatchQueue.main.asyncAfter(deadline: .now() + 1) {
newView.bounds = CGRect(x: 10, y: 0, width: 30, height: 30)
}
Here we're moving the bounds to the right by 10 points, so you'll see the "second view" (which is red) move to the left by 10 points.
Changing the origin of the bounds changes the coordinate system of the view, which affects the location of all of it's subviews. It doesn't affect its origin with respect to its super view, however. For that, you should change the origin of the frame.
Bounds only takes into account width and height, you are only changing the origin in your example, only changing x to be precise. To accomplish this use frame property:
v2.frame = CGRect(-2000, 0, 70, 70)

Setting UICollectionView frame at runtime

I am trying to set the frame of my UICollectionView at runtime.
I tried using
mainCollectionView.frame = CGRect(x: 20, y: 20, width: self.view.frame.width-20, height: self.view.frame.width-20)
in my viewDidLoad but unfortunately it will always stay as in IB.
I am not yet using constraints.
Otherwise resizing my cells is working in cellForItem:
collectionCell.frame.size.width = self.view.frame.width/8 * 3
Try to set frame in viewDidLayoutSubviews
you are wrong write height because you are set width at height.
try this line without navigation bar:
mainCollectionView.frame = CGRect(x: 20, y: 20, width: UIScreen.mainScreen().bounds.size.width - (20 * 2), height: UIScreen.mainScreen().bounds.size.height - (20 * 2))
Run the following in one of the LayoutSubviews overrides. This will tell collection view to update its frame.
override func viewWillLayoutSubviews() {
super.viewWillLayoutSubviews()
mainCollectionView.frame = CGRect(x: 0, y: 0, width: self.view.frame.width, height: self.view.frame.height)
mainCollectionView.collectionViewLayout.invalidateLayout()
}

Setting dynamic height on UItextview to fit content programmatically

Just by programmatically coding, I'm trying to achieve something like below image. TextView and ContainerView are embedded in scrollview although it is not shown in the image.
Here is my code for this.
override func viewDidLoad() {
super.viewDidLoad()
let margin = CGFloat(10)
textView = UITextView()
textView.text = "asdadaasdadadadasdadadadasdadadadasdadadadasdadadadasdadadadasdadadadasdadadadasdadadadasdadadadasdadadadasdadadadasdadadadasdadadadasdadadadaadasdadadadasdadadadasdadadadasdadadadasdadadadasdadadadasdadadadasdadadadasdadadadasdadadadasdadadadasdadadadasdadadaddadd"
let contentSize = textView.sizeThatFits(textView.bounds.size)
textView.frame = CGRectMake(margin, 0, self.view.frame.width - 2 * margin, contentSize.height)
let scrollView = UIScrollView(frame: CGRect(x: 0, y: 0, width: self.view.frame.width, height: self.view.frame.height - 50))
let containerView = UIView(frame: CGRectMake(margin, contentSize.height + margin, self.view.frame.width - 2 * margin, self.view.frame.height))
let button1 = UIButton(frame: CGRectMake(margin, contentSize.height + containerView.frame.height + 2 * margin, (view.frame.width - 2 * margin)/2, 30))
scrollView.contentSize = CGSize(width: self.view.frame.width, height: button1.frame.origin.y + button1.frame.height + margin)
self.view.addSubview(scrollView)
scrollView.addSubview(textView)
scrollView.addSubview(containerView)
scrollView.backgroundColor = UIColor.blueColor()
containerView.backgroundColor = UIColor.yellowColor()
textView.backgroundColor = UIColor.greenColor()
}
The problem is that textview's height is not dynamic to show all content in textview.
I've confirmed that if I add below code in viewdidappear, it does make the height of textview dynamic but it is stacked under Container view because below code runs after ViewDidLoad configured everything.
let contentSize = textView.sizeThatFits(textView.bounds.size)
textView.frame = CGRectMake(margin, 0, self.view.frame.width - 2 * margin, contentSize.height)
What would be the best approach for this kind of problem?
I think this is caused due to rendering order in viewdidload but I'm not 100% sure. It would be great if someone can talk about rendering order too.
To answer the original question, your call to sizeThatFits has no idea how tall the TextView should be because it has no idea how wide you want it to be. I think before the sizeThatFits line you want the following:
textView.frame.size.width = self.view.frame.width - 2 * margin

Wrong alignment of subviews in a UIScrollView

I have the following code, which creates UIView, and some of its subViews, and adds them to a UIScrollView, all in a loop :
var count:CGFloat=bookScrollView.frame.minX
for var i=0;i<10;i++ {
var view=UIView(frame: CGRect(x: count + 20, y: bookScrollView.frame.minY + 30, width: 200, height: 300))
view.backgroundColor=UIColor.whiteColor()
view.layer.cornerRadius = 5;
view.layer.masksToBounds = true;
var imageView=UIImageView(frame: CGRect(x: count, y: view.frame.minY - 30, width: 150, height: 220))
// imageView.image=UIImage(named: "Sample_Book")!
view.addSubview(imageView)
var titleLabel=UILabel(frame: CGRect(x: count + 10, y: imageView.frame.maxY + 30, width: 185, height: 60))
titleLabel.text="Head First Javascript"
titleLabel.backgroundColor=UIColor.clearColor()
titleLabel.font=UIFont(name: "Menlo-Bold ", size: 15)
titleLabel.textAlignment = NSTextAlignment.Center
titleLabel.textColor=UIColor.grayColor()
view.addSubview(titleLabel)
bookScrollView.addSubview(view)
count+=220
}
bookScrollView.contentSize=CGSize(width: count, height: 200)
It works fine,except the fact that other than in the first view,imageView and titleLabel are not visible.
The label and the imageView have moved towards the right from the second view onwards.
Frames are expressed according to the superview's coordinate space.
Since you're adding your image view and label to the view not the scroll view, their frames should be specified in view's coordinate space. So you do not need to add count to their x position.
var imageView=UIImageView(frame: CGRect(x: 0.0, y: 0.0, width: 150, height: 220))
And:
var titleLabel=UILabel(frame: CGRect(x: 10.0, y: imageView.frame.maxY + 30, width: 185, height: 60))
Note: You should look into UICollectionView and autolayout for a more robust way of achieving this.

Resources