Questions about SwiftUI Layout - ios

I tried to place a Button inside a TextField
List {
Section(header: Text("ADD WORD")) {
HStack {
TextField("input word", text: $dictionaryVM.inputText)
.autocapitalization(.none)
.disableAutocorrection(true)
Button(action: {
showDetailView = true
}, label: {
Image(systemName:"plus")
})
.frame(width: 40, height: 40)
.background(Color.blue.opacity(0.1))
.cornerRadius(10)
.padding(.trailing, -10)
}
}
}
I draw a red border on the screenshot 1 image, when I click outside that red border, it'll trigger the button action
and When I click the button, like the screenshot 2 showed, the whole TextField turned gray, I don't know what I did is wrong, please help me out.

Related

SwiftUI: add Text below a Button

So I'm building my first App and trying to get some Text below the Button, but it should still be a part of the button. So thats what i got:
Button{
print("tapped")
} label: {
Image("Wand")
.resizable()
.frame(width: 100, height: 100)
}
.font(.title3)
.background(Color.gray)
.foregroundColor(.black)
.cornerRadius(20)
It looks like this:
But I want is this:
I've tried putting a VStack into the Label, but the Text stays in the gray button
I think it may help you
public struct VerticalLabelStyle: LabelStyle {
public let spacing: CGFloat
public init(spacing: CGFloat = 8) {
self.spacing = spacing
}
public func makeBody(configuration: Configuration) -> some View {
VStack(alignment: .center, spacing: spacing) {
configuration.icon
configuration.title
}
}
}
public struct ContentView: View {
#State private var text: String = ""
public var body: some View {
Label {
Text(text)
} icon: {
Image(systemName: "gamecontroller.fill")
.resizable()
.frame(width: 44, height: 44, alignment: .center)
}
.frame(width: 100, height: 100)
.labelStyle(VerticalLabelStyle())
.onTapGesture(perform: onTap)
}
func onTap() {
text = "tapped"
}
}
If you have some questions please ask
Your idea with a VStack is the correct way. You just have to keep in mind where to place your modifiers. In your case you placed them on the button level. Meaning they are applied to the entire label, which is the reason why your Text is inside the gray background. Just update also the place of your modifiers inside your VStack.
Here is are short example:
Button {
// Your button action
} label: {
VStack {
RoundedRectangle(cornerRadius: 25)
.frame(width: 100, height: 100)
.padding()
.background(Color.black) // new position of background modifier that is only applied on your Image (here a rectangle)
Text("Foo")
.font(.title3)
.foregroundColor(.black)
// These modifiers could stay on button level, but I moved them here to explicitly show where they applied
}
}
Keep in mind you can put any view inside the label of your button and that in this case the Text is part of the button and will trigger the action if a user taps on it. If you only want that the Image is the tap action wrap your button inside a VStack containing only the Image and a Text as the second part of the Stack like this:
VStack {
Button {
// Your button action
} label: {
VStack {
RoundedRectangle(cornerRadius: 25)
.frame(width: 100, height: 100)
.padding()
.background(Color.black)
}
}
Text("Foo")
.font(.title3)
.foregroundColor(.black)
}

SwiftUI Button is not grayed out when tapping

I am really trying to understand something.
I want to create a button with some text on it. The button have a frame and a color (color is same as background). When I tap that button I want the some effect to produce (some kind of discolouration to entire button). If the color is the same as the background just the text is coloured different during the tap. If I have a button with red background the effect is produced to the whole button. I have attached a picture on how things should look.
Before tap button should look like this:
When the user press the button (without release) the button looks like this:
In my case the red rectangle color is the same as the background color.But I want to have the same rectangle overlay. Instead of this I obtain the following.
Before tap:
During the tap:
In this case only the number has some sort of overlay. But the rectangle not.
Here is the code. What should I change to obtain the same feedback if the button is coloured the same as the background?
Button(action: {
some action
}){
Text("1")
.font(.title)
.foregroundColor(.blue)
.frame(width: 80, height: 48)
.background(Color.white)
.cornerRadius(4)
}
I cannot say that understood what exactly you want to achieve, but different visual feedback on button pressed can be done with help of button style. Within a style we have access to isPressed state, so can conditionally change presentation of button depending on that.
Here is some demo that should be helpful
Button(action: {
some action
}){
Text("1")
}
.buttonStyle(MyButtonStyle())
struct MyButtonStyle: ButtonStyle {
func makeBody(configuration: Self.Configuration) -> some View {
configuration.label
.font(.title)
.foregroundColor(configuration.isPressed ? .white : .blue) // << ex. !!
.frame(width: 80, height: 48)
.background(configuration.isPressed ? Color.clear : Color.white) // << ex. !!
.cornerRadius(4)
}
}
I did not understand the question very well, however what I can tell is that you have a button that has a background the same as your main background, and you want the effect of when the user press the button, why not adding some Shadow?
Button(action: {
}){
Text("1")
.font(.title)
.foregroundColor(.blue)
.frame(width: 80, height: 48)
.background(Color.white)
.cornerRadius(4)
.shadow(color: Color.black.opacity(0.5), radius: 2, x: 0, y: 0)
}
The result as you said:
I understood your question. I think button pressed effect adopts color according to background color so I have just hacked this trick. In my code I have just used one ZStack and give white background color like this :
struct ContentView: View {
var body: some View {
ZStack{
Color.red
ZStack{
Rectangle().fill(Color.white)
Button(action: {
// some action
}){
Text("1")
.font(.title)
.frame(width: 80, height: 48, alignment: .center)
.background(Color.red)
}//.buttonStyle(MyButtonStyle()) // Set style if you want custom color on press event and remove background color from text.
}.frame(width: 80, height: 48, alignment: .center).cornerRadius(4)
}
}
}
struct MyButtonStyle: ButtonStyle {
func makeBody(configuration: Self.Configuration) -> some View {
configuration.label
.background(configuration.isPressed ? Color.blue.opacity(0.5) : Color.red)
}
}
If you want to add your own color on the press then set button style and remove the background color from Text.
Hope this useful :)

