How to change size of field in TextField? - swiftui

I need to change the size (actually just the height) of the TextField. Using .padding() increases just the area around the TextField, but not the field itself. I've tried some possible solutions:
Change the font size: This approach works, but I don't want to have a TextField with a too large text in itself.
Using custom modifier doesn't work. I get the message Inheritance from non-protocol type 'TextFieldStyle'. Seems to not working in Swift 5 anymore?
My current solution is:
#State private var searchText: String = ""
var body: some View {
HStack{
Image(systemName: "magnifyingglass")
.font(.system(size: 20, weight: .bold))
ZStack(alignment: .leading){
if searchText.isEmpty { Text("search") }
TextField("", text: $searchText,
onEditingChanged: { focused in
if focused {
// do something...
}
},
onCommit: {
// do something...
})
.keyboardType(.alphabet)
.disableAutocorrection(true)
.frame(height: 50)
}
.textFieldStyle(PlainTextFieldStyle())
}
.frame(height: 30)
.frame(maxWidth: .infinity)
.foregroundColor(.white)
.accentColor(.white)
.padding()
.background(
Color("Color-2")
.cornerRadius(20)
.shadow(color: Color.black.opacity(0.3), radius: 5, x: 5, y: 5)
)
.contentShape(Rectangle())
}}
Only the red area is "clickable"

import SwiftUI
struct ContentView: View {
#State var stringOfText: String = ""
var body: some View {
TextField("", text: $stringOfText)
.font(Font.system(size: 50))
.background(Color.yellow)
.foregroundColor(Color.clear)
.cornerRadius(10)
.overlay(Text(stringOfText), alignment: .leading)
.padding()
.shadow(radius: 10)
}
}

Related

Keep VStack in center of the screen in SwiftUI

I'm new on SwiftUI and I don't know how to manage my views.
I have this code:
import SwiftUI
struct ContentView: View {
#State private var email: String = ""
#State private var passord: String = ""
var body: some View {
ZStack {
Image("corner")
.resizable()
.scaledToFill()
VStack {
VStack { //VStack1
TextField("Email", text: $email)
.frame(width: 300, height: 40)
.textFieldStyle(.roundedBorder)
.bold(true)
SecureField("Password", text: $passord)
.frame(width: 300, height: 40)
.textFieldStyle(.roundedBorder)
.bold(true)
Button {
//Do something
} label: {
Text("Forgot your password ?")
.underline()
.foregroundColor(.white)
}
}
VStack { // VStack2
Text("Not registered ?")
.font(.title2)
.foregroundColor(.white)
Button("Sign up") {}
.frame(width: 200, height: 37)
.foregroundColor(.white)
.background(Color(.orange))
.cornerRadius(20)
}
}
}
}
}
I want to place the VStack2 in the bottom of the screen and keep the VStack1 on the center of the screen.
How I can do that. I've try to search but I don't find the solution on StackOverflow.
I tried to play with Spacer() and padding() but I have not a good result.
Screen
A simple way to do this would be to add VStack1 to the ZStack which will place it in the centre of the screen. Then add wrap VStack2 in another VStack with a Spacer to push it to the bottom of the screen, e.g.
ZStack {
Image("corner")
VStack { //VStack1
// etc
}
VStack {
Spacer()
VStack { // VStack2
// etc
}
}
}
Simple put
HStack {
Spacer()
VStack {
Text("Centered")
}
Spacer()
}
import SwiftUI
struct ContentView: View {
#State private var email: String = ""
#State private var passord: String = ""
var body: some View {
VStack {
Spacer()
middleView()
Spacer()
bottomView()
.paddind(.bottom, 12)
}
.ignoresSafeArea()
.background {
Image("corner")
.resizable()
.scaledToFill()
}
}
func middleView() -> some View {
VStack(spacing: 20) {
TextField("Email", text: $email)
.frame(width: 300, height: 40)
.textFieldStyle(.roundedBorder)
.bold(true)
SecureField("Password", text: $passord)
.frame(width: 300, height: 40)
.textFieldStyle(.roundedBorder)
.bold(true)
Button {
//Do something
} label: {
Text("Forgot your password ?")
.underline()
.foregroundColor(.white)
}
}
}
func bottomView() -> some View() {
VStack {
Text("Not registered ?")
.font(.title2)
.foregroundColor(.white)
Button("Sign up") {}
.frame(width: 200, height: 37)
.foregroundColor(.white)
.background(Color(.orange))
.cornerRadius(20)
}
}
}

