SwiftUI button image inset - swiftui

Is there same thing as ImageEdgeInsets for SwiftUI. For example I have button 60x60. And want to make inset for image inside.
VStack(alignment: .leading, spacing: 0.0){
Section{
Button(action: {
if self.accountViewModel.signInContext == .quote{
self.presentationMode.wrappedValue.dismiss()
}else{
self.viewController?.dismiss(animated: true)
}
}){
Image("Close Icon").renderingMode(.template).padding(.vertical, 20).padding(.horizontal, 20).foregroundColor(.white).scaledToFit()
}
.frame(width: 60, height: 60)
Rectangle().line().padding(.horizontal, -30)
}
}

Yes, .padding is for that purpose, just needed to make image resizable. I suppose you need the following
Image("Close Icon")
.renderingMode(.template)
.resizable()
.aspectRatio(contentMode: .fit)
.padding(.vertical, 20).padding(.horizontal, 20)

Related

How to prevent Text from spreading VStack?

This is what I have in code:
VStack(spacing: 2) {
Text("23:11:45") or "23:11"
.foregroundColor(Color(uiColor: mode.underlayBackgroundColor))
.font(.liberationMonoRegular(withSize: 46))
.multilineTextAlignment(.center)
.scaledToFill()
.minimumScaleFactor(0.5)
ProgressView(value: progress, total: 1)
.tint(Color(uiColor: mode.underlayBackgroundColor))
.foregroundColor(Color(uiColor: mode.underlayBackgroundColor)
.opacity(0.3))
}
.fixedSize()
.background(.blue)
VStack is wrapped into:
ScrollView {
}
.background(.red)
.frame(maxWidth: .infinity)
here is version for "23:11:45"
here is version for "23:11"
As you can see the Text with 23:11:45 String extends VStack although it should change the scale of the font. What to do to make it working? Maximum width is 100% - padding for both sides.
Your use of fixedSize propagates down and tells the Text not to scale down.
Compare:
Here's the code that generated that image:
VStack(spacing: 10) {
Text("with fixedSize:")
VStack {
Text("Hello world")
Text("Hello world")
.font(Font.custom("Palatino", fixedSize: 46))
}
.fixedSize()
.minimumScaleFactor(0.5)
.frame(width: 50)
.background(Color.black.opacity(0.2))
Spacer().frame(height: 40)
Text("without fixedSize:")
VStack {
Text("Hello world")
Text("Hello world")
.font(Font.custom("Palatino", fixedSize: 46))
}
.minimumScaleFactor(0.5)
.frame(width: 50)
.background(Color.black.opacity(0.2))
}
.lineLimit(1)
It doesn't matter if the fixedSize comes before or after the minimumScaleFactor. It does matter if it's before or after the frame.

HStack background color blending into safe area

I am trying to prevent the background of my HStack from going into my safearea.
There is a ZStack that is setting the background color. I am using green just to be more defined for now.
struct AccountView: View {
var body: some View {
ZStack{
Color(.green)
.ignoresSafeArea()
VStack(spacing: 32){
HStack {
Image(systemName: "person")
.resizable()
.scaledToFill()
.frame(width: 64, height: 64)
.clipShape(Circle())
.padding(.leading)
VStack(alignment: .leading, spacing: 4) {
Text("First Last")
.font(.system(size: 18))
Text("Available")
.foregroundColor(.gray)
.font(.system(size: 14))
}
Spacer()
}
.frame(height: 80)
.background(Color("ItemBG"))
Spacer()
}
}
}
}
We need to use shape as background instead of pure-colour, then it is not spread outside.
Here is simplified demo. Tested with Xcode 13.2 / iOS 15.2
var body: some View {
VStack {
HStack {
Text("Hello")
}
.frame(maxWidth: .infinity, maxHeight: 80)
.background(Rectangle().fill(.yellow)) // << here !!
Spacer()
}
.background(Color.green.ignoresSafeArea())
}
I was able to figure it out...
I had to give by HStack a padding of 1 on the top. Apparently with IOS 15 if it touches the safe area it bleeds.
HStack {
Image(systemName: "person")
.resizable()
.scaledToFill()
.frame(width: 64, height: 64)
.clipShape(Circle())
.padding(.leading)
VStack(alignment: .leading, spacing: 4) {
Text("First Last")
.font(.system(size: 18))
Text("Available")
.foregroundColor(.gray)
.font(.system(size: 14))
}
Spacer()
}
.frame(height: 80)
.background(Color("ItemBG"))
.padding(.top, 1)

How to set a Limit for the the views inside a HStack?

