paged scrollView with labels - ios

I'm trying to create a scrollView where u scroll between different labels. As an illustration i have this image:
I want to make the bottom scrollView i've tried creating a replicate, but in my case it is only adding "Book" to the scrollView and how can i make a smaller spacing between the labels. because in my code there are one label per self.view.frame.width
categoryArray = NSArray(objects: "Book", "Elektronik")
var textWidth = 0
for val in categoryArray!
{
var textLabel: UILabel = UILabel(frame: CGRectMake(0, CGFloat(textWidth), categoryScrollView!.frame.width, categoryScrollView!.frame.height))
textLabel.textAlignment = NSTextAlignment.Center
textLabel.text = val as NSString
categoryScrollView?.addSubview(textLabel)
textWidth = textWidth + Int(textLabel.frame.size.width)
if textWidth > Int(self.view.frame.width) {
categoryScrollView?.contentSize = CGSizeMake(CGFloat(textWidth), categoryScrollView!.frame.height);
}
}

I don't read swift very well, but it looks to me like the code is advancing the y position of the label frame on each iteration, rather than the x. In other words, change:
CGRectMake(0, CGFloat(textWidth), categoryScrollView!.frame.width, categoryScrollView!.frame.height)
to:
CGRectMake(CGFloat(textWidth), 0, categoryScrollView!.frame.width, categoryScrollView!.frame.height))

Related

Wrapping text on TitleLabel and DetailLabel - Material Card

I am using CosmicMind - Material Framework to create a Card. titleLabel and DetailLabel do not wrap to a new line.
My question is: What do I need to do to accomplish such task and is it supposed to be automatically adjusted by the framework?
This is what I have so far:
let card = Card()
var heartIcon = IconButton()
heartIcon = IconButton(image: Icon.favoriteBorder, tintColor: Color.red.base)
//Title Bar
let toolbar = Toolbar(rightViews: [heartIcon])
toolbar.title = cardData.cardTitleText
toolbar.titleLabel.textAlignment = .left
toolbar.titleLabel.numberOfLines = 0
toolbar.detail = "Company: " + cardData.cardTitleSubtitle
toolbar.detailLabel.font = RobotoFont.regular(with: 14)
toolbar.detailLabel.textColor = Color.grey.base
toolbar.detailLabel.textAlignment = .left
toolbar.detailLabel.numberOfLines = 0
And this is my output:
Update:
I managed to achieve what I wanted by increasing the size of the toolbar frame.
toolbar.frame = CGRect(x:0,y:0,width: view.frame.width,height: 100)
My goal was to at least show 2 lines of text.
Thanks!
I have no experience with the CosmicMind framework but usually, the label.numberOfLines property defines the maximum number of lines that the label text can have. You can set it to 2 instead of 0 and it should wrap.

Word Wrap Occurs Inconsistently in UILabel

