I am creating a Widget in SwiftUI and I'm finding what I believe is a very silly issue.
I have an Image that I want to use as a background. I have set its aspect ratio as .fill but it doesn't seem to do it.
Here's the code:
var body: some View {
ZStack {
Image(affirmation.customImageName ?? "c_0")
.edgesIgnoringSafeArea(.all)
.aspectRatio(contentMode: .fill)
.frame(width: 300, height: 300, alignment: .center)
.background(Color.green)
HStack {
VStack {
Text(affirmation.title)
.font(.title)
.multilineTextAlignment(.leading)
}
Spacer()
}
.padding(.leading, 5)
.padding(.top, 5)
}
}
And how it looks:
Also, if I delete .frame(width: 300, height: 300, alignment: .center), the image won't use the whole area.
UPDATED:
Now the image resizes thanks to #staticVoidMan answer, adding resizable() did the trick. The issue now is that the Text seems to also resize and fill more than its space.
var body: some View {
ZStack {
Image(affirmation.customImageName ?? "c_0")
.resizable()
.aspectRatio(contentMode: .fill)
HStack {
Text(affirmation.title)
.font(.body)
.multilineTextAlignment(.leading)
.lineLimit(nil)
Spacer()
}
.padding(.leading, 5)
.padding(.top, 5)
}
Here's the image:
Thanks in advance
.resizable is an Image view modifier that allows it to occupy the maximum amount of space required.
ZStack by default can stretch indefinitely to fit all it's inner views and hence you need to define the frame via the .frame modifier so all the inner views stay within defined limits.
i.e.
ZStack {
//...
}
.frame(width: 300, height: 300)
Solution:
ZStack(alignment: .leading) {
Image("yourImageName")
.resizable()
.aspectRatio(contentMode: .fill)
.background(Color.green)
Text("Lorem ipsum dolor set amet")
.font(.title)
.padding(.leading, 5)
}
.frame(width: 300, height: 300)
ZStack(alignment: .leading) reduces the need of HStack:Text|Spacer to just the Text
.multilineTextAlignment(.leading) is default so not required
.lineLimit(nil) is default so not required
code
V/Hstack({}).frame(maxWidth: .infinity, maxHeight: .infinity).background(
Image("yourImageName")
.resizable()
.scaledToFill()
)
check your image resolution.I came into the image resolution problem. The image with resolution value 72x72 cannot fulfill the Widget background. Use the image with 144x144 resolution
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'm trying to align an image to the center of the screen in Swift/SwiftUI.
GeometryReader { geometry in
HStack {
Spacer()
Color.white
.ignoresSafeArea()
Image("1Pzpe")
.frame(width: geometry.size.width-3, height: geometry.size.width-3, alignment: .center)
Spacer()
}
enter image description here
Instead of being centered, my image goes a little more to the right. Any help would be greatly appreciated :)
Using this modifier will let you center images
extension Image {
func centerCropped() -> some View {
GeometryReader { geo in
self
.resizable()
.scaledToFill()
.frame(width: geo.size.width, height: geo.size.height)
.clipped()
}
}
}
You probably don't need GeometryReader for this case
You are putting a Color view aside the image so it would never be centered
you probably just need a ZStack if you want the image over the color
ZStack{
Color.white
.ignoresSafeArea()
Image(systemName: "iphone")
}
to center a image in the view you only need to put the image there also you don't need GeometryReader to fill the image just use .resizable() .scaledToFit() and .padding(3)
ZStack{
Color.white
.ignoresSafeArea()
Image(systemName: "square.fill")
.resizable()
.scaledToFit()
.padding(3)
.foregroundColor(.red)
}
I'm creating an iOS minesweeper game and want to have a bar at the top with three pieces of information:
The high score (next to a trophy symbol) [LEFT]
The current time (next to a timer symbol) [CENTER]
The number of bombs left (next to a bomb symbol) [RIGHT]
However, the elements are not evenly aligned as you can see in the picture at the bottom- I'm guessing the spacers are automatically the same size. So, because the text on the left side of the screen is wider than that on the right, the middle text is offset to the right.
How can I align these items so the center time/image is perfectly in the middle with the other objects on the left/right?
My code looks like:
struct GameView: View {
#EnvironmentObject var game: Game
#State var labelHeight = CGFloat.zero
var body: some View {
VStack(alignment: .center, spacing: 10) {
Text("MINESWEEPER")
.font(.system(size: 25, weight: .bold, design: .monospaced))
.kerning(3)
.foregroundColor(.red)
HStack(alignment: .center, spacing: 5) {
Image(systemName: "rosette")
.resizable()
.aspectRatio(contentMode: .fit)
.foregroundColor(.black)
Text(game.highScoreString)
.font(.system(size: 15, weight: .bold, design: .monospaced))
.foregroundColor(.black)
Spacer()
Image(systemName: "timer")
.resizable()
.aspectRatio(contentMode: .fit)
.foregroundColor(.black)
Text(game.timerString)
.font(.system(size: 15, weight: .bold, design: .monospaced))
.foregroundColor(.black)
Spacer()
Image("top_bomb")
.resizable()
.aspectRatio(contentMode: .fit)
Text(String(game.bombsRemaining))
.font(.system(size: 15, weight: .bold, design: .monospaced))
.foregroundColor(.black)
.overlay(GeometryReader(content: { geometry in
Color.clear
.onAppear(perform: {self.labelHeight = geometry.frame(in: .local).size.height})
}))
}
.frame(width: UIScreen.main.bounds.width * 0.9, height: labelHeight, alignment: .center)
BoardView()
}
}
}
Instead of aligning by spacers, move each part into separate view, say LeftHeader, CenterHeader, and RightHeader and use frame alignment, which gives exact separation by equal sizes, like
HStack {
LeftHeader()
.frame(maxWidth: .infinity, alignment: .leading)
CenterHeader()
.frame(maxWidth: .infinity, alignment: .center)
RightHeader()
.frame(maxWidth: .infinity, alignment: .trailing)
}
This can be achieved using a ZStack , HStack and Spacers.
ZStack{
HStack{
Text("Left")
Spacer()
}
HStack{
Text("Center")
}
HStack{
Spacer()
Text("Right")
}
}
Even if you remove left ( or right ) HStack, it won't affect the other components or the layout.
You can make it look bit nicer by adding paddings like this,
ZStack{
HStack{
Text("Left").padding([.leading])
Spacer()
}
HStack{
Text("Center")
}
HStack{
Spacer()
Text("Right").padding([.trailing])
}
}
I think you can create more one stack.
My solution like:
/**
* spacing is an example
* minWidth calculated by fontSize
*/
HStack(alignment: .center, spacing: 20){
HStack{ Image, Text }.frame(minWidth: 30)
HStack{ Image, Text }.frame(minWidth: 30)
HStack{ Image, Text }.frame(minWidth: 30)
}
Hope it useful for you.
I'm brand new to Swift and am making an iOS Minesweeper app. At the top of the screen I want to have an image of a bomb next to a Text() object displaying the number of bombs remaining.
I'd like to have the image and/or HStack resize to whatever the height of the adjacent text is without having to hard-code it's dimensions.
Can/how this be achieved?
The code so far looks like this:
HStack(alignment: .center, spacing: 10) {
Image("top_bomb")
.resizable()
.aspectRatio(contentMode: .fit)
Text(String(game.bombsRemaining))
.font(.system(size: 30, weight: .bold, design: .monospaced))
}
.frame(width: UIScreen.main.bounds.width, height: UIScreen.main.bounds.height * 0.1, alignment: .trailing)
And it looks like:
You just need to fix it by size, like
HStack(alignment: .center, spacing: 10) {
Image("top_bomb")
.resizable()
.aspectRatio(contentMode: .fit)
Text(String(game.bombsRemaining))
.font(.system(size: 30, weight: .bold, design: .monospaced))
}
.fixedSize() // << here !!
.frame(maxWidth: .infinity, alignment: .trailing) // << !!
Note: also pay attention that you don't need to hardcode frame to screen size
#State var labelHeight = CGFloat.zero
HStack(alignment: .center, spacing: 10) {
Image("top_bomb")
.resizable()
.aspectRatio(contentMode: .fit)
.frame(maxHeight: labelHeight)
Text(String(game.bombsRemaining))
.font(.system(size: 30, weight: .bold, design: .monospaced))
.overlay(
GeometryReader(content: { geometry in
Color.clear
.onAppear(perform: {
self.labelHeight = geometry.frame(in: .local).size.height
})
})
)
}
.frame(width: UIScreen.main.bounds.width, height: UIScreen.main.bounds.height * 0.2, alignment: .trailing)
I'm having a bit of trouble with this particular view. For some reason, it seems like depending on whether the Text(title) element is one line or two lines, I'm getting very odd behavior for the total height of the view. All the elements are dynamically populated so I can't just have a set height. I've ruled out that this is issue not dependent on the image that's loaded, but always occurs when the Text(title) element is one line. As you can see, when the element is only one line, it causes the image to have a padding above it and the 'See more' button to have a padding below it. The first image shows the margin issue (single line for title) and the second shows how the margins aren't there for multi-line title. Any help much appreciated!
https://i.stack.imgur.com/MB6Dt.jpg
https://i.stack.imgur.com/RDKOj.jpg
VStack(alignment: .leading) {
Image(systemName: "camera")
.data(url: URL(string: picture)!)
.resizable()
.scaledToFill()
.frame(width: UIScreen.main.bounds.width * 0.8)
.maxHeight(215)
.clipped()
Group {
HStack {
Text(title)
.bold()
.font(.system(size: 20, weight: .bold))
.padding(.vertical, 5)
Spacer()
}
HStack {
Text(subInformation)
.font(.system(size: 17, weight: .semibold))
.foregroundColor(Color.red)
.padding(.bottom, 5)
Spacer()
}
HStack {
Text(description)
.padding(.bottom, 2)
.foregroundColor(Color.gray)
Spacer()
}
}.padding(.horizontal)
DestinationAd()
.frame(width: UIScreen.main.bounds.width * 0.8, height: 50)
.padding(.bottom, 5)
Link(destination: URL(string: urlToOpen)!, label: {
HStack {
Spacer()
Text("See more")
.padding(.vertical, 5)
Spacer()
}.background(Color.blue)
.cornerRadius(10)
}).padding(.horizontal, 10)
.padding(.bottom, 10)
}.frame(width: UIScreen.main.bounds.width * 0.8)
.background(Color.white)
.cornerRadius(20)
I think that everything works as expected in your example. You are populating VStack with some child elements. VStack wraps it's content by default. In the first case (when the text only has one line) child views take less space that in the second example.
If you don't want to set frame for your VStack, maybe Spacer after the image and before the button could help.