SwiftUI getting SF image inside button - swift

I have the following button and code, but cannot get the SF image to go on top of the button. I'd like it to be on the left but on top of the gradient - how do I achieve this please?
NavigationLink(destination: MyView(viewModel: FairRentViewModel(Amounts(), people: 2)))
{
Image(systemName: "person.crop.circle.badge.plus")
.font(.largeTitle)
Text("2")
.fontWeight(.bold)
.font(.title)
.padding()
.frame(minWidth: 0 maxWidth: 250, alignment: .center)
.background(gradient)
.foregroundColor(.white)
.padding(2)
.overlay(
RoundedRectangle(cornerRadius:20)
.stroke(gradient, lineWidth:15)
)
.padding(5)
}

Put it into overlay
Text("2")
.fontWeight(.bold)
.font(.title)
.padding()
.frame(minWidth: 0 maxWidth: 250, alignment: .center)
.background(gradient)
.foregroundColor(.white)
.padding(2)
.overlay(
RoundedRectangle(cornerRadius:20)
.stroke(gradient, lineWidth:15)
)
.overlay( // << here !!
Image(systemName: "person.crop.circle.badge.plus")
.font(.largeTitle)
//.padding(.leading) // might be needed
, alignment: .leading)
.padding(5)

You could try to put it inside an HStack.

Related

How to remove big blank space on my list pagination [SwiftUI]

I am new to SwiftUI and I trying to remove the blank space on my list pagination. Everytime when the list loaded the new page, a blank space is pop-up. how can I fix this?
You can see the problem by bellow attached image,
Screenshot
this is my list view
My List
List {
LazyVGrid(columns: setGridLayout(), spacing: 20) {
ForEach(viewModel.personPopularList, id: \.id) { person in
PeopleCardView(person: person)
.listRowBackground(Color.white)
.listRowSeparator(.hidden)
}
.id(UUID())
.frame(maxWidth: .infinity)
}
.listRowBackground(Color.white)
.listRowSeparator(.hidden)
}
.frame(maxWidth: .infinity)
.onAppear(perform: {
UITableView.appearance().contentInset.top = -20
UITableView.appearance().backgroundColor = UIColor.white
})
.listStyle(GroupedListStyle())
this is my cardview
My CardView
struct PeopleCardView: View {
#State var person: PersonPopularResult
var body: some View {
ZStack(alignment: .center) {
HStack(alignment: .center) {
WebImage(url: URL(string: Constant.POSTER_URL + (person.profilePath ?? "")))
.placeholder {
Image("placeholder")
}
.resizable()
.aspectRatio(contentMode: .fill)
.frame(width: 100, height: 100)
.clipShape(RoundedRectangle(cornerRadius: 10))
.overlay(RoundedRectangle(cornerRadius: 10)
.stroke(Color.mPurple, lineWidth: 3))
Spacer()
VStack(alignment: .leading) {
Text("\(person.name!)")
.fontWeight(.bold)
.lineLimit(1)
.font(.system(size: 21))
.font(.headline)
Text("Popolarity Rate: \(String(format: "%.3f", person.popularity!))")
.fontWeight(.bold)
.foregroundColor(.mPurple)
.lineLimit(1)
.font(.system(size: 14))
.padding(.top, -8)
Spacer()
}
.padding([.top, .leading], 10)
Spacer()
}
.frame(width: 300, height: 100, alignment: .center)
.padding()
.background(
RoundedRectangle(cornerRadius: 15, style: .continuous)
.fill(.white)
.overlay(RoundedRectangle(cornerRadius: 10)
.stroke(Color.mPurple, lineWidth: 3))
.shadow(radius: 7)
)
}
.frame(maxWidth: .infinity, maxHeight: .infinity)
}
}
thanks for anyone can help to my problem.

SwiftUI How to align the bottom of two text with different font size?