I have a UILabel that is designed to expand in height when the width of the text's CGSize is greater than the width of the label. I accomplish that with this code:
func viewHeight(_ locationName: String) -> CGFloat {
let locationName = tappedLocation[0].name
var size = CGSize()
if let font = UIFont(name: ".SFUIText", size: 17.0) {
let fontAttributes = [NSAttributedStringKey.font: font]
size = (locationName as NSString).size(withAttributes: fontAttributes)
}
let normalCellHeight = horizontalStackViewHeightConstraint.constant
let extraLargeCellHeight = horizontalStackViewHeightConstraint.constant + 20.33
let textWidth = ceil(size.width)
let cellWidth = ceil(nameLabel.frame.width)
if textWidth > cellWidth {
return extraLargeCellHeight
} else {
return normalCellHeight
}
}
Lines = 0 and line break style = Word Wrap:
The label lives inside a vertical stackView, and is constrained to its top, leading and trailing edges and a stackView beneath it. The height of the label and the UIView properly expand in height when the CGSize width of the text is longer than the width of the label. All well and good.
However, the words do not wrap consistently. This behavior is intentional:
Bobby Mao's Chinese Kitchen & Bar:
XL cell. Width: 184.0,
Text width: 287.0
This behavior is not (why isn't "steak" on the prior line?):
Ruth's Chris Steak House:
XL cell. Width: 184.0,
Text width: 204.0
And neither is this (why didn't Gina wrap if it's over the label width parameter?):
Ristorante Mamma Gina:
XL cell. Width: 184.0,
Text width: 191.0
I have also set a temporary background color on my label to ensure that it does, in fact correspond to the intended width. The label in this example creates another line when the label's width is exceeded, but the text does not wrap:
I have read the other entries on Stack Overflow about word wrapping. I don't believe this is a duplicate. I do not have trouble creating two lines for my text. I don't have trouble with word wrapping occurring. I have trouble with how and when it is occurring.
I think the intent is clear... what am I missing?

StackView - center buttons with text below image

I am using this class for center text below icon for UIButton:
#IBDesignable
class TopIconButton: UIButton {
override func layoutSubviews() {
super.layoutSubviews()
let kTextTopPadding:CGFloat = 3.0;
var titleLabelFrame = self.titleLabel!.frame;
let labelSize = titleLabel!.sizeThatFits(CGSize(width: self.contentRect(forBounds: self.bounds).width, height: CGFloat.greatestFiniteMagnitude))
var imageFrame = self.imageView!.frame;
let fitBoxSize = CGSize(width: max(imageFrame.size.width, labelSize.width), height: labelSize.height + kTextTopPadding + imageFrame.size.height)
let fitBoxRect = self.bounds.insetBy(dx: (self.bounds.size.width - fitBoxSize.width)/2, dy: (self.bounds.size.height - fitBoxSize.height) / 2)
imageFrame.origin.y = fitBoxRect.origin.y
imageFrame.origin.x = fitBoxRect.midX - (imageFrame.size.width/2)
self.imageView!.frame = imageFrame;
// Adjust the label size to fit the text, and move it below the image
titleLabelFrame.size.width = labelSize.width
titleLabelFrame.size.height = labelSize.height
titleLabelFrame.origin.x = (self.frame.size.width / 2) - (labelSize.width / 2)
titleLabelFrame.origin.y = fitBoxRect.origin.y + imageFrame.size.height + kTextTopPadding
self.titleLabel!.frame = titleLabelFrame
self.titleLabel!.textAlignment = .center
}
}
It's working fine. My problem is when I start using in UIStackView. I am creating something similar to UITabBar so I have 5 buttons next to each other. I want to middle button be in exact center of screen but it's always several pixels to side. I check my constraints for UIStackView and it's okay. I remove all buttons exect middle one and then it's in exact middle. I tried different options for UIStackView (Fill, Centered, Fill Equally, etc.). Nothing helps. Do anyone has any idea? Each button has different icon (with different size) and texts are different too (free, premium, etc. - sometimes bigger then icon sometimes smaller), is this relevant?
Example of my StackView (red line shows where is middle):
The image size is going to be relevant here. Once you get all 5 images to be the same exact size you won't experience this issue anymore. Using 'fill equally' after doing that and you will get the result you want

UILabel on second line if the content doesn't fit in the view's first line

The best way to describe my situations is with images. What I have is a view which contains several UILabels and UIImage. The red box is a UILabel and if the content is too big it should go to the second line.
From the storyboard I have a working case when the content fits but the problem is that I am not sure how to handle the case when the last (red box) should go to the second line. I am using autolayout and cartography.
If someone can point me to the right direction I will be very grateful.
First calcululate width of text as per your current label's position.
If text width is more than current label's width then see my answer from below link:
Auto Layout how to move the view2 from right to the bottom?
Calculate width:
func widthForView1(_ text:String, font:UIFont, height:CGFloat) -> CGFloat
{
let label:UILabel = UILabel(frame: CGRect(x: 0, y: 0, width: your_label_width, height: your_lable_height))
label.numberOfLines = 0
label.lineBreakMode = NSLineBreakMode.byWordWrapping
label.text = text
label.font = font
label.sizeToFit()
return label.frame.width
}
You cannot do that with constraints only. To change the entire position of the element on the screen, you need to do it programmatically.
Use of tag View can solve this issue. TagListView is an external library.
When u add a view as subclass of taglistView, its height automatically increases accordingly.
ADD this to pod file : pod 'TagListView'
func addTags() {
let str1 = "Hi"
tagListView.addTag(str1)
let str2 = "Helloo"
tagListView.addTag(str2)
let str3 = "How Are u ? "
tagListView.addTag(str2)
tagListView.isUserInteractionEnabled = false
}

ios autolayout: dynamic width should push down 2nd label with SnapKit, proper way

I have 2 UILabels. lbl1's text can change, while lbl2's text is static.
They are both initially set on the same line. I have lbl1's numberOfLines set to 0 (infinity). I would like lbl2 to push down and align its top to lbl1's bottom when lbl1's width encroaches on lbl2's space. I have a current solution, but feel there's a pure autolayout way I'm missing. Any help would be great!
Both labels fit on 1 line:
lbl2 does not shift down in my attempts at pure autolayout:
Desired:
Current solution works, but feels un-ideal:
import XCPlayground
import SnapKit
import UIKit
let screen: UIView = UIView(frame: CGRectMake(0,0,320,568))
XCPlaygroundPage.currentPage.liveView = screen
XCPlaygroundPage.currentPage.needsIndefiniteExecution = true
let lbl1: UILabel = UILabel()
lbl1.text = "Short Text asnoetuha 1 1 1 1 "
lbl1.numberOfLines = 0
lbl1.backgroundColor = UIColor.whiteColor()
let lbl2: UILabel = UILabel()
lbl2.text = "Amount Text"
lbl2.backgroundColor = UIColor.yellowColor().colorWithAlphaComponent(0.5)
screen.addSubview(lbl1)
screen.addSubview(lbl2)
lbl1.snp_makeConstraints { (make: ConstraintMaker) in
make.top.leading.equalTo(screen)
make.width.lessThanOrEqualTo(screen.snp_width)
}
lbl2.snp_makeConstraints { (make: ConstraintMaker) in
// Below lines feel un-ideal
let lbl2X: CGFloat = screen.frame.width - lbl2.intrinsicContentSize().width
let lbl1RightX: CGFloat = screen.frame.origin.x + lbl1.intrinsicContentSize().width
let hasOverlap: Bool = lbl1RightX >= lbl2X
make.top.equalTo(hasOverlap ? lbl1.snp_bottom : lbl1.snp_top).priorityLow()
make.trailing.equalTo(screen)
}
I do believe you are not approaching this the right way. You should be able to create a function that listens for when lbl1 has its right anchor come into contact with lbl2's left anchor (very easy with SnapKit).
When this does happen, you call a function that remakes the constraints to how fit the image you provided. This is done with a call to snap_updateConstraints or snp_remakeConstraints. Then your constraint code should be straight forward as you would just pin the bottom anchor of lbl1 to the top anchor of lbl2 and then just make the other constraints until you get that desired effect.

Resources