Place label above each element in scrollview? - ios

I'm populating my scrollview in a for loop and trying to place a UILabel on top of each inserted element. However, the label won't center horizontally for some reason even though I'm setting its centerXAnchor to be equal to each element's centerXAnchor. Here's a picture with the label and element's borders shown:
As seen, the label I'm inserting isn't being centered horizontally with each element in the scrollview for some reason. Here's my for loop where I populate the scrollview:
for i in 0..<petsDict.count {
let imageView = UIImageView()
imageView.image = petsDict[i]
imageView.contentMode = .scaleAspectFit
let xPos = self.view.frame.width * CGFloat(i)
imageView.frame = CGRect(x: xPos - CGFloat(20*i), y: 0, width: self.mainScrollView.frame.width, height: self.mainScrollView.frame.height)
let label = UILabel(frame: CGRect(x: 0, y: -20, width: 200, height: 40))
label.text = "Joy"
label.textAlignment = .center
imageView.addSubview(label)
label.font = UIFont(name: "SFUIText-Regular", size: 20)!
label.sizeToFit()
mainScrollView.contentSize.width = mainScrollView.frame.width * CGFloat(i + 1)
mainScrollView.addSubview(imageView)
label.centerXAnchor.constraint(equalTo: imageView.centerXAnchor).isActive = true
label.bottomAnchor.constraint(equalTo: imageView.topAnchor).isActive = true
}
Can anybody help me understand why my x centering isn't working properly?

Try to remove label.sizeToFit(), this function resizes your labels.

for i in 0..<petsDict.count {
let imageView = UIImageView()
imageView.image = petsDict[i]
imageView.contentMode = .scaleAspectFit
let xPos = self.view.frame.width * CGFloat(i)
imageView.frame = CGRect(x: xPos - CGFloat(20*i), y: 0, width: self.mainScrollView.frame.width, height: self.mainScrollView.frame.height)
let label = UILabel(frame: CGRect(x: 0, y: -20, width: self.mainScrollView.frame.width, height: 20))
label.text = "Joy"
label.textAlignment = .center
imageView.addSubview(label)
label.font = UIFont(name: "SFUIText-Regular", size: 20)!
mainScrollView.contentSize.width = mainScrollView.frame.width * CGFloat(i + 1)
mainScrollView.addSubview(imageView)
label.centerXAnchor.constraint(equalTo: imageView.centerXAnchor).isActive = true
label.bottomAnchor.constraint(equalTo: imageView.topAnchor).isActive = true
}
Try this code

Give width to label same as your imageview width and remove sizeToFit and anchor. You just need to add then textAlignment which you have already added.

Related

Swift Add UIView with subviews to titleView

I'd like to customize my navigation bar and insert a UIView with two subviews into the title view of the navigation bar.
Unfortunately the subviews aren't displayed.
Do you have any idea why?
let titleContainer = UIView()
titleContainer.frame = CGRect(x: 0, y: 0, width: UIScreen.main.bounds.size.width, height: UIScreen.main.bounds.size.height)
let searchIcon = UIButton()
searchIcon.setImage(UIImage(named: "search_icon"), for: UIControlState.normal)
searchIcon.layer.frame = CGRect(x: 0, y: (UIScreen.main.bounds.size.height - 28) / 2, width: 28, height: 28)
titleContainer.addSubview(searchIcon)
let titleLabel = UILabel()
titleLabel.frame = CGRect(x: 28, y: UIScreen.main.bounds.size.height, width: UIScreen.main.bounds.size.width-28, height: UIScreen.main.bounds.size.height)
titleLabel.textColor = UIColor(red:255, green:255, blue:255, alpha:1.0)
titleContainer.addSubview(self.titleLabel)
self.navigationItem.titleView = titleContainer
problem and expected solution:
Why did you use height of all the element as UIScreen.main.bounds.size.height? Please try the below code.
P.S. I have changed the color of searchIcon as i didn't have the image and changed the color of text of label and added some text so that it is visible.
let titleContainer = UIView()
titleContainer.frame = CGRect(x: 0, y: 0, width: UIScreen.main.bounds.size.width, height: 45)
let searchIcon = UIButton()
//searchIcon.setImage(UIImage(named: "search_icon"), for: UIControlState.normal)
searchIcon.backgroundColor = UIColor.red
searchIcon.layer.frame = CGRect(x: 0, y: 8, width: 28, height: 28)
titleContainer.addSubview(searchIcon)
let titleLabel = UILabel()
titleLabel.frame = CGRect(x: 28, y: 8, width: UIScreen.main.bounds.size.width-28, height: 30)
titleLabel.textColor = UIColor.blue//(red:255, green:255, blue:255, alpha:1.0)
titleContainer.addSubview(titleLabel)
titleLabel.text = "Sample Text"
self.navigationItem.titleView = titleContainer
Here is the screenshot of the above code:
Please change the x,y accordingly as per your requirement.
Have you considered making your let bar = UINavigationBar() programmatically and then add it with: self.view.addSubview(bar)?
So you can push all the "UIBarItems" you want..?

