I'm trying a lot of different ways, using padding(), spacer(), frame() modifiers but can't get what I want.
Essentially, I would like for the Stack to have a uniform Look w/ the same font sizes across all labels/values. As can see from the pic, the distance label/value ends up being smaller. (Where should I place the minScaleFactor() for it to effect the entire HStack?)
My Goal is
Have all the values/labels shown in it's entirety
Adjust the spacing between each HStack to be the same
Have MinScaleFactor() apply to all the values/labels so that they appear uniform.
Unfortunately, I'm just not getting it. :-(
var body: some View {
HStack (spacing: 15) {
VStack(alignment: .leading){
Text("Load")
Text("24533")
}
.padding(.leading, 10)
VStack(alignment: .leading) {
Text("Time")
Text("99h 44m 05s")
}
VStack(alignment: .leading) {
Text("Dist")
Text("999999.00km")
}
VStack(alignment: .leading) {
Text("D+")
Text("100000m")
}
VStack(alignment: .leading) {
Text("Calories")
Text("1000000033333")
}
VStack(alignment: .leading) {
Text("Joules")
Text("111111")
}
}
.frame(maxWidth: .infinity, alignment: .leading)
.minimumScaleFactor(0.2)
.lineLimit(1)
.font(.subheadline)
.border(Color.blue, width: 3)
}
With the suggestion to add a Spacer in between the 2 texts
Related
I've got a list of items that display a title, a subheading and their distance. The subheading and title can both change in size and may be smaller or large depending on data. The problem is I want the Text(distance) to remain in the same position regardless of the heading or subheading size.
var body: some View {
VStack {
Divider()
HStack {
Circle()
.fill(index < 7 ? .blue : .white)
.frame(width: 10, height: 10)
.padding(.leading, 4)
Circle()
.fill(getColor(index: index))
.scaledToFit()
.frame(height: 35)
.clipShape(Circle())
HStack {
VStack (alignment: .leading) {
Text(title)
.fontWeight(.medium)
.minimumScaleFactor(20)
.foregroundColor(.black)
Text(subheading)
.font(.subheadline)
.lineLimit(2)
.foregroundColor(.secondary)
.multilineTextAlignment(.leading)
}
}
Text("\(distance)")
.font(.subheadline)
.foregroundColor(.secondary)
Spacer()
Spacer()
}.frame(maxWidth: .infinity)
}
}
I've got some circles in there too that are based on the design, but they can be ignored. My issue is towards the bottom of the HStack. Trying to add padding etc. hasn't worked and causes strange renders of the view.
I would have added this as a comment, however, I am not sure what you mean by keeping the Text("\(distance)") the same position.
You may be able to use a ZSTack and then set the .offset of the Text field, but this would mean that the distance text may overlap the other text
I am creating a "News" SwiftUI widget and I need to display rows, each containing time and news header.
I am using a VStack containing HStack's for each item but I am encountering an issue with extra HStack spacing between the two Text's. I need the left Text taking all the width needed for its content and the right Text taking all the width that is left. Seems to work as expected for the longer date (second line) for not for the first one.
In AutoLayout world I would need to play around with Content hugging / Compression resistance priority to achieve what I need but not sure what to do in SwiftUI.
Here's my code for creating the view:
private func createView(from headers: [NewsHeaderEntry.NewsHeader], with first: Int) -> some View {
GeometryReader { metrics in
VStack(alignment: .leading, spacing: 16) {
title
ForEach(headers[0...first - 1]) { header in
HStack(spacing: 4) {
Text(header.newsAt)
.font(.system(size: 12))
.fontWeight(.light)
.background(.green)
.frame(alignment: .leading)
Text(header.title)
.font(.system(size: 14))
.fontWeight(.semibold)
.redacted(reason: header.isPlaceholder ? .placeholder : .init())
.background(.yellow)
.lineLimit(2)
.frame(maxWidth: .infinity, alignment: .trailing)
}
.background(.red)
.frame(maxWidth: .infinity, alignment: .center)
.padding(.horizontal, 8)
}
Spacer()
}
.frame(width: metrics.size.width)
.background(.blue)
}
}
I have also tried setting maxWidth: .infinity for the left Text as well but it resulted in equal widths for both Texts which is not what I need.
Update: Without .padding(.horizontal, 8) the spacing works as expected but I need the horizontal spacing from the design perspective.
[2:
What you're looking for is the default behavior of the stack. Your frame modifiers are the issue:
private func createView(from headers: [NewsHeaderEntry.NewsHeader], with first: Int) -> some View {
GeometryReader { metrics in
VStack(alignment: .leading, spacing: 16) {
title
ForEach(headers[0...first - 1]) { header in
HStack(spacing: 4) {
Text(header.newsAt)
.font(.system(size: 12))
.fontWeight(.light)
.background(.green)
Text(header.title)
.font(.system(size: 14))
.fontWeight(.semibold)
.redacted(reason: header.isPlaceholder ? .placeholder : .init())
.background(.yellow)
.lineLimit(2)
}
.background(.red)
.padding(.horizontal, 8)
}
Spacer()
}
.frame(width: metrics.size.width)
.background(.blue)
}
}
I'm trying to create a chat bubble like this:
Actual Bubble
Actual Bubble 2.0
This is what I have been able to achieve so far.
My attempt
My attempt
This is my code so far:
import SwiftUI
struct TestingView: View {
var body: some View {
ZStack {
/// header
VStack(alignment: .trailing) {
HStack {
HStack() {
Text("abcd")
}
HStack {
Text("~abcd")
}
}.padding([.trailing, .leading], 15)
.fixedSize(horizontal: false, vertical: true)
/// text
HStack {
Text("Hello Everyone, bdhjewbdwebdjewbfguywegfuwyefuyewvfyeuwfvwbcvuwe!")
}.padding([.leading, .trailing], 15)
/// timestamp
HStack(alignment: .center) {
Text("12:00 PM")
}.padding(.trailing,15)
}.background(Color.gray)
.padding(.leading, 15)
.frame(maxWidth: 250, alignment: .leading)
}
}
}
struct TestingView_Previews: PreviewProvider {
static var previews: some View {
TestingView()
}
}
The main goal is that I want the two labels on top to be distant relative to the size of the message content. I am not able to separate the two labels far apart i.e one should be on the leading edge of the bubble and the other one on the trailing edge.
Already tried spacer, it pushes them to the very edge, we need to apart them relative to the content size of the message as shown in attached images.
Here is a simplified code.
Regarding Spacer: To achieve your desired result you put both Text views inside of a HStack, and put a Spacer between them. So the Spacer pushes them apart to the leading and trailing edge.
Also I recommend to only use one padding on the surrounding stack.
VStack(alignment: .leading) {
// header
HStack {
Text("+123456")
.bold()
Spacer() // Spacer here!
Text("~abcd")
}
.foregroundStyle(.secondary)
// text
Text("Hello Everyone, bdhjewbdwebdjewbfguywegfuwyefuyewvfyeuwfvwbcvuwe!")
.padding(.vertical, 5)
// timestamp
Text("12:00 PM")
.frame(maxWidth: .infinity, alignment: .trailing)
}
.padding()
.background(Color.gray.opacity(0.5))
.cornerRadius(16)
.frame(maxWidth: 250, alignment: .leading)
}
We can put that header into overlay of main text, so it will be always aligned by size of related view, and then it is safe to add spacer, `cause it do not push label wider than main text.
Tested with Xcode 13.4 / iOS 15.5
var body: some View {
let padding: CGFloat = 15
ZStack {
/// header
VStack(alignment: .trailing) {
/// text
HStack {
//Text("Hello Everyone") // short test
Text("Hello Everyone, bdhjewbdwebdjewbfguywegfuwyefuyewvfyeuwfvwbcvuwe!") // long test
}
.padding(.top, padding * 2)
.overlay(
HStack { // << here !!
HStack() {
Text("abcd")
}
Spacer()
HStack {
Text("~abcd")
}
}
, alignment: .top)
.padding([.trailing, .leading], padding)
/// timestamp
HStack(alignment: .center) {
Text("12:00 PM")
}.padding(.trailing, padding)
}.background(Color.gray)
.padding(.leading, padding)
.frame(maxWidth: 250, alignment: .leading)
}
}
To separate two components with fairly space in the middle, use HStack{} with Spacer().
This is a sample approach for this case. Code is below the image:
VStack {
HStack {
Text("+92 301 8226")
.foregroundColor(.red)
Spacer()
Text("~Usman")
.foregroundColor(.gray)
}
.padding(.bottom, 5)
.padding(.horizontal, 5)
Text("Testing testingtesting testing testing testingtesting testing testing testing testing testing testing testing testing testing.")
.padding(.horizontal, 5)
HStack {
Spacer()
Text("2:57 AM")
.foregroundColor(.gray)
.font(.subheadline)
}
.padding(.trailing, 5)
}
.frame(width: 300, height: 160)
.background(.white)
.cornerRadius(15)
I am trying to make an adaptive CommentViewRow for a social app where the whole comment text can be displayed within the row.
So far I am achieving this but I have 3 issues:
1 When the comment-text is short it is being centred within the row even when I specify ".alignment: .leading" in the VStack.
2 When the comment-text uses more than one line there is a mysterious padding between the user's profile picture & the comment-text?? see image below.
3 I am not sure if my .frame modifier is the best way to achieve what I am doing, it seems mickey-mouse, I was reading about .frame(idealWith, idealHeight, etc..) and not sure if that would help.
Any idea on how I can fix this so that each CommentViewRow displays like your average social-media comment view??
Thank you!
struct CommentViewRow: View {
var comment: Comment
var body: some View {
HStack {
KFImage("profilePicture")
// COMMENT
VStack(alignment: .leading, spacing: 5) {
Text("**\(comment.username)** \(comment.comment)")
.font(.caption)
.frame(width: 310)
.fixedSize(horizontal: true, vertical: false)
Text(comment.createdAt.timeAgoDisplay())
.bold()
.font(.caption)
}
Spacer()
}.padding([.leading, .trailing], 10)
}
}
1st option: If you really need that view to be 310 wide
You can change .frame(width: 310) to .frame(width: 310, alignment: .leading)
2nd option: Let the view adjust itself based on content, you just need to specify the alignment (.leading in this case)
struct CommentViewRow: View {
var comment: Comment
var body: some View {
HStack {
KFImage("profilePicture")
VStack(alignment: .leading, spacing: 5) {
Text("**\(comment.username)** \(comment.comment)")
.font(.caption)
Text(comment.createdAt.timeAgoDisplay())
.font(.caption.bold())
}
.frame(maxWidth: .infinity, alignment: .leading)
}
.padding([.horizontal], 10)
}
}
yes, get rid of the frame:
struct ContentView: View {
var comment = "Thjfhg jhfgjhdfg jdfhgj dfhdfsjjdfgh djdshfg hjdfgjfdh ghjkf gdhjdfgh jkh fjg dfjkhgj dfglkhdfsg"
var body: some View {
HStack {
Image(systemName: "person.circle")
.font(.largeTitle)
VStack(alignment: .leading, spacing: 5) {
Text("\(comment)")
.font(.caption)
Text("3 minutes ago")
.bold()
.font(.caption)
}
Spacer()
}.padding([.leading, .trailing], 10)
}
}
I just learned swiftUI and I got little trouble. I want to make navigationBarTitle and title headline alignment like this:
Image 1: I want to make my view like this
I have tried to make like below but it does not work:
struct HeaderView: View {
var body: some View {
NavigationView {
VStack {
Image("kante_training_champions_league")
.resizable()
.scaledToFill()
.frame(width: 370, height: 150)
.cornerRadius(10.0)
Text("KANTE: NEW PLAYERS DON’T SEEM NEW")
.font(.title)
.fontWeight(.bold)
.multilineTextAlignment(.leading)
.frame(width: 370)
Spacer()
}
.navigationBarTitle("Chelsea FC")
}
}
}
From my code above, I got a view like this:
Image 2: I got a view like this from my code above
Could someone help me how to get a view like I want
Try leading alignment
var body: some View {
NavigationView {
VStack(alignment: .leading) { // << here !!
// ... no changes in image
Text("KANTE: NEW PLAYERS DON’T SEEM NEW")
.font(.title)
.fontWeight(.bold)
.padding(.leading) // << here !!
.multilineTextAlignment(.leading)
}
You should add alignment to StackView. You can change alignment to .leading, .trailing or .center. It is centered by default thats why you are having the label in center.
var body: some View {
NavigationView {
VStack(alignment: .leading) {
// Your Code
}
}
}
Remove .frame(width: 370) and use .frame(maxWidth: .infinity) so that the text takes the whole width of its parent.
VStack {
Image("kante_training_champions_league")
.resizable()
.scaledToFill()
.frame(width: 370, height: 150)
.cornerRadius(10.0)
Text("KANTE: NEW PLAYERS DON’T SEEM NEW")
.font(.title)
.fontWeight(.bold)
.multilineTextAlignment(.leading)
.frame(maxWidth: .infinity)
Spacer()
}