I am using a SwiftUI Form view but the 1st item in the Section of multiple items ("Account" in RED) has a shorter height than the following two items "Notifications" & "Preferences".
I tried adding a .frame(height: ) modifier to SettingsItem's VStack but that didn't force all the items to have the same height.
The only way the different sections look correct is if it's a single item in its own section, see the image below where the text "Password" is even inside its container but 3 items sharing a section are not even.
2 QUESTIONS
How can I make all items in a section have the same vertical height.
Is it possible to remove the corner radius so that the form has sharp edges? I need to get rid of the corner radius because I will add negative 20 padding leading & trailing so that each item expands to the edge of the screen so I don't want to see rounded corners.
struct Settings: View {
var body: some View {
NavigationView {
Form {
Section(header: Text("ACCOUNT SETTINGS")
.foregroundColor(.gray)) {
SettingsItem(showDivider: true, text: "Account")
SettingsItem(showDivider: true, text: "Notifications")
SettingsItem(showDivider: false, text: "Preferences")
}
Section(header: Text("SECURITY")
.foregroundColor(.gray)) {
SettingsItem(showDivider: false, text: "Password")
}
Section(header: Text("ABOUT")
.foregroundColor(.gray)) {
SettingsItem(showDivider: true, text: "FAQ")
SettingsItem(showDivider: true, text: "About")
SettingsItem(showDivider: false, text: "Contact")
}
}
}
}
}
struct SettingsItem: View {
let showDivider: Bool
var text: String
var body: some View {
VStack {
HStack {
Text(text)
.font(.system(size: 18, weight: .regular))
.foregroundColor(.gray)
Spacer()
Image(systemName: "chevron.right")
.font(.system(size: 16, weight: .bold))
.foregroundColor(.gray)
}
if showDivider {
Divider()
}
}
}
}
Removing the dividers fixes the problem:
struct ContentView: View {
var body: some View {
NavigationView {
Form {
Section("ACCOUNT SETTINGS") {
SettingsItem(text: "Account")
SettingsItem(text: "Notifications")
SettingsItem(text: "Preferences")
}
Section("SECURITY") {
SettingsItem(text: "Password")
}
Section("ABOUT") {
SettingsItem(text: "FAQ")
SettingsItem(text: "About")
SettingsItem(text: "Contact")
}
}
}
}
}
struct SettingsItem: View {
var text: String
var body: some View {
VStack {
HStack {
Text(text)
.font(.system(size: 18, weight: .regular))
.foregroundColor(.gray)
Spacer()
Image(systemName: "chevron.right")
.font(.system(size: 16, weight: .bold))
.foregroundColor(.gray)
}
}
}
}
Related
I have a problem with space occupied by NavigationLink. Following code:
struct EditView: View {
var body: some View {
NavigationView {
Form {
Section("Colors") {
ColorList(colors: viewModel.game.gameColors)
}
}
}
}
}
struct ColorList: View {
let colors: [String]
private let gridItemLayout = [GridItem(.adaptive(minimum: 44))]
var body: some View {
ScrollView {
LazyVGrid(columns: gridItemLayout) {
ForEach(colors, id: \.self) { colorName in
Meeple(colorName: colorName)
}
.padding(.vertical, 2)
}
}
}
}
// Meeple is just an image
struct Meeple: View {
// ...
var body: some View {
Image("meeple.2.fill")
.resizable()
.padding(5)
.foregroundColor(color.color)
.background(color.backgroundColor)
.frame(width: 44, height: 44, alignment: .center)
.clipShape(RoundedRectangle(cornerRadius: 5))
.shadow(color: .primary, radius: 5)
}
}
Produces a good result:
As soon as I add a NavigationLink around the ColorList like so
Section("Colors") {
NavigationLink(destination:
MultiColorPickerView(
selection: $viewModel.game.colors.withDefaultValue([])
)
) {
ColorList(colors: viewModel.game.gameColors)
}
}
The result looks weird:
There's plenty of space left. Why does it break after 3 items? And how can I make it to show more in one line?
add .frame(maxWidth: .infinity) to your ColorList.
Code below is working perfectly but i have an issue, i don't want to provide functionality here, i just want to add button (dropDownButton) and provide the functionality when using this custom view.
struct DrawerItemListRowView: View {
#State var iconName: Icon
#State var text: String
#State var dropDownButton = Button(action: {}) {
Image(icon: .drawer)
}
var body: some View {
HStack(alignment: .center, spacing: 15) {
Image(icon: iconName)
Text(text)
.foregroundColor(.customLightBlack)
.font(.custom(ubuntu: .regular, style: .title2))
Spacer()
dropDownButton
.frame(width: 24, height: 24, alignment: .trailing)
}
.padding()
.listRowSeparator(.hidden)
.listRowBackground(Color.customBackground)
.background(Color.clear)
}
}
struct DrawerItemListRowView_Previews: PreviewProvider {
static var previews: some View {
Group {
DrawerItemListRowView(iconName: .mainCategory, text: "Shop by category")
DrawerItemListRowView(iconName: .paymentMethod, text: "Payment Methods")
}
.previewLayout(.sizeThatFits)
.background(.white)
} }
You need to pass the action, not the button, as of type ()->Void.
Check out this example:
struct DrawerItemListRowView: View {
let iconName: String
let text: String
let action: ()->Void // Pass the action, not the button
var body: some View {
HStack(alignment: .center, spacing: 15) {
Image(systemName: iconName)
Text(text)
.foregroundColor(.gray)
Spacer()
Button {
action() // Call the action
} label: {
Text(text)
.fixedSize()
}
.frame(width: 24, height: 24, alignment: .trailing)
}
.padding()
.listRowSeparator(.hidden)
.listRowBackground(Color.yellow)
.background(Color.clear)
}
}
struct Example: View {
var body: some View {
VStack {
DrawerItemListRowView(iconName: "house", text: "Shop by category") {
print("Bought")
}
DrawerItemListRowView(iconName: "minus", text: "Payment Methods") {
print("Paid")
}
}
.previewLayout(.sizeThatFits)
.background(.white)
}
}
I'm trying to reposition a list using scrollTo with a Slider and Button and have 2 problems. The list has Sections with id's and nested Texts below, so the scrolling (by Slider or Button) is to the Section heads only.
Here are the problems:
Slider works fine except that the animation briefly shows the list at the top (you can see the navigationTitle go to full size) before it scrolls to the desired position correctly.
The Button moves the Slider but appears to not find the id's in the Section, so it doesn't reposition to the right Section.
Anyone have any ideas?
struct Floors: Identifiable {
let id: String
let name: String
}
struct UnitLine: Identifiable {
let id=UUID()
let name: String
}
struct UnitKeyboardView: View {
#Environment(\.presentationMode) var presentationMode
#State private var sliderValue = 8.0
var body: some View {
let floors=[Floors(id:"8",name:"8"),Floors(id:"9",name:"9"),Floors(id:"10",name:"10"),Floors(id:"11",name:"11"),Floors(id:"12",name:"12"),Floors(id:"13",name:"13"),Floors(id:"14",name:"14"),Floors(id:"15",name:"15"),Floors(id:"16",name:"16"),Floors(id:"17",name:"17"),Floors(id:"18",name:"18"),Floors(id:"19",name:"19"),Floors(id:"20",name:"20"),Floors(id:"21",name:"21"),Floors(id:"22",name:"22"),Floors(id:"23",name:"23"),Floors(id:"24",name:"24"),Floors(id:"25",name:"25"),Floors(id:"26",name:"26"),Floors(id:"27",name:"27"),Floors(id:"28",name:"28"),Floors(id:"29",name:"29")]
let unitlines=[UnitLine(name:"01"),UnitLine(name:"02"),UnitLine(name:"03"),UnitLine(name:"04"),UnitLine(name:"05"),UnitLine(name:"06"),UnitLine(name:"07"),UnitLine(name:"08")]
NavigationView {
ScrollViewReader {proxy in
VStack {
Spacer()
List {
ForEach(floors) { i in
Section(header: Text("Floor \(i.name)")) {
ForEach(unitlines) { u in
Text(u.name)
.padding(.trailing,200)
.contentShape(Rectangle())
.onTapGesture {
print("tapped")
presentationMode.wrappedValue.dismiss()
}
}
}
}
}
HStack {
Spacer()
Text("Flr: \(Int(sliderValue))")
.font(.title)
.padding(10)
Button {
if sliderValue>8 {
sliderValue=sliderValue-1.0
proxy.scrollTo(String(Int(sliderValue)), anchor: .topLeading)
}
else { print("slider below (\(sliderValue))") }
print(proxy)
} label: {
Image(systemName: "minus")
}
.frame(width:30, height:15)
.padding(10)
.background(Color.red)
.clipShape(Capsule())
Slider(value: $sliderValue, in: 8...42, step: 1.0, onEditingChanged: {_ in
withAnimation {
proxy.scrollTo(String(Int(sliderValue)), anchor: .topLeading)
print(String(Int(sliderValue)))
}
}
)
.background(Color.cyan)
.border(Color.blue, width: 1)
.padding(10)
Button {
if sliderValue<42 {
print(sliderValue)
sliderValue=sliderValue+1.0
print(sliderValue)
proxy.scrollTo(String(Int(sliderValue)), anchor: .topLeading)
}
} label: {
Image(systemName: "plus")
}
.frame(width:30, height:15)
.padding(10)
.background(Color.green)
.clipShape(Capsule())
Spacer()
}
.background(Color.gray)
}
}
.navigationTitle("Select Address")
}
}
}
I couldn't figure out why it is not working my ScrollViewReader below my code. Please help me figure out the issue. I want to pass my zolyric.number into scrollToIndex and that scrollToIndex will set the number that I want to scroll in my HymnLyrics(). Also, although I couldn't find the error, the building is pretty slow.
Here ZolaiTitles() is the same list just sorting the song titles algebraically and HymnLyrics() is the one to display in the canvas.
struct ZolaiTitles: View {
#AppStorage("scrollToIndex") var scrollToIndex: Int?
#EnvironmentObject var tappingSwitches: TapToggle
let zoLyrics: [Lyric] = LyricList.hymnLa.sorted { lhs, rhs in
return lhs.zoTitle < rhs.zoTitle
}
var body: some View {
ScrollView {
ForEach(zoLyrics, id: \.id) { zoLyric in
VStack {
Button(action: {
//if let lyricNum = String(zoLyric) {
scrollToIndex = zoLyric.number // zolyric.number is already an interger.
//}
self.tappingSwitches.isHymnTapped.toggle()
}, label: {
HStack {
Text(zoLyric.zoTitle)
.foregroundColor(Color("bTextColor"))
.lineLimit(1)
.minimumScaleFactor(0.5)
Spacer()
Text("\(zoLyric.number)")
.foregroundColor(Color("bTextColor"))
}
})
}
.frame(maxWidth: .infinity, alignment: .leading)
.padding([.leading, .bottom, .trailing])
}
}
}
}
struct HymnLyrics: View {
#AppStorage("scrollToIndex") var scrollToIndex: Int = 1
var lyrics: [Lyric] = LyricList.hymnLa
#AppStorage("fontSizeIndex") var fontSizeIndex = Int("Medium") ?? 18
#AppStorage("fontIndex") var fontIndex: String = ""
#AppStorage("showHVNumbers") var showHVNumbers: Bool = true
var body: some View {
ScrollViewReader { proxy in
List(lyrics, id: \.id) { lyric in
VStack(alignment: .center, spacing: 0) {
Text("\(lyric.number)")
.padding()
.multilineTextAlignment(/*#START_MENU_TOKEN#*/.leading/*#END_MENU_TOKEN#*/)
.id(lyric.number)
VStack {
VStack {
Text(lyric.zoTitle)
.font(.title2)
.fontWeight(.bold)
.foregroundColor(.primary)
.autocapitalization(.allCharacters)
Text(lyric.engTitle)
.font(.title3)
.fontWeight(.medium)
.foregroundColor(.secondary)
.italic()
}
// Don't use Padding here!
}
.multilineTextAlignment(.center)
HStack {
Text(lyric.key)
.italic()
Spacer()
Text(lyric.musicStyle)
}
.foregroundColor(.blue)
.padding(.vertical)
}
//.id(lyric.number)
}
.onChange(of: scrollToIndex, perform: { value in
proxy.scrollTo(value, anchor: .top)
})
}
}
}
My Custom button does not tap and passes to next view called AddCreditCardView.
I have tested the button action with print statement and it won't work too.
I copied my code below in separate.
This is my ContentView
import SwiftUI
struct ContentView: View {
let membershipRows = MembershipData.listData()
let corporateRows = CorporateData.listData()
let otherOperationRows = OtherOperationsData.listData()
#State var selectedCard = CreditCard(id: "", cardOwnerName: "", cardNumber: "", cardExpMonth: "", cardExpYear: "", ccv: "")
#State var shown: Bool = false
var body: some View {
NavigationView {
VStack {
List {
Section(header: Text("Bireysel")) {
ForEach(membershipRows) { row in
NavigationLink(destination: CreditCardView()) {
RowElementView(row: row)
}
}
}
if self.corporateRows.count == 0
{
Rectangle()
.background(Color(.white))
.edgesIgnoringSafeArea(.all)
.foregroundColor(.white)
.padding(.vertical,32)
}
else {
Section(header: Text("Kurumsal")) {
ForEach(corporateRows) { row in
RowElementView(row: row)
}
}
}
Section(header: Text("Diger Islemler")) {
ForEach(otherOperationRows) { row in
RowElementView(row: row)
}
}
Rectangle()
.foregroundColor(.clear)
.frame(width: UIScreen.main.bounds.width, height: UIScreen.main.bounds.height )
}
.navigationBarTitle("Odeme Yontemleri", displayMode: .inline)
.font(Font.custom("SFCompactDisplay", size: 16))
Button(action: {
AddCreditCardView(item: self.selectedCard)
}, label: { CustomButton(title: "Odeme Yontemi Ekle", icon: .none, status: .enable)
})
}
}
}
This is my AddCreditCardView
import SwiftUI
struct AddCreditCardView: View {
var item: CreditCard
var body: some View {
NavigationView {
VStack {
TopBar()
Spacer()
CardInfo()
Spacer()
}
.navigationBarTitle("Odeme Yontemi", displayMode: .inline)
}
}
}
struct TopBar : View {
var body: some View {
VStack {
HStack() {
Image("addcreditcard")
Image("line")
Image("locationBar")
Image("line")
Image("check-circle")
}
.padding(.horizontal,62)
VStack {
Text("Kredi Karti Ekle")
.font(Font.custom("SFCompactDisplay-Bold", size: 14))
Text("1. Adim")
.font(Font.custom("SFCompactDisplay", size: 14))
.fontWeight(.regular)
.foregroundColor(.gray)
}
}
.padding()
}
}
struct CardInfo : View {
var body: some View {
VStack {
CustomTextField(tFtext: "Kartin Uzerindeki Isim", tFImage: "user")
.textContentType(.givenName)
CustomTextField(tFtext: "Kredi Kart Numarasi", tFImage: "credit")
.textContentType(.oneTimeCode)
.keyboardType(.numberPad)
HStack {
CreditCardDateTextField(tFtext: "", tFImage: "date")
.textContentType(.creditCardNumber)
Spacer()
Text("|")
.foregroundColor(.black)
.overlay(
Rectangle()
.frame(width: 60, height: 53))
CustomTextField(tFtext: "CCV", tFImage: "")
.textContentType(.creditCardNumber)
}
.foregroundColor(Color(#colorLiteral(red: 0.9647058824, green: 0.9725490196, blue: 0.9882352941, alpha: 1)))
CustomTextField(tFtext: "Kart Ismi", tFImage: "cardEdit")
Spacer()
}
}
}
And Finally, this is my CreditCard Model
import SwiftUI
struct CreditCard: Identifiable {
var id: String = UUID().uuidString
var cardOwnerName : String
var cardNumber: String
var cardExpMonth: String
var cardExpYear: String
var ccv: String
Seems like you are trying to navigate to AddCreditCardView on the button press. The action closure can not present a view automatically like that! You should change that code to something like this:
#State var navigated = false
,,,
NavigationLink("AddCreditCardView", destination: AddCreditCardView(), isActive: $navigated)
Button(action: { self.navigated.toggle() },
label: { CustomButton(title: "Odeme Yontemi Ekle", icon: .none, status: .enable) })
changing the navigated state will show the next page as it seems you wished.