I am using many TextFields in my SwiftUI Mac OS app. I am a main form, where the user adds data, which is composed of multiple Stacks/ views which contain TextFields/ and Text()
I noticed a strange bug, when I am using many TextFields combined in different views, I get some very heavy lags when selecting the TextField. Also when I skip to the next one with Tab it takes time.
It is really strange behavior and I am not sure what is causing that. I have a different view with many TextFields aswell, where everything is working smooth.
Also sometimes I can not jump back to the prior TextField with Shift+Tab.
Edit: I could figure out how to get rid of it. However, only if I remove one view. I don't want to.
My main container looks like that:
HStack
{
//Left Side
VStack{
Text("Here is the next #1")
}
VStack
{
//The View posted below
ViewBelow()
}
}
If I remove the first VStack, the issue is solved. Nothing lagging. If I add it, it is there again.
Just to give you a neckline of my code (many Stacks with TextFields)
ZStack
{
VStack
{
HStack
{
Text("Personal Data")
.font(.title)
.fontWeight(.bold)
.padding(.horizontal, 0)
.padding(.vertical, 5)
Spacer()
}
Divider()
.padding(.bottom, 5)
//Personal Data Types
HStack(spacing: 0)
{
//Left Element
VStack(alignment: .center)
{
Text("Vorname")
.foregroundColor(Color.gray)
} .frame(minWidth: 0, maxWidth: .infinity, alignment: .leading)
//Right Elemenet
VStack()
{
Text("Nachname")
.foregroundColor(Color.gray)
}
.frame(minWidth: 0, maxWidth: .infinity, alignment: .leading)
}.frame(minWidth: 0, maxWidth: .infinity)
HStack(spacing: 0)
{
VStack(alignment: .center)
{
//Left Element
if (self.editMode)
{
TextField("Enter some text", text: $s_test)
.frame(maxWidth:250)
}
else
{
Text(self.person.firstName)
.font(.body)
}
} .frame(minWidth: 0, maxWidth: .infinity, alignment: .leading)
VStack()
{
//Left Element
if (self.editMode)
{
TextField("Enter some text", text: self.$s_test)
.frame(maxWidth:250)
}
else
{
Text(self.person.lastName)
.font(.body)
}
}
.frame(minWidth: 0, maxWidth: .infinity, alignment: .leading)
}.frame(minWidth: 0, maxWidth: .infinity)
.padding(.top, 0)
//Personal Data Types
HStack(spacing: 0)
{
//Left Element
VStack(alignment: .center)
{
Text("Nickname")
.foregroundColor(Color.gray)
} .frame(minWidth: 0, maxWidth: .infinity, alignment: .leading)
//Right Elemenet
VStack()
{
Text("Birthday")
.foregroundColor(Color.gray)
}
.frame(minWidth: 0, maxWidth: .infinity, alignment: .leading)
}.frame(minWidth: 0, maxWidth: .infinity)
.padding(.top, 10)
HStack(spacing: 0)
{
VStack(alignment: .center)
{
//Left Element
if (self.editMode)
{
TextField("Enter some text", text: self.$s_test)
.frame(maxWidth:250)
}
else
{
Text(self.person.nickname)
.font(.body)
}
} .frame(minWidth: 0, maxWidth: .infinity, alignment: .leading)
VStack()
{
//Right Element
if (self.editMode)
{
TextField("Enter some text", text: self.$s_test)
.frame(maxWidth:250)
}
else
{
Text(self.person.birthdate)
.font(.body)
}
}
.frame(minWidth: 0, maxWidth: .infinity, alignment: .leading)
}.frame(minWidth: 0, maxWidth: .infinity)
.padding(.top, 0)
}
Maybe someone experienced the same already.. I am not quiet sure how to solve it. I removed many views, then it is working better. However I am not sure if it is just the quantity of TextFields or some bug in the other view.
I demonstrate the lag in the Gif. I press instantly when I hover above the TextField. See that lag..
Related
Pagination is not working on LazyVGrid layout, but without LazyVGrid the pagination is working properly. I really need to use LazyVGrid for my list. How can I fix this?
My code
VStack(alignment: .center) {
List {
LazyVGrid(columns: gridItemLayout, spacing: 20) {
ForEach(viewModel.tvShowList, id: \.id) { tvShow in
VStack {
KFImage.url(URL(string: Constant.POSTER_URL + tvShow.posterPath)!)
.placeholder {
Image("placeholder")
.scaledToFill()
.frame(width: 160, height: 100, alignment: .center)
.clipped()
}
.resizable()
.shadow(radius: 10)
.padding(.trailing, 20)
.scaledToFit()
.frame(width: 160, alignment: .center)
Text("\(tvShow.name)")
.multilineTextAlignment(.center)
.lineLimit(1)
.frame(maxWidth: .infinity)
.font(.system(size: 14))
.font(.headline)
}
.listRowBackground(Color.white)
.listRowSeparator(.hidden)
}
.id(UUID())
.frame(maxWidth: .infinity)
if (viewModel.page < viewModel.totalPage) {
HStack {
Spacer()
ProgressView()
.onAppear {
viewModel.page += 1
viewModel.getTvShowTopRated()
}
Spacer()
}
}
}
}
.listStyle(GroupedListStyle())
.padding([.leading, .trailing], 15) }
I've been trying to create a list and expand the space between the rows, while keeping them the full width, but I seem to be having some challenges. I think the approach is to make the HStack within the list expand horizontally from end to end and try to narrow top and bottom. I thought a frame modifier would do this but it doesn't seem to be working.
Here is the code:
NavigationView() {
List(caseList) {caseItem in
HStack {
Image(systemName: "folder.fill.badge.person.crop")
.foregroundColor(.accentColor)
VStack(alignment: .leading, spacing: 5) {
Text(caseItem.alias)
Text("# team members")
.font(.subheadline)
.foregroundColor(.secondary)
}
}
.listRowInsets(EdgeInsets())
.background(Color.green)
.clipShape(RoundedRectangle(cornerRadius: 10))
.badge(Int.random(in: 0..<5))
.listRowSeparatorTint(Color.cyan, edges: .all)
.listRowSeparator(.visible)
.listRowBackground(Color.orange)
.frame(
maxWidth: .infinity,
minHeight: 0,
maxHeight: .infinity,
alignment: .topLeading
)
}
.listStyle(InsetGroupedListStyle())
}
.onAppear() {
loadCases()
}
.navigationTitle("Cases")
I would also like to delete the gap between the list items and cases at the top.
UPDATE
I added a 2nd image to show, in red, what I would like the green shape to cover. I guess my goal is to make them look a little more like independent items with additional information and bigger spaces between them. This should not be an exhaustive list and in most occasions people will only have one, so I am trying to make them of substance. I was toying with expanded/collapsed ones so if you only had one, it would be expanded and not look so lonely.
If I understood the goal correctly, here it is (tested with Xcode 13.4 / iOS 15.5)
HStack {
Image(systemName: "folder.fill.badge.person.crop")
.foregroundColor(.accentColor)
VStack(alignment: .leading, spacing: 5) {
Text(caseItem.alias)
Text("# team members")
.font(.subheadline)
.foregroundColor(.secondary)
}
Spacer()
}
.badge(Int.random(in: 0..<5)).padding(.horizontal)
.listRowInsets(EdgeInsets(top: 8, leading: 0, bottom: 8, trailing: 0))
.background(Color.green)
.listRowSeparatorTint(Color.cyan, edges: .all)
.listRowSeparator(.visible)
.listRowBackground(Color.orange)
If i understood correctly, you want to space out your Items inside of your list?
in this case, you can add some padding(EdgeInsets(top: 15, bottom: 15))
"change the cursive text to the values that you want"
this would look something like this:
NavigationView() {
List(caseList) {caseItem in
HStack {
Image(systemName: "folder.fill.badge.person.crop")
.foregroundColor(.accentColor)
VStack(alignment: .leading, spacing: 5) {
Text(caseItem.alias)
Text("# team members")
.font(.subheadline)
.foregroundColor(.secondary)
}
}
.listRowInsets(EdgeInsets())
.background(Color.green)
.clipShape(RoundedRectangle(cornerRadius: 10))
.badge(Int.random(in: 0..<5))
.listRowSeparatorTint(Color.cyan, edges: .all)
.listRowSeparator(.visible)
.listRowBackground(Color.orange)
.padding(EdgeInsets(top: 15, bottom: 15))
.frame(
maxWidth: .infinity,
minHeight: 0,
maxHeight: .infinity,
alignment: .topLeading
)
}
.listStyle(InsetGroupedListStyle())
}
.onAppear() {
loadCases()
}
.navigationTitle("Cases")
Hope that helped you! if you need anymore help, you can contact me over on GitHub or Discord! (Discord on my profile)
(MacOS app)
I am trying to place a lazyvgrid next to an image. to have the image in a specific size and let the LazyVGrid take the rest of the width. I set the frame of the image but than the grid does not take the extra space and there are extra empty space to the left and right of the image and the grid.
import SwiftUI
struct ContentView: View {
var body: some View {
HStack{
LazyVGrid(columns: [GridItem(
.adaptive(minimum: 40)
)]){
Text("Placeholder")
Text("Placeholder")
}
.padding()
.background(Color.blue)
Image("bla")
.resizable()
//.scaledToFit()
.frame(width: 100, height: 100)
.background(Color.pink)
}
}
}
try something like this:
struct ContentView: View {
var body: some View {
HStack {
LazyVGrid(columns: [GridItem(.adaptive(minimum: 40))]){
Text("Placeholder")
Text("Placeholder")
}
.padding()
// put this here if you want the width and the height to expand
// .frame(maxWidth: .infinity, maxHeight: .infinity, alignment: .leading)
.background(Color.blue)
// put this here if you want just the width to expand
.frame(maxWidth: .infinity, maxHeight: .infinity, alignment: .leading)
Image(systemName: "globe")
.resizable()
//.scaledToFit()
.frame(width: 100, height: 100)
.background(Color.pink)
}.frame(maxWidth: .infinity, maxHeight: .infinity, alignment: .leading)
}
}
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
I have a button which I am unable to align to the top left with topLeading.
What I hope to accomplish:
my code:
var body: some View {
ZStack {
ZStack(alignment: .topLeading) {
Button(action: { self.show.toggle() }) {
HStack {
Spacer()
Image(systemName: "list.dash")
.foregroundColor(.black)
}
.padding(.trailing, 20)
.frame(width: 90, height: 60)
.background(Color.white)
.cornerRadius(30)
.shadow(color: Color("buttonShadow"), radius: 10, x: 0, y: 10)
}
Spacer()
}
}
}
But I get this:
The issue is that your wrapping views (two ZStacks) by default will take up only the space of their content, which is only the button. If you add a frame to allow the wrapper to expand you'll see the alignment working as you expect.
var body: some View {
ZStack {
ZStack {
Button(action: { self.show.toggle() }) {
HStack {
Spacer()
Image(systemName: "list.dash")
.foregroundColor(.black)
}
.padding(.trailing, 20)
.frame(width: 90, height: 60)
.background(Color.white)
.cornerRadius(30)
.shadow(color: Color.gray, radius: 10, x: 0, y: 10)
}
Spacer()
}
.frame(
maxWidth: .infinity,
maxHeight: .infinity,
alignment: Alignment.topLeading
)
}
}
Add background space consumer, like below (tested with Xcode 11.4)
ZStack(alignment: .topLeading) {
Color.clear // << here !!
Button(action: { self.show.toggle() }) {