Custom titleView changes location after push and pop new screen in stack

I'm trying to implement custom titleView for navigation controller with "title" and "description" labels. If I placed this titleView on first VC, it looks good. If I push second VC into navigation stack and pop it, location of the titleView is changed.
titleView's constraints:
titleLabel.translatesAutoresizingMaskIntoConstraints = false
descriptionLabel.translatesAutoresizingMaskIntoConstraints = false
titleLabel.widthAnchor.constraint(equalTo: widthAnchor).isActive = true
descriptionLabel.widthAnchor.constraint(equalTo: titleLabel.widthAnchor).isActive = true
titleLabel.topAnchor.constraint(equalTo: topAnchor).isActive = true
descriptionLabel.bottomAnchor.constraint(equalTo: bottomAnchor, constant: 2.0).isActive = true
In viewDidLoad of VC I use follow code to insert titleView:
navigationItem.titleView = BarTitleView()
navigationItem.titleView?.bounds = CGRect(x: 0, y: 0, width: view.bounds.width, height: 44)
navigationItem.titleView?.updateConstraints()
I tried to insert follow lines into viewWillAppear (second VC has different bar buttons and it can be root of problem), but nothing changes
navigationItem.titleView?.bounds = CGRect(x: 0, y: 0, width: view.bounds.width, height: 44)
navigationItem.titleView?.updateConstraints()
How can I fixed this issue?
I have created a Title and Subtitle in the Navigation bar without the need for Interface Builder and constraint modification.
My Function to create the title view looks as follows:
class func setTitle(title:String, subtitle:String) -> UIView {
let titleLabel = UILabel(frame: CGRect(x: 0, y: -8, width: 0, height: 0))
titleLabel.backgroundColor = UIColor.clear
titleLabel.textColor = UIColor.white
titleLabel.font = UIFont.boldSystemFont(ofSize: 17)
titleLabel.text = title
titleLabel.sizeToFit()
let subtitleLabel = UILabel(frame: CGRect(x: 0, y: 12, width: 0, height: 0))
subtitleLabel.backgroundColor = UIColor.clear
subtitleLabel.textColor = UIColor.white
subtitleLabel.font = UIFont.systemFont(ofSize: 12)
subtitleLabel.text = subtitle
subtitleLabel.sizeToFit()
// Fix incorrect width bug
if (subtitleLabel.frame.size.width > titleLabel.frame.size.width) {
var titleFrame = titleLabel.frame
titleFrame.size.width = subtitleLabel.frame.size.width
titleLabel.frame = titleFrame
titleLabel.textAlignment = .center
}
let titleView = UIView(frame: CGRect(x: 0, y: 0, width: titleLabel.frame.size.width, height: titleLabel.frame.size.height))
titleView.addSubview(titleLabel)
titleView.addSubview(subtitleLabel)
let widthDiff = subtitleLabel.frame.size.width - titleLabel.frame.size.width
if widthDiff < 0 {
let newX = widthDiff / 2
subtitleLabel.frame.origin.x = abs(newX)
} else {
let newX = widthDiff / 2
titleLabel.frame.origin.x = newX
}
return titleView
}
Then to use the title view in any view controller I just call this line:
self.navigationItem.titleView = Functions.Views.setTitle(title: "Title String", subtitle: "Subtitle String")

Auto-resized navigationBar title misplaced