I’m trying to align the bottom of two Text but the larger one looks like thismy widget looks like this. I don’t know why there’s still some space below this Text view.
This is my code:
var body: some View {
GeometryReader{geometry in
ZStack(alignment: .center){
Image("background")
.resizable()
VStack(){
HStack(alignment: .bottom){
Text("3")
.lineLimit(1)
.font(.bold(.system(size: 100))())
.minimumScaleFactor(0.1)
.foregroundColor(Color.white)
.frame(width: nil, height: geometry.size.height/3, alignment: .bottom)
.lineLimit(1)
.shadow(radius: 2)
Text("cups")
.foregroundColor(Color.white)
.font(.system(size: 12))
.shadow(radius: 2)
}
Text("Next cup on")
.foregroundColor(Color.white)
.font(.system(size: 10))
.shadow(radius: 2)
.opacity(0.5)
Text("10 : 00")
.foregroundColor(Color.white)
.font(.system(size: 12))
.shadow(radius: 1)
.opacity(0.5)
}
}
}
}
What I want is the number 3’s bottom aligned to “cups”’s bottom.
Thanks!
Instead of .bottom, you can use .lastTextBaseline as your HStack alignment:
HStack(alignment: .lastTextBaseline) {
Text("Hello").font(.system(size: 40))
Text("World").font(.system(size: 10))
}

onTapGesture does only partially work on a ZStack

