How to stack both to top and bottom? [duplicate] - swiftui

This question already has an answer here:
Aligning SwiftUI text to the baseline and top of another text
(1 answer)
Closed 6 months ago.
This is my code:
HStack {
Text("AAA")
.font(.system(size: 60))
VStack {
Text("BBB")
Text("CCC")
}
}
This is how it looks like:
I want to align the top of 'BBB' to the top of 'AAA' and also align the bottom of 'CCC' to the bottom of 'AAA'.
I tried stack alignments, frame alignments, also tried working with custom alignments but it's all too messy and didn't work as expected.
Anyone has any suggestions?
Thank you

Just add Spacer and fixedsize
HStack {
Text("AAA")
.font(.system(size: 60))
VStack {
Text("BBB")
Spacer()
Text("CCC")
}
.fixedSize(horizontal: true, vertical: true)
}
Result

Related

Text with Text.DateStyle in SwiftUI View in Complication alignment

I want to create a complication rendered by a SwiftUI View that contains a label and a timer value.
I want the label to be on the complication background layer, and the timer value to be on the complication foreground layer so that they get tinted separately.
I would like this line of text, comprised of 2 parts, to be centered.
The trouble is, when using Text.DateStyle.timer, the Text behaves differently within a complication vs in a normal view.
In a normal view the Text frame behaves as any other text, only taking the space it needs.
When displayed in a complication, the Text frame expands to fill all the space it can, and the text within is left aligned.
This makes it so I cannot find a way to center the group of 2 Texts.
I tried a somewhat hacky approach with infinite spacers to try to steal the extra space from the Text that has the expanding frame. This works to center the content, but it causes the Text to truncate.
HStack {
Text("T:")
.foregroundColor(.accentColor)
Text(Date(), style: .timer)
.complicationForeground()
}
HStack {
Spacer()
.frame(maxWidth: .infinity)
HStack {
Text("T:")
.foregroundColor(.accentColor)
Text(Date(), style: .timer)
.complicationForeground()
}
Spacer()
.frame(maxWidth: .infinity)
}
A normal preview:
A preview of rendering within complication:
CLKComplicationTemplateGraphicExtraLargeCircularView(
ExtraLargeStack()
)
.previewContext(faceColor: .multicolor)
Edit to show full code
import ClockKit
import SwiftUI
struct ExtraLargeStack: View {
var body: some View {
VStack(alignment: .center) {
HStack {
Text("T:")
.foregroundColor(.accentColor)
Text(Date(), style: .timer)
.complicationForeground()
}
HStack {
Spacer()
.frame(maxWidth: .infinity)
HStack {
Text("T:")
.foregroundColor(.accentColor)
Text(Date(), style: .timer)
.complicationForeground()
}
Spacer()
.frame(maxWidth: .infinity)
}
}
.font(.system(size: 18, weight: .regular))
.lineLimit(1)
}
}
struct ExtraLargeStack_Previews: PreviewProvider {
static var previews: some View {
/// Preview normal view
// ExtraLargeStack()
/// Preview as Complication
CLKComplicationTemplateGraphicExtraLargeCircularView(
ExtraLargeStack()
)
.previewContext(faceColor: .multicolor)
}
}
Edit: Another partial solution
Based on suggestions from #Yrb, an overlay provides a partial solution that may be good enough for my use case.
The following does not fully center the 2 part line, but it is pretty close.
HStack {
// Use placeholder text to create a view with the appropriate size for _most_ timer values that I need to support
Text("L: 00:00 ").hidden()
}
.overlay(
// overlay the real content, which is constrained to the frame created by the hidden placeholder.
HStack(spacing: 5) {
Text("L:")
.foregroundColor(.accentColor)
Text(Date() - 3599, style: .timer)
.complicationForeground()
}
)
So, I figured out what the issue with aligning Text(Date(), style: .timer) is. The timer format from hours on down. The document give this as an example: 2:59 36:59:01. It appears that .timer reserves all of the possible space it needs and then is formatted on that possible space, not the space actually used. There does not appear to be any way to change this behavior, even if your goal is a 5 minute countdown timer.
I think you need to consider slight UI change. I did find that you can change the alignment of the displayed Text with a .timer by using .multilineTextAlignment(), but that is about all you can do. The following code demonstrates this:
struct ExtraLargeStack: View {
var body: some View {
// I removed (alignment: .center) as it is redundant. VStacks default to center
VStack {
// I put the negative spacing to tighten the T: with the timer
VStack(spacing: -6) {
Text("T:")
.foregroundColor(.accentColor)
Text(Date(), style: .timer)
// If you center with .multilineTextAlignment the timer
// will be centered
.multilineTextAlignment(.center)
.complicationForeground()
}
HStack {
HStack {
Text(Date(), style: .timer)
.multilineTextAlignment(.center)
.complicationForeground()
.overlay(
Text("T:")
.foregroundColor(.accentColor)
// This offset would need to be computed
.offset(x: -30, y: 0)
)
}
}
}
.font(.system(size: 18, weight: .regular))
}
}
I left the second timer as an HStack, but I put your Text("T") as an .overlay() with a .offset(). I don't particularly like this as it will be fragile if you attempt to adjust the offset for the additional time units, but if you have a limited range, it may work well enough. Also, if you use .monospaced on the timer text, the computation should be a linear amount.