SwiftUI: Dynamically move navigationBar items on List scroll

I have custom navigationBarItems attached to my NavigationBar (the SF Symbols chevron) and when I go to scroll through my items in the ScrollView, the NavigationBar will collapse to .inline and my items stay put.
Is it possible to anchor the chevron to the right of the .navigationBarTitle or dynamically move the items upon scroll?
Here's my current code:
NavigationView {
ScrollView {
eventView()
}
.navigationBarItems(leading:
Button(action: {
// action
}) {
Image(systemName: "chevron.down.circle")
.font(.system(size: 21, weight: .regular))
.offset(x: 169, y: 47)
.foregroundColor(Color(#colorLiteral(...))
}
)
.navigationBarTitle("Upcoming")
}
(I'm new to SwiftUI, I know it's not up to scratch)
Any help is greatly appreciated :)
i am not sure what you want, but the reason for this behavior is your offset.
Try this:
struct ContentView: View {
var body: some View {
NavigationView {
List {
ForEach(UIFont.familyNames, id: \.self) { name in
Text(name)
}
}.navigationBarTitle("Title")
.navigationBarItems(leading:
HStack {
Button(action: {
// action
}) {
HStack {
Text("Upcoming")
Image(systemName: "chevron.down.circle")
.font(.system(size: 21, weight: .regular))
// .offset(x: 169, y: 47)
.foregroundColor(Color.orange)
}
}
})
}
}
}

Expand SwiftUI button tap area over the button frame

I read a similar question about that issue. But that only expand the button size use .padding(). The red region in the snapshot is the tappable area.
The trailing padding to screen edge inserted by SwiftUI.framework can not be removing (I think). That causes any tap in the right edge of the screen can not trigger button action. How can I make the tappable area beyond the button size? So that user could tap that button more easier.
Thanks.
.navigationBarItems(trailing:
Button(action: {
self.context.isSheetDisplay = true
}, label: {
Image(systemName: "square.and.pencil")
.font(.system(size: 20))
})
.padding([.leading, .top, .bottom])
.background(Color.red)
)
Update:
e.g.
The Photos.app in simulator could trigger tap at the edge.
My solution to this issue for iOS is to add a nearly transparent background color ViewModifier to the button as part of a ButtonStyle:
import SwiftUI
struct ExampleBigPaddedButton: View {
var body: some View {
Button("Tap anywhere inside") {
print("Tapped")
}.buttonStyle(BigPaddedButtonStyle())
}
}
struct BigPaddedButtonStyle: ButtonStyle {
func makeBody(configuration: Configuration) -> some View {
return configuration
.label
.foregroundColor(configuration.isPressed ? .gray : .black)
.padding(EdgeInsets(top: 75, leading: 25, bottom: 75, trailing: 25))
.background(Color(red: 1, green: 1, blue: 1, opacity: 0.01))
.background(Rectangle().stroke(Color.gray))
}
}
struct ExampleBigPaddedButton_Previews: PreviewProvider {
static var previews: some View {
ExampleBigPaddedButton()
}
}
This produces a button having any size of padding you need that is tappable anywhere within its bounds.
The hit test area includes the background, but only when it isn’t clear. If your button is overlaying an area with a uniform background, you can make its background not clear, while still not noticeable to the user, by setting its background to the background color.
Button(…)
.background(.background)
So basically you need to give the label of the Button a padding and then give the button an offset with this padding. This is how I did it:
Button {
print("Tapped")
} label: {
Image(systemName: "xmark.circle.fill")
.foregroundColor(.grayColor.opacity(0.7))
.padding(EdgeInsets(top: 15, leading: 15, bottom: 15, trailing: 15))
}
.background(.red) // Shows the tappable area
.offset(x: 20, y: -20)

SwiftUI: How can I increase the area in which a button can be triggered?

How can I increase the area in which a button can be triggered without changing the UI?
This is my code
struct ContentView: View {
var body: some View {
NavigationView {
Text("Text")
.navigationBarTitle(Text("Title"))
.navigationBarItems(
leading:
Button(action: { print("add") }) {
Image(systemName: SFSymbolName.plus)
.font(.system(size: 18))
}
)
}
}
}
For this particular situation, You can add padding to all edges excluding the leading edge to the label of the button:
Button(action: { print("add") }) {
Text("+")
.padding(EdgeInsets(top: 20, leading: 0, bottom: 20, trailing: 50))
}
.background(Color.red) // This is just for seeing the hit area. You should get rid of it
Note that The maximum tappable area should be inside the rectangle above the title:
The Button is as big as it's content. In your case, it is as big as the image. Your button, or the tappable area, is small because the image is just small.
You can contain your image in a bigger frame, like this:
Button(action: { print("add") }) {
Image(systemName: SFSymbolName.plus)
.font(.system(size: 18))
.frame(width: 40, height: 40)
}

Resources