I have build a ZStack containing an image, an overlay and a systemImage. I want to open a sheet when the user taps on this image but it only works when the user clicks on a very specific point on the very bottom of the ZStack. Does anyone know how I can make this work? And also why this doesn't work?
My code:
NavigationView {
VStack {
VStack {
ZStack {
if let image = pfimage {
Image (uiImage: image)
.resizable()
.frame(width: 100, height: 100)
} else {
Image ("testimage")
.resizable()
.frame(width: 100, height: 100)
}
Image(systemName: "photo")
.resizable()
.frame(width: 30, height: 25)
.foregroundColor(Color.white)
}
.clipShape(Circle())
.contentShape(Circle())
.onTapGesture {
print("tap")
changepfsheet = true
}
Text("Displayname")
.padding(.top)
.foregroundColor(Color.white)
.font(.title3)
}
.frame(width: UIScreen.main.bounds.width, height: 225)
.background(Color.red)
HStack {
Image(systemName: "person.2.circle")
TextField("Enter newdisplayname", text: $newdisplayname)
}
.padding()
.background(Color.gray.opacity(0.1))
.cornerRadius(10)
.padding(.horizontal)
.padding(.top, 25)
Text("Change displayname")
Spacer()
HStack {
Spacer()
Text("Change password")
.foregroundColor(Color.white)
Spacer()
Image(systemName: "key")
.foregroundColor(Color.white)
}
.padding()
.background(Color.red)
.cornerRadius(15)
.padding(.horizontal)
.padding(.bottom, 5)
HStack {
Spacer()
Text("Logout")
Spacer()
}
.padding(.horizontal)
.padding(.bottom, 20)
}
.edgesIgnoringSafeArea(.top)
Spacer()
}
.navigationBarHidden(false)
.navigationBarBackButtonHidden(false)
You have interfering tap gestures. Instead, just have one tap gesture on the ZStack. Now you can tap anywhere on it:
ZStack {
Image(uiImage: image)
.resizable()
.frame(width: 100, height: 100)
Color.black.opacity(0.5)
.frame(width: 100, height: 100)
Image(systemName: "photo")
.resizable()
.frame(width: 30, height: 25)
.foregroundColor(.white)
}
.clipShape(Circle())
.contentShape(Circle())
.onTapGesture {
print("tap")
showsheet = true
}
I suspect the real issue is that you using a NavigationView, and putting content behind where the title would be. That means that you can't click through the view that the title is in, even if it's an empty title. You should either remove the NavigationView (as you aren't making use of it) or don't ignore safe area and use a NavigationView as you should do.
Removing edgesIgnoringSafeArea(.top) makes your code work, because the content will no longer be behind the navigation bar.

How to remove border outline when clicking on styled link label?

I have the following code for a styled link label:
extension Text {
func styledLinkLabel<V: View & ShapeStyle>(with gradient: V) -> some View {
self.fontWeight(.bold)
.font(.title)
.padding()
.frame(minWidth: 0, maxWidth: 250, alignment: .center)
.background(gradient)
.foregroundColor(.white)
.padding(2)
.overlay(
RoundedRectangle(cornerRadius:20)
.stroke(gradient, lineWidth:15)
)
.overlay(
Image(systemName: "person.crop.circle.badge.plus")
.font(.largeTitle)
.padding(.leading)
.foregroundColor(.white)
, alignment: .leading)
.padding(5)
}
}
This is used in the code as follows:
NavigationLink(destination: RentView(viewModel: RentViewModel(Amounts(), housemates: 1)))
{
Text("1")
.styledLinkLabel(with: gradient)
}
NavigationLink(destination: RentView(viewModel: RentViewModel(Amounts(), housemates: 2)))
{
Text("2")
.styledLinkLabel(with: gradient)
}
However when I click on this in the app (screenshot below of a click in progress), the outline underneath shows. Is there any way to get rid of this?
You need to use compositingGroup:
extension Text {
func styledLinkLabel<V: View & ShapeStyle>(with gradient: V) -> some View {
self.fontWeight(.bold)
.font(.title)
.padding()
.frame(minWidth: 0, maxWidth: 250, alignment: .center)
.background(gradient)
.foregroundColor(.white)
.padding(2)
.overlay(
RoundedRectangle(cornerRadius: 20)
.stroke(gradient, lineWidth: 15)
)
.overlay(
Image(systemName: "person.crop.circle.badge.plus")
.font(.largeTitle)
.padding(.leading)
.foregroundColor(.white),
alignment: .leading
)
.compositingGroup() // <- add here
.padding(5)
}
}
Alternatively, if you don't want to modify styledLinkLabel, you can use a custom ButtonStyle:
struct CustomButtonStyle: ButtonStyle {
func makeBody(configuration: Configuration) -> some View {
configuration.label
.compositingGroup()
.opacity(configuration.isPressed ? 0.5 : 1)
}
}
NavigationLink(destination: Text("Destination")) {
Text("Text")
.styledLinkLabel(with: gradient)
}
.buttonStyle(CustomButtonStyle())

Make Text inside VStack take the whole width of the VStack

I'm trying to make two Text that are inside a VStack to take the whole width of the parent (the VStack).
I'm completely out of ideas.
This is what I have:
var body: some View {
VStack(alignment: .center, spacing: 0) {
Image("image")
.resizable()
.scaledToFill()
.frame(height: 190)
.clipped()
VStack(alignment: .leading, spacing: 8) {
Text(title)
.font(.title)
.background(Color.red)
.fixedSize(horizontal: false, vertical: true)
Text(subtitle)
.font(.subheadline)
.background(Color.yellow)
.fixedSize(horizontal: false, vertical: true)
}
.frame(minWidth: 0, maxWidth: .infinity)
.background(Color.green)
.padding(.top, 24)
.padding(.horizontal, 24)
Button(buttonTitle) { print("Something") }
.frame(maxWidth: .infinity, minHeight: 56)
.background(Color.red)
.foregroundColor(.white)
.cornerRadius(56/2)
.padding(.top, 32)
.padding(.horizontal, 24)
.padding(.bottom, 20.0)
}.background(Color.blue)
.cornerRadius(38)
.frame(minWidth: 0, maxWidth: UIScreen.main.bounds.size.width - 48)
}
And this is how it looks:
I want the red and the yellow label to take the full width of the green VStack.
How can I achieve that?!
Remove the .fixedSize on both Text
Add .frame(minWidth: 0, maxWidth: .infinity) instead
In SwiftUI, it also matters the order of things, so you'll want to add the .background to after the .frame
Final result would be:
Text("title")
.font(.title)
.frame(minWidth: 0, maxWidth: .infinity)
.background(Color.red)
To instead make it left aligned:
HStack {
Text("title")
.font(.title)
Spacer(minLength: 0)
}
.background(Color.red)
Here is possible solution
VStack(alignment: .leading, spacing: 8) {
Text(title)
.font(.title)
.frame(maxWidth: .infinity) // << here
.background(Color.red)
.fixedSize(horizontal: false, vertical: true)
Text(subtitle)
.font(.subheadline)
.frame(maxWidth: .infinity) // << here
.background(Color.yellow)
.fixedSize(horizontal: false, vertical: true)
}
.frame(maxWidth: .infinity) // << here