swiftUI list selection lead to textfield

As I have constructed a list of country codes and I am able to tap on the list items. Here i want to show the tapped or selected country code inside my textfield which means, when I click on a country code it should show inside the textfield. I am new to swiftUI, it would be great if someone helped me to get this.
enter image description here
state variables given as:
#State private var text = ""
#State private var selection: String!
My textfield code goes here:
HStack {
TextField("Country code", text: $text).padding(.leading)
.frame(width: 385, height: 50)
.border(.gray)
.padding(.leading, 25)
.overlay(
Button(action: {
withAnimation {
showCodes.toggle()
}
}, label: {
Image(systemName: "chevron.down")
.foregroundColor(.gray)
.padding(.leading, 320)
.position(x: 215, y: 25)
})
)
.position(x: 195, y: 40)
.padding(.top, -570)
}
List code goes here :
if showCodes == true {
List (selection: $selection) {
ForEach(datas.users, id: \.dial_code) { user in
HStack{
Text(user.name)
.font(.callout)
.foregroundColor(Color.black)
Spacer()
Text(user.dial_code)
.font(.callout)
.foregroundColor(Color.blue)
}
}
}
.listRowInsets(EdgeInsets())
.frame(maxWidth: 400, maxHeight: .infinity, alignment: .leading)
.padding(.top, -585)
}
You can have it like:
ForEach(datas.users, id: \.dial_code) { user in
HStack {
Text(user.name)
.font(.callout)
.foregroundColor(Color.black)
Spacer()
Text(user.dial_code)
.font(.callout)
.foregroundColor(Color.blue)
}
.onTapGesture { text = user.dial_code }
}
I also suggest extracting the HStack along with it's content in a separate func like:
private func getCountryCodeCell(for user: User) -> some View {
HStack {
Text(user.name)
.font(.callout)
.foregroundColor(Color.black)
Spacer()
Text(user.dial_code)
.font(.callout)
.foregroundColor(Color.blue)
}
}

How to give shadow with cornerRadius to a Button inside ScrollView and HStack in SwiftUI

I'm trying to give a shadow to Button using following code.
VStack{
HStack(){
Text("Menu")
.font(.title3)
.fontWeight(.bold)
Spacer()
Image(systemName: "magnifyingglass")
}.padding(.horizontal)
ScrollView(.horizontal){
HStack(){
ForEach(menuOptions, id: \.self){m in
MenuButtons(title:"\(m)")
}
}.frame(height:50)
}
.padding(.horizontal)
.background(.clear)
}.background(.clear)
And my MenuButton struct:
struct MenuButtons: View {
var title: String
var body: some View {
Button(action:{}, label: {
Text(title)
.font(.system(size: 17))
.frame(width:120, height:35)
.cornerRadius(10)
.foregroundColor(Color("secondaryColor"))
.background(Rectangle().fill(.white).shadow(color:.gray,radius:2).cornerRadius(10))
})
}
}
this would be my output:
Expected output:
In above image you can see that shadow is not proper.
How can I achieve the following?
#Dans code works. But its not so much the .tint as the .background of the button, and the order of applying modifiers.
You used a rectangle, then applied shadow, then used cornerRadius. In this order the cornerRadius "cuts off" the shadow applied before.
If you use RoundedRectangle instead (as Dan did) it works fine.
.background(
RoundedRectangle(cornerRadius: 12)
.fill(.white)
.shadow(color:.gray,radius: 2, y: 1)
)
Or you just change the ordering of the modifiers. First cornerRadius, then shadow.
.background(
Rectangle()
.fill(.white)
.cornerRadius(12)
.shadow(color:.gray,radius: 2, y: 1)
)
I believe adding a .buttonStyle(.borderedProminent) and .tint(.clear) may help achieve your desired look. Something like this;
struct ButtonView: View {
let menuOptions = ["Entradas", "Bebidas", "Plato Fuerte", "Postre"]
var body: some View {
VStack{
HStack(){
Text("Menu")
.font(.title3)
.fontWeight(.bold)
Spacer()
Image(systemName: "magnifyingglass")
}.padding(.horizontal)
ScrollView(.horizontal) {
HStack {
ForEach(menuOptions, id: \.self){ m in
MenuButtons(title:"\(m)")
}
}.frame(height:50)
}
.padding(.horizontal)
//.background(.clear)
}//.background(.clear)
}
}
struct MenuButtons: View {
var title: String
var body: some View {
Button(action:{ }, label: {
Text(title)
.font(.system(size: 17))
.frame(width: 120, height: 35)
.cornerRadius(10)
.foregroundColor(.black)
.background(
RoundedRectangle(cornerRadius: 10, style: .circular)
.fill(.white)
.shadow(color: .gray, radius: 2, x: -1, y: 2)
)
})
.buttonStyle(.borderedProminent)
.tint(.clear)
}
}
Result