Good day, beginner SwiftUI & iOS developer here.
I'm not quite sure how else I could've worded this question, but I'll try my best to explain what I would like to achieve.
Right now, I have a VStack that contains a WebImage and Text view, and this VStack is nested inside a HStack. The views inside the VStack are inside a ForEach loop and are generated dynamically with the data I fetch.
When I display these on a screen, all of these views appear in a single line, as shown below.
However I would like for there to only be max two views per "line", not all four of them stacked into a single line. Is there a way to achieve this?
Here is the code:
HStack(spacing: 20) {
ForEach(attViewModel.students, id: \.self) { student in
VStack {
WebImage(url: URL(string: student.photo))
.resizable()
.aspectRatio(contentMode: .fill)
.frame(width: 40, height: 40)
.clipShape(Circle())
.overlay(Circle().stroke(Color("DarkGreen"), lineWidth: 3))
.compositingGroup()
Text("\(student.name)")
.bold()
.compositingGroup()
CustomRadioButton()
}
.padding()
.overlay(RoundedRectangle(cornerRadius: 10)
.stroke(Color.orange, lineWidth: 2))
.shadow(radius: 7)
}
}
.frame(maxWidth: .infinity)
Here a possible approach for you:
struct ContentView: View {
let arrayOfStudents: [String] = ["jessy", "joy", "joly", "jack"]
var body: some View {
GeometryReader { proxy in
ScrollView(.horizontal) {
HStack(spacing: .zero) {
ForEach(arrayOfStudents, id: \.self) { student in
VStack {
Image(systemName: "person")
.resizable()
.aspectRatio(contentMode: .fit)
.frame(width: 40, height: 40)
.padding()
.clipShape(Circle())
.overlay(Circle().stroke(Color.green, lineWidth: 3))
Text(student)
.bold()
Circle()
.strokeBorder(style: .init(lineWidth: 2))
.frame(width: 10, height: 10)
}
.compositingGroup()
.padding()
.overlay(RoundedRectangle(cornerRadius: 10).stroke(Color.orange, lineWidth: 2))
.shadow(radius: 7)
.padding()
.frame(width: proxy.size.width/2.0)
}
}
}
.position(x: proxy.size.width/2.0, y: proxy.size.height/2.0)
}
}
}

swiftui edgesIgnoreSafeArea only showing on canvas and not working on actual device

Im using .edgesIgnoringSafeArea(.top) to ignore the safe area on the top. this seems to work, and show the image going over the safe area on the top as expected on the canvas. But when I run this on a iPhone 11 plus simulator or iPhone x device (i also tested on other devices on the simulator) it doesn't seem to ignore the edges.
I have tried excluding:
.navigationBarTitle("")
.navigationBarBackButtonHidden(true)
But I need the above so I can use a custom back button.
var body: some View {
VStack (alignment: .leading ) {
Image("user1")
.resizable()
.frame(width: (UIScreen.main.bounds.width), height: ((UIScreen.main.bounds.height) / 2) + 50)
ScrollView {
HStack {
Text("\(userData.username), 30")
.fontWeight(.semibold)
.font(.system(.largeTitle, design: .rounded))
.padding([.leading,.top])
Spacer()
Image(systemName: "paperplane")
.aspectRatio(contentMode: .fill)
.frame(width: 65, height: 65)
.background(Color("message-background"))
.foregroundColor(.white)
.cornerRadius(25)
.font(.system(size: 25))
.padding(.top)
}.padding(.trailing)
HStack {
Text("Singer, London")
.fontWeight(.light)
.padding([.leading])
Spacer()
}
HStack {
Text("all the bio info will go there all the bio info will go thereall the bio info will go thereall the bio info will go there all the bio info will go there.")
.fontWeight(.light)
.padding([.leading])
.padding(.top)
.frame(width: (UIScreen.main.bounds.width - 20))
Spacer()
}.padding(.bottom,50)
}
}.edgesIgnoringSafeArea(.top)
.navigationBarTitle("")
.navigationBarBackButtonHidden(true)
.navigationBarItems(leading: Button(action: {
self.presentationMode.wrappedValue.dismiss()
}){
Image(systemName: "arrow.left")
.aspectRatio(contentMode: .fill)
.frame(width: 40, height: 40)
.background(Color("message-background"))
.foregroundColor(.white)
.cornerRadius(15)
.font(.system(size: 15))
.padding(.top,20)
})
}
Your code works for me on the simulator as expected. I just added the Text "This works" to demonstrate it:
So your problem must be somewhere outside the code which you presented in your question.

how to strech image on one side in swiftUI, like a .9 file in Android?

i have an image that i want to strech only it's height to fit different content, how do i do that in swiftUI? right now it looks like this
struct ContentView: View {
var body: some View {
VStack {
HStack {
VStack(alignment: .leading, spacing: 130) {
Text("Title")
.font(.headline)
.foregroundColor(.primary)
Text("text")
.font(.subheadline)
.foregroundColor(.secondary)
Text("padding")
}
.padding(.vertical)
Spacer()
Image("rightTag")
.resizable(capInsets: .init(top: 0, leading: 0, bottom: 0, trailing: 0), resizingMode: .stretch)
.aspectRatio(contentMode: .fit)
.frame(maxWidth: 20)
}
.frame(maxWidth: screen.width - 60)
.padding(.leading)
.background(.white)
.cornerRadius(20)
}
}
}
how can i stretch its height to fit this outer frame? ragular resizable and stuff can't get it done.
any helped would be wonderful! Thanks!
sry i didn't make myself clear earllier.
Here is possible approach. However as I see now you'd rather need to stretch not the entire original image, but only middle of it, so in real project it would be needed to make your image tri-part and apply below stretching approach only to middle (square) part.
Approach uses asynchronous state update, so works in Live Preview / Simulator / RealDevice. (Tested with Xcode 11.2 / iOS 13.2)
struct ContentView: View {
#State private var textHeigh: CGFloat = .zero
var body: some View {
VStack {
HStack(alignment: .top) {
VStack(alignment: .leading, spacing: 130) {
Text("Title")
.font(.headline)
.foregroundColor(.primary)
Text("text")
.font(.subheadline)
.foregroundColor(.secondary)
Text("padding")
}
.padding(.vertical)
.alignmentGuide(.top, computeValue: { d in
DispatchQueue.main.async {
self.textHeigh = d.height // !! detectable height of left side text
}
return d[.top]
})
Spacer()
Image("rightTag")
.resizable()
.frame(maxWidth: 20, maxHeight: max(60, textHeigh)) // 60 just for default
}
.frame(maxWidth: screen.width - 60)
.padding(.leading)
.background(Color.white)
}
}
}