I have a UINavigationBar with a title of variable length. To make sure the title fits without being truncated I've implemented the following code in my viewDidLoad():
let titleLabel = UILabel(frame: CGRect(x: 0, y: 0, width: 200, height: 40))
titleLabel.text = "\(petsName)'s Day"
titleLabel.font = UIFont.systemFont(ofSize: 30)
titleLabel.backgroundColor = UIColor.clear
titleLabel.textColor = UIColor.white
titleLabel.adjustsFontSizeToFitWidth = true
titleLabel.minimumScaleFactor = 0.5
self.navBar.topItem?.titleView = titleLabel
However, because I have a bar button item, the title is being moved over to the left:
Is there any way to implement the code above but keep the text center aligned within the navigation bar?
Please help me to resolve this issue
Try this.. may be worked
var view = UIView(frame: CGRect(x: 0, y: 0, width: 150, height: 40))
var label = UILabel(frame: CGRect(x: 0, y: 0, width: 150, height: 40))
label.text = "Joys Day"
label.textAlignment = .center
label.font = UIFont.systemFont(ofSize: 30)
view.addSubview(label)
navigationItem?.titleView = view
Change titleLabel width to device width and align it to center. Try this:
let deviceWidth = UIScreen.main.bounds.size.width
let titleLabel = UILabel(frame: CGRect(x: 0, y: 0, width: deviceWidth, height: 40))
titleLabel.text = "My Test Title"
titleLabel.font = UIFont.systemFont(ofSize: 20)
titleLabel.backgroundColor = UIColor.clear
titleLabel.textColor = UIColor.white
titleLabel.adjustsFontSizeToFitWidth = true
titleLabel.minimumScaleFactor = 0.5
titleLabel.textAlignment = .center
self.navigationItem.titleView = titleLabel
Output:

How to create custom uiview that button can be clicked inside uiview?