Widget UI preview in SwiftUI

How can I insert the preview of a widget into the app?
Can anyone give me some advice?
I did a naive version of a Widget configuration preview using SwiftUI. I used a RoundedRectangle with a small 3D rotation and applied a shadow:
I contained the code inside a custom View called WidgetView:
struct WidgetView<Content: View>: View {
let content: Content
init(#ViewBuilder content: () -> Content) {
self.content = content()
}
var body: some View {
ZStack {
RoundedRectangle(cornerRadius: 24, style: .continuous)
.fill(Color(.systemBackground))
content
}
.frame(width: 162, height: 162)
.rotation3DEffect(.degrees(10), axis: (x: 1, y: 1, z: 0))
.shadow(color: Color(UIColor.systemGray), radius: 20, x: -5, y: 10)
}
}
The usage is quite simple. Just add the content view you want inside the Widget view:
WidgetView {
HealthActiveEnergyView(entry: ActiveEnergyEntry.mock())
}
.preferredColorScheme(.light)
.previewLayout(layout)
struct HealthActiveEnergyView: View {
var entry: ActiveEnergyEntry
var body: some View {
VStack(alignment: .leading) {
HStack {
Text(NSLocalizedString("Active", comment: ""))
.foregroundColor(entry.configuration.accentColor)
Spacer()
Image(systemName: "flame.fill")
.font(.system(.title))
.foregroundColor(entry.configuration.accentColor)
}
Text(dateFormatter.string(from: entry.date))
.foregroundColor(Color(.systemGray))
.font(.caption)
HStack(alignment: .lastTextBaseline) {
Text("\(entry.totalOfKilocalories)")
.font(.system(.largeTitle, design: .rounded))
.bold()
.foregroundColor(Color(.label))
Text("kcal")
.foregroundColor(Color(.systemGray))
Spacer()
}
Spacer()
Text(NSLocalizedString("AVG 7 DAYS", comment: ""))
.foregroundColor(Color(.systemGray))
.font(.caption)
HStack(alignment: .lastTextBaseline) {
Text("\(entry.avgOfKilocalories)")
.font(.system(.callout, design: .rounded))
.bold()
.foregroundColor(Color(.label))
Text("kcal")
.foregroundColor(Color(.systemGray))
.font(.caption)
Spacer()
}
}
.padding()
}
}

Edit mode in a List