ScrollView shows smudge at the bottom of the frame when scrolling the items

I am using the GridItems inside the ScrollView to show ten circles horizontally. It works fine but there are lines of smudge shown at the bottom border line of ScrollView container. I tried,
Addind padding to ScrollView.
Adding padding to HStack.
Any recommendations would be appreciated! I captured the screenshot scrolling all the way to the left and beyond holding the press.
Using iPhone 13 mini simulator,
here is the screenshot
struct HomeView: View {
var body: some View {
ScrollView.init([.vertical]) {
Section(header: Text("Today's Items").font(.system(size: 20.0, weight:.semibold, design: .rounded))) {
ScrollView(.horizontal, showsIndicators: false) {
HStack(spacing: 10) {
ForEach(0..<20) { _ in
Circle()
.fill(Color.random)
.frame(width: 100, height: 100)
}
}.padding(.vertical).background(.blue)
}.padding(.vertical).background(.orange)
}
...
}
}
}
UPDATE: With help from Yrb, I verified that I only see this in iPhone 12 and 13 mini simulators only (with 13 device being worse). But I don't own either model physically. If anybody can test it on the physical devices and share the observation I would appreciate it.
Add padding to HStack, not to ScrollView

how can I make onTapGesture works only if user tap on circle not inside all frame of Circle in SwiftUI? [duplicate]

This question already has an answer here:
SwiftUI: How to make entire shape recognize gestures when stroked?
(1 answer)
Closed 2 years ago.
I am using this down code for reading tap of user on Circle, the problem is here that it works on all part of frame 100X100 but I expect that it should work only on color filled Circle, how can I solve this issue?
struct ContentView: View {
var body: some View {
Circle()
.fill(Color.red)
.frame(width: 100, height: 100, alignment: .center)
.onTapGesture {
print("tap")
}
}
}
A nice little hack would be to add a background layer to the circle (it can't be 100% clear or it wouldn't render, so I made it opacity 0.0001 which looks clear) and then add another tapGesture onto that layer. The new gesture will take priority in the background area and we can just leave it without an action so nothing happens.
Circle()
.fill(Color.red)
.frame(width: 100, height: 100, alignment: .center)
.background(
Color.black.opacity(0.0001).onTapGesture { }
)
.onTapGesture {
print("tap")
}

Background for List Items on Apple Watch with SwiftUI [duplicate]

This question already has answers here:
How to style rows in SwiftUI List on WatchOS?
(6 answers)
Closed 3 years ago.
I'm working on building an Apple Watch screen in SwiftUI. The layout is working nicely, but there are aspects of the color styling that I can't seem to figure out. Here's my code:
struct Watch3ThingsMainUI: View {
var goals: [Goal]
var body: some View {
VStack {
Text("3things")
.foregroundColor(Color("3thingsBlue"))
List(goals) { goal in
HStack {
Text(goal.name)
Spacer()
Image(systemName: "gear")
}
.background(Color.blue)
}
.background(Color.green)
.foregroundColor(Color.red)
.accentColor(Color.yellow)
}
}
}
And here's a shot of how it renders:
You'll note that the HStack's blue background only covers a rectangular area, not the whole button that the List seems to create automatically. And oddly, while the List supports a background modifier, it appears to be ignored -- nothing is colored green.
What I'd love to be able to do is to determine the background for the entire button, but I can't figure a way to do so -- it remains stubbornly dark gray around the HStack no matter what shenanigans I try.
Try to replace your body with that can make the whole button is blue
var body: some View {
VStack {
Text("3things")
.foregroundColor(Color("3thingsBlue"))
List {
ForEach(self.goals) { goal in
HStack {
Text(goal.name)
Spacer()
Image(systemName: "gear")
}
.listRowBackground(Color.blue)
}
}
.foregroundColor(Color.red)
.accentColor(Color.yellow)
}
}

Shrinking Picker to fit content and no larger

I am developing a MacOS app using SwiftUI and would like a Picker to shrink to only show its label and content, and a Spacer to take up the rest of the view, but I'm not sure what the correct way to do this. The code looks something like this:
HStack{
Text("hello")
Text("more text")
Spacer()
Picker(selection: self.$stuff, label: Text("some stuff:")) {
ForEach(0 ..< self.getStuff().count) {
Text(self.getStuff()[$0])
}
}
}
and the Picker is expanded to take up as much room as possible. I would prefer that the picker take up the minimum amount of space and the Spacer to take up the remaining space.
Edit: photo:
You can use .scaledToFit to fit it to content as below
Picker(selection: self.$stuff, label: Text("some stuff:")) {
ForEach(0 ..< self.getStuff().count) {
Text(self.getStuff()[$0])
}
}
.scaledToFit()
// .frame(width: 160) // < alternate approach - give explicit desired width