I tried to create clicked scrollview button like this (at bottom):
this is my code so far:
scView = UIScrollView(frame: CGRect(x: 0, y: view.frame.maxY-110, width: view.bounds.width, height: 110))
self.view.addSubview(scView)
scView.backgroundColor = UIColor.lightGray
scView.translatesAutoresizingMaskIntoConstraints = false
for i in 0 ... 10 {
let myNewView=UIView(frame: CGRect(x: xOffset, y: CGFloat(buttonPadding), width: 200, height: 100))
myNewView.backgroundColor=UIColor.white
myNewView.layer.cornerRadius=10
self.scView.addSubview(myNewView)
let label = UILabel(frame: CGRect(x: xOffset, y: CGFloat(buttonPadding)+5, width: 150, height: 10))
label.center = CGPoint(x: 160, y: 285)
label.textAlignment = .left
label.text = "I'am a title label"
label.textColor = .black
myNewView.addSubview(label)
let ditancelabel = UILabel(frame: CGRect(x: xOffset, y: CGFloat(buttonPadding)+5, width: 50, height: 10))
ditancelabel.center = CGPoint(x: 160, y: 285)
ditancelabel.textAlignment = .right
ditancelabel.text = "0.04 km"
ditancelabel.textColor = .red
myNewView.addSubview(ditancelabel)
let textView = UITextView(frame: CGRect(x: xOffset, y: CGFloat(buttonPadding)+15, width: 200.0, height: 40.0))
self.automaticallyAdjustsScrollViewInsets = false
textView.center = self.view.center
textView.textAlignment = NSTextAlignment.justified
textView.textColor = UIColor.lightGray
textView.backgroundColor = UIColor.clear
myNewView.addSubview(textView)
let button = UIButton()
button.tag = i
button.backgroundColor = UIColor.white
button.setTitle("\(i)", for: .normal)
button.setTitleColor(.black, for: .normal)
button.backgroundColor = UIColor.clear
button.addTarget(self, action:#selector(handleRegister(sender:)), for: .touchUpInside)
button.frame = CGRect(x: xOffset, y: CGFloat(buttonPadding), width: 200, height: 100)
xOffset = xOffset + CGFloat(buttonPadding) + button.frame.size.width
myNewView.addSubview(button)
}
scView.contentSize = CGSize(width: xOffset, height: scView.frame.height)
but code result like this:
The first button can be clicked, but the other cannot be clicked. And 2 UILabels and 1 UITextView did not appear.
the handleRegister method is to get sender tag and print it as log to know the button can be clicked or not.
How to repair the code so it can be like the custom UIView in the above image?
I need to transfer label and textview text by button click to another viewcontroller which handle by seque in handleRegister.
1) You can't see labels and other control because of your container view size is (200, 100)
let myNewView=UIView(frame: CGRect(x: xOffset, y: CGFloat(buttonPadding), width: 200, height: 100))
and you set center of controls.
label.center = CGPoint(x: 160, y: 285)
ditancelabel.center = CGPoint(x: 160, y: 285)
This center point is not visible within container view. That's why you can't see labels within view. Just comment these line to set center of labels and you can see those perfectly.
2) I need to transfer label and textview text by button click to another viewcontroller which handle by seque in handleRegister.
I hope you have a array in which you stored data to display in your custom view, Just find that object from array based on button tag, and pass that object to another control.
3) The first button can be clicked, but the other cannot be clicked.
Again problem is same like for labels. You had set frame of button like this
button.frame = CGRect(x: xOffset, y: CGFloat(buttonPadding), width: 200, height: 100)
and increase xOffset by this line to create another view
xOffset = xOffset + CGFloat(buttonPadding) + button.frame.size.width
xOffset increased each time with the size of button. So if you print xOffset value it actually print like (assuming initial value of xOffset = 10, padding = 0)
for i in 0 ... 10 {
print(xOffset)
..... your other code
}
Output: will be like
10, 210, 410, 610...... Because of this your button is out of bound from container view and because of that you can't click on that.
I have updated your code, check below
scView = UIScrollView(frame: CGRect(x: 0, y: view.frame.maxY-110, width: view.bounds.width, height: 110))
self.view.addSubview(scView)
scView.backgroundColor = UIColor.lightGray
scView.translatesAutoresizingMaskIntoConstraints = false
for i in 0 ... 10 {
let myNewView=UIView(frame: CGRect(x: xOffset, y: CGFloat(buttonPadding), width: 200, height: 100))
myNewView.backgroundColor=UIColor.white
myNewView.layer.cornerRadius=10
self.scView.addSubview(myNewView)
let subVwOffset = 5
let label = UILabel(frame: CGRect(x: subVwOffset, y: CGFloat(buttonPadding)+5, width: 150, height: 10))
label.textAlignment = .left
label.text = "I'am a title label"
label.textColor = .black
myNewView.addSubview(label)
let ditancelabel = UILabel(frame: CGRect(x: subVwOffset, y: CGFloat(buttonPadding)+5, width: 50, height: 10))
ditancelabel.textAlignment = .right
ditancelabel.text = "0.04 km"
ditancelabel.textColor = .red
myNewView.addSubview(ditancelabel)
let textView = UITextView(frame: CGRect(x: subVwOffset, y: CGFloat(buttonPadding)+15, width: 200.0, height: 40.0))
self.automaticallyAdjustsScrollViewInsets = false
textView.center = self.view.center
textView.textAlignment = NSTextAlignment.justified
textView.textColor = UIColor.lightGray
textView.backgroundColor = UIColor.clear
myNewView.addSubview(textView)
let button = UIButton()
button.tag = i
button.backgroundColor = UIColor.white
button.setTitle("\(i)", for: .normal)
button.setTitleColor(.black, for: .normal)
button.backgroundColor = UIColor.clear
button.addTarget(self, action:#selector(handleRegister(sender:)), for: .touchUpInside)
button.frame = CGRect(x: subVwOffset, y: CGFloat(buttonPadding), width: 200, height: 100)
xOffset = xOffset + CGFloat(buttonPadding) + button.frame.size.width
myNewView.addSubview(button)
}
scView.contentSize = CGSize(width: xOffset, height: scView.frame.height)
Let me know if you find any other difficulty.

How to get correct width for view with content by systemLayoutSizeFittingSize when height gived

I want to calculate view size with autolayout, but it can not get right value. Here is my code
// build views
let view = UIView(frame: CGRect(x: 0, y: 0, width: 100, height: 100))
let posterView = UIImageView(frame: CGRect(x: 0, y: 0, width: 50, height: 100))
let titleLabel = UILabel(frame: CGRect(x: 0, y: 0, width: 100, height: 20))
titleLabel.text = "Title "
titleLabel.font = UIFont.systemFontOfSize(16) // label height = 19.5
view.addSubview(posterView)
view.addSubview(titleLabel)
posterView.snp_makeConstraints { (make) in
make.top.left.right.equalTo(view).offset(0)
make.width.equalTo(posterView.snp_height).multipliedBy(16.0 / 9.0)
}
titleLabel.snp_makeConstraints { (make) in
make.top.equalTo(posterView.snp_bottom).offset(0)
make.left.equalTo(view).offset(0).priority(750)
make.right.equalTo(view).offset(0).priority(750)
make.bottom.equalTo(view.snp_bottom).offset(0)
}
// calculate
view.translatesAutoresizingMaskIntoConstraints = false
let heightConstraint = NSLayoutConstraint(item: view, height: 90+19.5)
view.addConstraint(heightConstraint)
let fittingSize = view.systemLayoutSizeFittingSize(UILayoutFittingCompressedSize)
// the fittingSize is (40,109.5), not expect value (160, 109.5)
Please don't tell me how to calculate dynamic height for UITableViewCell. This is a opposite problem from height to width.
Thanks

Resources