Updated with working code.
I've implemented a List in my app with Edit mode, so I can move the rows by dragging a row handle. That works fine, but doesn't look too good, since the move icon is placed under the content of the row (see screen dump). And that is because Edit mode makes room for a delete button.
Is there a way to hide elements in the row when you're in Edit mode?
The code for the View is:
import SwiftUI
import Combine
import DateHelper
struct EggList: View {
#EnvironmentObject var egg : Egg
#State private var eggs = Egg.all()
#State private var editMode: EditMode = .inactive
var body: some View {
NavigationView {
List {
Image("Pantanal")
.resizable()
.frame(height: 250)
ForEach(eggs) { eggItem in
NavigationLink(destination: EggDayList(eggItem: eggItem)) {
CellRow(eggItem: eggItem)
.environment(\.editMode, self.$editMode)
}
}
.onDelete(perform: delete)
.onMove(perform: move)
}
.navigationBarTitle(Text("Eggs"), displayMode: .inline)
.navigationBarItems(leading: EditButton(), trailing: NavigationLink(destination: Settings()){
Text("Add Egg")})
.environment(\.editMode, self.$editMode)
}
}
func delete(at offsets: IndexSet) {
eggs.remove(atOffsets: offsets)
}
func move(from source: IndexSet, to destination: Int) {
eggs.move(fromOffsets: source, toOffset: destination)
}
}
struct CellRow: View {
let eggItem: Egg
#Environment(\.editMode) private var editMode
var body: some View {
HStack(spacing: 8) {
Image(eggItem.species)
.resizable()
.frame(width: 48, height: 48)
.clipShape(Circle())
VStack(alignment: .leading, spacing: 0) {
Text("\(eggItem.species)")
.font(.footnote)
.lineLimit(1)
.padding(.top, -4)
Text("id-"+String(eggItem.eggNumber))
.font(.footnote)
.lineLimit(1)
.padding(0)
Text("\(eggItem.layDate.string(with: "dd-MM-yy"))")
.font(.footnote)
.lineLimit(1)
.padding(.bottom, -7)
}.frame(width: 90, alignment: .leading)
VStack(spacing: 2) {
Text("days")
.font(.footnote)
.padding(.top, 12)
Image(systemName: "\(eggItem.diffToday)"+".circle")
.resizable()
.frame(width: 40, height: 30)
.padding(.bottom, 12)
.foregroundColor(.red)
}.frame(width: 50, alignment: .leading)
VStack(spacing: 0) {
Text("prediction")
.font(.footnote)
.padding(.top, 14)
Text(formatVar1(getal: eggItem.calcWeights[eggItem.daysToPip-1].prediction)+"%")
.font(.title)
.padding(.bottom, 12)
}.frame(width: 80, alignment: .leading)
if !(self.editMode?.wrappedValue.isEditing ?? false) {
VStack(alignment: .leading, spacing: 0) {
Text("INC")
.font(.footnote)
.lineLimit(1)
.padding(.top, -4)
Text("37.3")
.font(.footnote)
.lineLimit(1)
.padding(0)
Text("30%")
.font(.footnote)
.lineLimit(1)
.padding(.bottom, -7)
}
.frame(width: 30, alignment: .leading)
}
Spacer()
VStack(alignment: .trailing, spacing: 0) {
Image(systemName: "info.circle")
.resizable()
.frame(width: 22, height: 22)
.foregroundColor(.accentColor)
.onTapGesture(count: 1) {
print("action")
}
}
}
.listRowInsets(.init(top: 0, leading: 0, bottom: 0, trailing: 0))
.frame(height: 46, alignment: .leading)
.padding(0)
}
}
Your problem is, that the editMode variable does not change when you press the EditButton. No matter in what state, in your CellRow the editMode variable always returns .inactive. I don't know why, it could be a bug.
I had the same problem, but I found this question here: SwiftUI - How do I make edit rows in a list?, which uses a workaround by passing the editMode environment value into a private #State variable, which seems to work perfect.
So here is what you need to do:
Add #State private var editMode: EditMode = .inactive to your EggList view.
This creates a state variable that from now on holds the editing mode.
Add .environment(\.editMode, self.$editMode) somewhere after the .navigationBarItems(...).
This sets the environment variable editMode in EggList to a binding of the state variable above.
Add .environment(\.editMode, self.$editMode) directly after the CellRow(...) initializer.
This inserts the state variable editMode into the environment of CellRow, where it can be accessed via #Environment(\.editMode).
Now you can just wrap one of your elements in an if-statement to hide it when in editing mode:
if !self.editMode?.wrappedValue.isEditing ?? true {
VStack(alignment: .leading, spacing: 0) {
Text("INC")
.font(.footnote)
.lineLimit(1)
.padding(.top, -4)
Text("37.3")
.font(.footnote)
.lineLimit(1)
.padding(0)
Text("30%")
.font(.footnote)
.lineLimit(1)
.padding(.bottom, -7)
}
.frame(width: 30, alignment: .leading)
}
or, if you prefer, continue using the isHidden extension from LuLuGaGa:
.isHidden(self.editMode?.wrappedValue.isEditing ?? false)
Add a little extension to View:
extension View {
func isHidden(_ hidden: Bool) -> some View {
if hidden {
return AnyView(self.hidden())
} else {
return AnyView(self)
}
}
}
Next add #Enviroment to your CellRow:
#Environment(\.editMode) var editMode: Binding<EditMode>?
You will be able to add a modifier:
.isHidden(editMode?.wrappedValue.isEditing ?? false)
to one of the stacks that you think is the least important.