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)
Related
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.
For the life of me, I can't figure out how to center a UIButton in UIScrollView...
let sv = UIScrollView(frame: CGRect(x: 0, y: 0, width: 300, height: 600))
let b = UIButton(frame: CGRect(x: 0, y: 0, width: 30, height: 30))
sv.addSubview(b)
b.center = sv.center
No matter what I do, the button seems to be off center. This logic works in normal UIView. Why doesn't it with UIScrollView?
you can also use
let b = UIButton(frame: CGRect(x: sv.frame.size.width/2 -15, y: sv.frame.size.height/2 -15, width: 30, height: 30))
for your code first check value of sv.center, if it is OK and your UI is not updating then call layoutIfneeded
Reference : How is layoutIfNeeded used?
I have been fighting with this all morning and can't seem to find a solution. I have created a UIImageView, filled it with red, then added it to a UIScrollView and set the contentSize to the size of the UIImageView. If I print the contentOffset i see (0, 0) and if I print the contentSize and the UIImageView.frame.size they are the same but the red "image" always appears smaller than what the scrollView thinks the contentSize is.
If I scroll all the way to the top I see a cyan stripe about 100 pixels high above the red image and the scroll bar will not make it all the way to the top of what I believe the top of my scroll view to be. Although the top of the scroll bar does line up with the top of my red window so it would seem as though the scroll view is confused as to where it actually lives. Or more likely, I'm confused
Here is my what seems like very simple code...
imgHorizon = UIImage.init(named:"horizon")!
imgBezel = UIImage.init(named:"bezel_transparent")!
imgWings = UIImage.init(named:"wings_transparent")!
imgViewHorizon = UIImageView.init()
imgViewBezel = UIImageView.init()
imgViewWings = UIImageView.init()
svHorizon = UIScrollView.init()
super.init(coder: aDecoder)
imgViewHorizon = UIImageView(frame: CGRect(x: 0, y: 0, width: imgBezel.size.width, height: imgHorizon.size.height))
imgViewHorizon.backgroundColor = UIColor.red
imgViewBezel = UIImageView(frame: CGRect(x: 0, y: 0, width: imgBezel.size.width, height: imgBezel.size.height))
imgViewBezel.contentMode = UIViewContentMode.center
imgViewBezel.clipsToBounds = true
imgViewBezel.image = imgBezel
imgViewWings = UIImageView(frame: CGRect(x: 0, y: 0, width: imgBezel.size.width, height: imgBezel.size.height))
imgViewWings.contentMode = UIViewContentMode.center
imgViewWings.clipsToBounds = true
imgViewWings.image = imgWings
svHorizon = UIScrollView(frame: CGRect(x: 0, y: 0, width: imgBezel.size.width, height: imgBezel.size.width))
svHorizon.contentSize = CGSize(width: imgBezel.size.width, height: imgHorizon.size.height)
svHorizon.contentMode = UIViewContentMode.scaleToFill
svHorizon.bounces = false
svHorizon.backgroundColor = UIColor.cyan
svHorizon.contentOffset = CGPoint(x: 0, y: 0)
svHorizon.addSubview(imgViewHorizon)
addSubview(svHorizon)
addSubview(imgViewBezel)
addSubview(imgViewWings)
From the discussion in the comments it turns out that the Adjust Scroll View Insets option was checked in the attributes inspector of the ViewController. Unchecking it resolved the problem. Have a look at the image below. You need to uncheck the highlighted option.
I have a UIView that holds a UILabel inside.
After applying affine transform on the UIView using:
myView.transform = CGAffineTransformMakeScale(4, 4);
My UILabel (which is a sub view to myView) grows as well.
Is there a way to prevent this?
i tried:
1) Using the CGAffineTransformIdentity flag on the label.
2) Adding a superview to myView and adding myView as superview's subview, and the label as a subview to the superview (and not myView).
Non of them seem to be working, the label keeps growing.
Any ideas?
You answered your own question with option 2. Not sure why it's not working since you did not supply any code. The playground code below shows it will work. Uncomment out the last line to transform the subview but not the label.
import UIKit
import XCPlayground
let superview = UIView(frame: CGRect(x: 10, y: 10, width: 200, height: 200))
XCPlaygroundPage.currentPage.liveView = superview
superview.backgroundColor = UIColor.redColor()
let view = UIView(frame: CGRect(x: 10, y: 10, width: 100, height: 100))
view.backgroundColor = UIColor.greenColor()
superview.addSubview(view)
let label = UILabel(frame: CGRect(x: 20, y: 10, width: 40, height: 40))
label.text = "Hello"
superview.addSubview(label)
//view.transform = CGAffineTransformMakeScale(2, 2)
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.