As you can see from the image below the L (Lorem) and the p (previewing) are cutoff, any idea why some of the text inside the Text gets cut off?
struct ContentView: View {
var body: some View {
ZStack {
Image("placeholder-image")
.resizable()
.scaledToFill()
.ignoresSafeArea()
VStack {
Text("Lorem ipsum is placeholder text commonly used in the graphic, print, and publishing industries for previewing layouts and visual mockups..")
.foregroundColor(Color.systemGray)
.cornerRadius(15)
Button("Tap Me") {
// some action
}.buttonStyle(.borderedProminent)
}
.padding()
.background(.thinMaterial)
.cornerRadius(15)
}
}
}
The cornerRadius adds clipping, so remove it after text (anyway it is not needed there by logic of your code even if it would behave differently)
VStack {
Text("Lorem ipsum is placeholder text commonly used in the graphic, print, and publishing industries for previewing layouts and visual mockups..")
.foregroundColor(Color.systemGray)
//.cornerRadius(15) // << this !!
you can use as below for text:
.fixedSize(horizontal: false, vertical: true)
Related
I'm Having a text view with custom font and color. One of them is a button label. I put them into an HStack for horizontal alignment. However, the text breaks oddly when the text size gets bigger.
The below image is what im trying to create.
This is my current code, I've tried .allowsTightening(true) or .fixedSize(horizontal: true, vertical: false) but nothing works out
HStack(spacing: Constants.horizontalGap4){
Image(systemName: isChecked ? "checkmark.square.fill" : "square")
.foregroundColor(isChecked ? Color(UIColor.systemBlue) : Color.secondary)
.onTapGesture {
self.isChecked.toggle()
}
ActionTinyTextView(text: "I agree with the ", color: Color.gray)
.allowsTightening(true)
Button {
} label: {
ActionTinyTextView(text: CRContent.termAndConditionText)
.allowsTightening(true)
}
}
It can be used markdown, like
Text("I agree with [Terms & Use](link1) and [Privacy Policy](link2)")
.foregroundColor(.gray) // << for main text
.tint(.green) // << your color for active text
For such action links handling see my other answer https://stackoverflow.com/a/72798487/12299030
You can achieve this with the + operator for Text view.
As long as you will be using only the modifiers which have a Text return type, this will solve your problem. Sample code and image are below:
struct SampleView: View {
var body: some View {
ZStack(alignment: .leading) {
Color.black.edgesIgnoringSafeArea(.all)
VStack { //from here
Text("I agree with the ")
.foregroundColor(.white) + //this
Text("Terms & Use")
.foregroundColor(.teal)
.fontWeight(.bold) + //this
Text(" and ")
.foregroundColor(.white) + //this
Text("Privacy Policy.")
.foregroundColor(.teal)
.fontWeight(.bold)
}
.frame(width: 180)
}
}
}
NavigationView{
List{
VStack{
Text("EdwardCullen")
.padding(.vertical, -20)
AsyncImage(url)) { image in
image
.center()
} placeholder: {
ProgressView()
}
}
Text("Test")
}
.navigationTitle("EdwardCullen's Profile")
.navigationBarTitleDisplayMode(.inline)
}
Picture of what I want
I included a picture of what I want kind of, so basically "Status" on the left side of the Text and "Online" on the total other side. I also would preferably want "Online" to be green, so I think I need to use two different Text views, but how exactly would I do this in a list? Is there any good way to do this?
The way I did what is in the picture is just adding many spaces to Text like this, but obviously that is not very smart and also not exactly what I want.
Text("First Second")
Use HStack{} plus Spacer(). (Code is below the image)
var body: some View {
VStack {
HStack {
Text("First")
Spacer() //this one
Text("Second")
}
.padding()
.background(.blue)
.cornerRadius(15)
}
}
Use a spacer "Spacer()". This is an adaptive view that expands as much as it can.
NavigationView{
List{
VStack{
Text("EdwardCullen")
.padding(.vertical, -20)
AsyncImage(url)) { image in
image
.center()
} placeholder: {
ProgressView()
}
}
# new code here
HStack {
Text("Status")
Spacer()
Text("Online")
.foregroundColor(.green)
}
}
.navigationTitle("EdwardCullen's Profile")
.navigationBarTitleDisplayMode(.inline)
}
Just Use a HStack and put a spacer between two text .
sample code :
HStack{
Text("Status")
Spacer()
Text("Online")
}.cornerRadius(8)
you may use this anywhere you want .
Sample Output:
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.
In iOS Settings > Music > Apple Music and Privacy, there is a modal that I've mostly successfully duplicated except in two ways (a brief demo of Apple's modal is here). First, I don't know how to duplicate the bullet points seen in the beginning of the text. Second, I don't know how to hide the nav bar title until scrolling past the logo and modal title. That behavior matches the .inline nav title style and suggests the logo and title are actually part of the nav bar title.
The answer here was really helpful in actually getting the nav bar to show up. I also tried using ToolbarItem and .principal from here to add an image to the toolbar, but that doesn't give the desired result. I tried adding padding because the image was squished into the nav bar but that didn't work. Lastly, I tried a VStack in the .principal placement to add the image and text below it, but that didn't work either.
Here's the code in the parent view:
struct ModalNavBar: View {
#State private var showApplePolicy = false
var body: some View {
Button() {
showApplePolicy = true
} label: {
Text("Apple Music and Privacy")
}.sheet(isPresented: $showApplePolicy, content: {
NavigationView {
TermsAndPrivacyView()
.navigationTitle("Apple Music & Privacy")
.navigationBarTitleDisplayMode(.inline)
.toolbar {
ToolbarItem(placement: .principal) {
VStack {
Image("privacy")
.resizable()
.frame(width: 80, height: 65)
.padding()
.padding(.vertical, 20)
Text("Apple Music & Privacy")
}
}
ToolbarItem(placement: .navigationBarTrailing) {
Button(action: {
self.showApplePolicy = false
}) {
Text("Done").bold()
}
}
}
}
})
}
}
and the modal view:
struct TermsAndPrivacyView: View {
var body: some View {
ScrollView {
VStack(alignment: .center, spacing: 20) {
Group {
Image("privacy")
.resizable()
.aspectRatio(contentMode: .fit)
.frame(width: 80, height: 65)
.padding()
.padding(.top, 20)
.padding(.bottom, 5)
Text("Apple Music & Privacy")
.font(.title).bold().padding(.top, -20)
VStack(alignment: .center) {
Text("Apple Music is designed to protect your information and enable you to choose what you share.")
}
}
}.padding(.horizontal, 30)
}
}
}
Any help with the nav bar would be appreciated.
Firstly, This question should have been broken up into multiple questions. Normally that would have gotten the question closed, but here people only downvoted this. Make sure to read the links that I put in my first comment for future questions. Your questions are:
How do I put place two texts or images next to each other and align them?
How do I hide and show the .navigationTitle when a certain view is fully hidden behind the navigation bar?
In answer to the first question, I used a mix of .firstTextBaseline alignment and an .alignmentGuide to put the text bullet in the correct spot. While I hardcoded these values, try to avoid it if things can change. In this case, the view is unchanging so it is acceptable.
As to the hiding and showing the title, I used a PreferenceKey to read the location of the bottom of the Text("Apple Music & Privacy") view in the ScrollView. When that hits zero, this view is behind the navigation bar. Then I simply set a #State variable to toggle when this happens, and use that to set the title.
You will also notice I pulled everything that was in your ModalNavBar out. In a case like this, everything should be contained in the view that the sheet is displaying. It works better, and encapsulates things so you could just drop a different view into the sheet and it still works fine.
Lastly, I have omitted a bunch of text views to keep the answer brief. Feel free to add them back in. When you see the ellipsis, that simply means omitted code.
struct ModalNavBar: View {
#State private var showApplePolicy = false
var body: some View {
Button() {
showApplePolicy = true
} label: {
Text("Apple Music & Privacy")
}.sheet(isPresented: $showApplePolicy, content: {
NavigationView {
TermsAndPrivacyView()
.toolbar {
ToolbarItem(placement: .navigationBarTrailing) {
Button(action: {
self.showApplePolicy = false
}) {
Text("Done").bold()
}
}
}
}
})
}
}
struct TermsAndPrivacyView: View {
#State var showTitle = false
var body: some View {
ScrollView {
VStack(alignment: .center, spacing: 20) {
Image(systemName: "person.3.fill")
.font(.system(size: 80))
Text("Apple Music & Privacy")
.font(.title).bold()
// The PreferenceKey reads where it is within the ScrollView. "Scroll" is a coordinate space name
// set on the ScrollView. .maxY is simply the value of the Y dimension at the bottom of that view
// within the coordinates of the ScrollView. When that hits zero, it is behind the navigation bar.
.background(
GeometryReader {
Color.clear.preference(key: TextLocationPrefKey.self,
value: $0.frame(in: .named("Scroll")).maxY)
}
)
Text("Apple Music is designed to protect your information and enable you to choose what you share.")
// Put the text bullet and text together in an HStack with a .firstTextBaseline alignement
HStack(alignment: .firstTextBaseline) {
Text(Image(systemName: "circle.fill"))
.font(.system(size: 4))
.opacity(0.5)
// The .alignmentGuide let's you tweak the actual alignment. In this case I moved it up by 2.
.alignmentGuide(.firstTextBaseline) { context in
context.height + 2
}
Text("Lorem ipsum dolor sit amet, praesent necessitatibus ei has, te sit hinc munere, ea vix fugit novum noluisse. Nulla graeci delicatissimi qui cu, nec doming iudicabit ex, indoctum partiendo an has. In qui sensibus dissentiunt, inani iudico accusamus ei eum. Suas vidit primis vel ad, meis ignota postea at pri, ei usu consul evertitur. Per vocent sadipscing et. Has debitis deterruisset ei, democritum scribentur te duo, purto accommodare id ius.")
}
...
}.padding(.horizontal, 30)
}
// This is a simple ternary condition. If showTitle is true the title is set to "Apple Music & Privacy" else ""
.navigationTitle(showTitle ? "Apple Music & Privacy" : "")
.navigationBarTitleDisplayMode(.inline)
// This is where the PreferenceKey value is compared to zero to set the showTitle variable.
.onPreferenceChange(TextLocationPrefKey.self) { textLocation in
withAnimation(.easeIn(duration: 0.15)) {
showTitle = !(textLocation > 0)
}
}
// This is where you select and name the view for the coordinate space
.coordinateSpace(name: "Scroll")
}
}
// This is how the preference key is set up.
fileprivate struct TextLocationPrefKey: PreferenceKey {
typealias Value = CGFloat
static var defaultValue = CGFloat.zero
static func reduce(value: inout Value, nextValue: () -> Value) {
// This adds or subtracts based on the change in the value as you scroll the view towards the navigation
// bar, nextValue() is negative, reducing value towards zero.
value += nextValue()
}
}
Sorry for the newbie question, but I'm stuck on why Navigationlink produces no links at all. Xcode compiles, but there's a blank for where the links to the new views are. This particular view is View 3 from ContentView, so the structure is ContentView -> View 2 -> View 3 (trying to link to View 4).
struct MidnightView: View {
var hourItem: HoursItems
#State var showPreferencesView = false
#State var chosenVersion: Int = 0
#State var isPsalmsExpanded: Bool = false
#State var showLXX: Bool = false
var body: some View {
ScrollView (.vertical) {
VStack (alignment: .center) {
Group {
Text (hourItem.hourDescription)
.font(.headline)
Text ("Introduction to the \(hourItem.hourName)")
.font(.headline)
.bold()
.frame(maxWidth: .infinity, alignment: .center)
ForEach (tenthenou, id: \.self) {
Text ("\($0)")
Text ("\(doxasi)")
.italic()
}
}
.padding()
NavigationView {
List {
ForEach (midnightHours, id:\.id) {watch in
NavigationLink ("The \(watch.watchName)", destination: MidnightWatchView (midnightItem: watch, chosenVersion: self.chosenVersion, isPsalmsExpanded: self.isPsalmsExpanded, showLXX: self.showLXX))
}
}
}
Group {
Text ("Absolution of the \(hourItem.hourName)")
.font(.headline)
Text (absolutionTexts[(hourItem.hourName)] ?? " ")
Divider()
Text ("Conclusion of Every Hour")
.font(.headline)
Text (hourConclusion)
Divider()
Text (ourFather)
}
.padding()
}
}
.navigationBarTitle ("The Midnight Hour", displayMode: .automatic)
.navigationBarItems (trailing: Button (action: {self.showPreferencesView.toggle()}) {Text (psalmVersions[chosenVersion])}
.sheet(isPresented: $showPreferencesView) {PreferencesView(showPreferencesView: self.$showPreferencesView, chosenVersion: self.$chosenVersion, isPsalmsExpanded: self.$isPsalmsExpanded, showLXX: self.$showLXX)})
}
}
The cause of the NavigationLink not appearing is probably due to the fact that you're including a List within a ScrollView. Because List is a scrolling component as well, the sizing gets messed up and the List ends up with a height of 0. Remove the List { and corresponding } and your links should appear.
There are a number of other potential issues in your code (as I alluded to in my comment), including a NavigationView in the middle of a ScrollView. I'd remove that as well, as you probably have a NavigationView higher up in your view hierarchy already.