I was building a form on Xcode 12 and using iOS 14 and everything was working as expected. But after switching to 13 and iOS 15, the height of the cells are inconsistent, even changing when scrolled offscreen like they were a reusable table cell.
For example, I have this code: *** EDIT: I changed the below code to have everything that's currently on that page.
Struct EvalViewMHx: View {
var body: some View {
VStack {
Form {
Label(
title: {
Text("Demographics & Medical History")
.font(.title)
.foregroundColor(.white)
.padding()
},
icon: {
Image(systemName: "heart.text.square.fill")
.resizable()
.aspectRatio(contentMode: .fit)
.foregroundColor(.white)
})
.listRowBackground(Color.blue)
.frame(minWidth: 0, maxWidth: .infinity, minHeight: 0, maxHeight: .infinity, alignment: .center)
Section(header: Text("Demographics")) {
demographicsView(nameText: $nameText, DOB: $DOB, height: $height, weight: $weight)
}
Section(header: Text("Medical History")) {
VStack {
HStack {
Text("When did you get hurt?")
.padding()
Spacer()
Toggle("", isOn: $doesNotKnowInjuryDate)
.frame(width: 35)
.padding(.horizontal)
Text("I don't know")
.fontWeight(!doesNotKnowInjuryDate ? .regular : .bold)
.padding(.leading)
}
if !doesNotKnowInjuryDate {
DatePicker("Injury Date", selection: $injuryDate, displayedComponents: [.date])
.foregroundColor(Color(UIColor.systemGray3))
.padding()
}
}
.frame(minWidth: .zero, idealWidth: .infinity, maxWidth: .infinity, minHeight: 150, idealHeight: 150, maxHeight: 150, alignment: .center)
VStack(alignment: .leading) {
HStack {
Text("Where is your injury?")
Spacer()
Text("Right")
.fontWeight(isInjuryOnRightSide ? .regular : .bold)
Toggle("", isOn: $isInjuryOnRightSide)
.toggleStyle(SwitchToggleStyle(tint: Color(UIColor.systemGray5)))
.frame(width: 35)
.padding(.horizontal)
Text("Left")
.fontWeight(!isInjuryOnRightSide ? .regular : .bold)
.padding(.leading)
}
.zIndex(2.0)
Picker(selection: $injuryLocation, label: Text(""), content: {
ForEach(injuryLocations, id: \.self) { location in
Text(location)
}
})
.pickerStyle(WheelPickerStyle())
.frame(minWidth: .zero, idealWidth: .infinity, maxWidth: .infinity, minHeight: 100, idealHeight: 100, maxHeight: 100, alignment: .center)
.zIndex(1.0)
.padding()
}
.padding()
VStack(alignment: .leading) {
Text("How did you get hurt? (Method of Injury)")
.padding()
TextEditor(text: $MOI)
.frame(height: 150)
.background(Color(UIColor.systemGray5).opacity(0.75))
.cornerRadius(15)
}
.frame(minWidth: .zero, idealWidth: .infinity, maxWidth: .infinity, minHeight: 200, idealHeight: 200, maxHeight: 200, alignment: .center)
.padding()
if injuryLocation != "Lower Back" && injuryLocation != "Upper Back" && injuryLocation != "Head / Neck" && injuryLocation != "Chest" {
VStack {
pastInjuryHistory(injuryLocation: $injuryLocation, hasHadSameSideInjury: $hasHadSameSideInjury, hasHadOppositeSideInjury: $hasHadOppositeSideInjury, isSameSide: true)
pastInjuryHistory(injuryLocation: $injuryLocation, hasHadSameSideInjury: $hasHadSameSideInjury, hasHadOppositeSideInjury: $hasHadOppositeSideInjury, isSameSide: false)
}
}
}
}
}
}
}
(In the picture below, you're also seeing some buttons at the top, which are just rectangles in a horizontal scroll view. The code above is then just placed below that in a tab view like so: )
TabView(selection: $activeTab) {
EvalViewMHx()
.tag(1)
EvalObjectiveView()
.tag(2)
viewThree(activeTab: $activeTab)
.tag(3)
viewFour(activeTab: $activeTab)
.tag(4)
}
.tabViewStyle(PageTabViewStyle())
.onChange(of: activeTab, perform: { value in
print(activeTab)
})
.animation(.default)
and the output shows that one of the cells has a totally different height.
Even stranger, another section has a cell with a 0 height but still shows the text field sitting over the rest of the cells. I have a picker view that is also in these cells and putting the pickerStyle to
.pickerStyle(InlinePickerStyle())
expands the cell to larger than an iPad screen size and doesn't put it in a wheel like it did in the previous versions.
Are these bugs that I should just be patient for a fix, or is there something that I can do to fix this and keep moving with my project?
Was struggling with the same issue. Turned out .animation caused the issue, as its deprecated since iOS 15. Removing that line fixed the issue for me.
Related
A whiteness is seen in the area drawn with the red line. If I change the background color of the most inclusive Vstack, that white area changes.
Deleting spacer() lines doesn't work.
Why is there a gap even though there is no space in between?
struct TabbarView: View {
var body: some View {
VStack{
Spacer()
ZStack{
Color.orange.opacity(0.5)
VStack(spacing: 0){
Text("Home")
.padding()
}
}
Spacer()
HStack{
VStack{
Image(systemName: "homekit")
.resizable()
.aspectRatio(contentMode: .fit)
.frame(width: UIScreen.main.bounds.size.width / 15, height: UIScreen.main.bounds.size.height / 25)
}
}
.frame(width: UIScreen.main.bounds.size.width, height: UIScreen.main.bounds.size.height / 13)
.background(Color.purple)
}
.ignoresSafeArea()
// .background(Color.purple.shadow(radius: 2))
}
}
enter image description here
you can add for VStack:
VStack {}
.frame(minWidth: 0, maxWidth: .infinity, minHeight: 0, maxHeight: .infinity, alignment: .center)
updated:
struct ContentView: View {
var body: some View {
ZStack {
Color.orange.opacity(0.5)
VStack {
Spacer()
VStack(spacing: 0){
Text("Home")
.padding()
}
Spacer()
HStack {
VStack {
Image(systemName: "homekit")
.resizable()
.aspectRatio(contentMode: .fit)
.frame(width: 25, height: 25, alignment: .center)
.frame(width: UIScreen.main.bounds.size.width / 15, height: UIScreen.main.bounds.size.height / 25)
}
}
.frame(width: UIScreen.main.bounds.size.width, height: UIScreen.main.bounds.size.height / 13)
.background(Color.purple)
}
}
.ignoresSafeArea()
.frame(minWidth: 0, maxWidth: .infinity, minHeight: 0, maxHeight: .infinity)
}
}
you used nesting incorrectly and there is a native TabView for tabs
result:
I've been trying to change the layout to the WatchLandmarks tutorial that Apple provides for making SwiftUI apps for the watch (https://developer.apple.com/tutorials/swiftui/creating-a-watchos-app) and I can't figure out why the images aren't loading for me. It works just fine in the completed tutorial code, and the only differences are in my changes to the layout of LandmarkList and LandmarkRow.
changes to LandmarkList:
struct LandmarkList<DetailView: View>: View {
#EnvironmentObject private var userData: UserData
let detailViewProducer: (Landmark) -> DetailView
var body: some View {
VStack(alignment: .leading){
Text(" Landmarks")
.font(.system(size: 16))
ScrollView(.horizontal, showsIndicators:false){
HStack(alignment: .center){
ForEach(userData.landmarks) { landmark in
// if !self.userData.showFavoritesOnly || landmark.isFavorite {
NavigationLink(
destination: self.detailViewProducer(landmark).environmentObject(self.userData)) {
LandmarkRow(landmark: landmark)
.frame( maxWidth: 70, maxHeight: 70, alignment: .leading)
}
// }
}
}
}.frame(minWidth: 0, maxWidth: .infinity, maxHeight: 100, alignment: .center)//.frame(width:150, height: 100)
Text(self.userData.landmarks[0].name)
.frame(minWidth: 0, maxWidth: .infinity, minHeight: 24, alignment: .center)
HStack(spacing: 32){
Button(action: { print("first button") }) {
Text("P")
}.frame(minWidth: 20, maxWidth:50, minHeight: 20, maxHeight:50)
.background(Color.orange)
.clipShape(Circle())
.overlay(Circle().stroke(Color.clear, lineWidth: 4))
.shadow(radius: 10)
Button(action: { print("second button") }) {
Text("S")
}.frame(minWidth: 20, maxWidth:50, minHeight: 20, maxHeight:50)
.background(Color.orange)
.clipShape(Circle())
.overlay(Circle().stroke(Color.clear, lineWidth: 4))
.shadow(radius: 10)
}.frame(minWidth: 0, maxWidth: .infinity, maxHeight: 100, alignment: .center)
// List {
// Toggle(isOn: $userData.showFavoritesOnly) {
// Text("Show Favorites Only")
// }
//
// ForEach(userData.landmarks) { landmark in
// if !self.userData.showFavoritesOnly || landmark.isFavorite {
// NavigationLink(
// destination: self.detailViewProducer(landmark).environmentObject(self.userData)) {
// LandmarkRow(landmark: landmark)
// }
// }
// }
// }
// .navigationBarTitle(Text("Landmarks"))
}.frame(maxWidth: .infinity, minHeight:200, maxHeight: .infinity, alignment: .leading)
}
}
changes to LandmarkRow
struct LandmarkRow: View {
var landmark: Landmark
var body: some View {
HStack {
landmark.image
.resizable()
.frame(width: 50, height: 50)
.cornerRadius(8.0)
// Text(landmark.name)
// Spacer()
//
// if landmark.isFavorite {
// Image(systemName: "star.fill")
// .imageScale(.medium)
// .foregroundColor(.yellow)
// }
}
}
}
What am I doing wrong?
Try to call .renderingMode(.original) on the image.
There are two types of rendering modes for your image assets:
Original
Template
Original mode will portray the image asset as it is, while the template mode will turn all the non-transparent parts of the image into one color that you can set. The default color is black.
Note: No overview available is available in Apple documentation.
In this tutorial, you’ll learn what rendering mode in SwiftUI is and how to use it.
I am creating an app that will let people keep score in board games. I created a view that contains the player name and their current score. I have my iphone layout set to landscape and don't care which layout is used on the ipad. The problem I am having is when I am on my iphone the size of the four player views are all different. You can see that I am trying to use .frames, and I assumed swiftUI would realize the four views should always remain the same size. This solution might not be optimal, but I am trying to figure out how to fit it all on the page and have it scale to fit within an ipad view?
Here is the current view:
Player 1 in the top right corner or player two in the bottom left would be great sizes
Player View:
struct PlayerView: View {
var playerName:String
//var score:Int
var body: some View {
ZStack{
RoundedRectangle(cornerRadius: 10)
.stroke(Color.black, lineWidth: 3)
.frame(minWidth: 115, idealWidth: 115, maxWidth: 384, minHeight: 25, idealHeight: 34, maxHeight: 50, alignment: .center)
RoundedRectangle(cornerRadius: 10)
.fill(Color.blue)
.frame(minWidth: 115, idealWidth: 115, maxWidth: 384, minHeight: 25, idealHeight: 34, maxHeight: 50, alignment: .center)
Text("\(playerName)")
.foregroundColor(.white)
}
Score View:
struct ScoreView: View {
var body: some View {
ZStack(alignment:.bottom){
RoundedRectangle(cornerRadius: 25)
.stroke(Color.black, lineWidth: 3)
.frame(minWidth: 115, idealWidth: 115, maxWidth: 200, minHeight: 100, idealHeight: 100, maxHeight: 175, alignment: .center)
RoundedRectangle(cornerRadius: 25)
.fill(Color.blue)
.frame(minWidth: 115, idealWidth: 115, maxWidth: 200, minHeight: 100, idealHeight: 100, maxHeight: 175, alignment: .center)
VStack(spacing: 3){
Text("Points")
Text("0")
.padding(.bottom)
}
.foregroundColor(Color.white)
}
.aspectRatio(contentMode: .fit)
}
}
Combined View:
struct ScoreBoardView: View {
var playerName: String
var body: some View {
ZStack(alignment: .top){
ScoreView()
.layoutPriority(2.0)
PlayerView(playerName: playerName)
.layoutPriority(1.0)
}
}
}
Board View:
var body: some View {
VStack {
Text("BANNER PLACEHOLDER")
.padding([.leading,.trailing],80)
.padding([.top,.bottom],20)
.border(Color.black)
HStack {
VStack{
ScoreBoardView(playerName: "Player 1")
.padding(.bottom, 50)
.padding(.leading,10)
ScoreBoardView(playerName: "Player 2")
.padding(.leading,10)
}
addPointsCombinedView()
.aspectRatio(contentMode: .fit)
.layoutPriority(1.0)
VStack{
ScoreBoardView(playerName: "Player 3")
.padding(.bottom, 50)
ScoreBoardView(playerName: "Player 4")
}
}
}
It finally clicked last night. I was able to solve the problem by putting my combined view into HStacks and then imbedding those into VStacks. It looks much nicer now.
VStack {
Text("BANNER PLACEHOLDER")
.padding([.leading,.trailing],80)
.padding([.top,.bottom],10)
.border(Color.black)
.padding(.top, 5)
.layoutPriority(1.0)
ZStack{
addPointsCombinedView()
.aspectRatio(contentMode: .fit)
VStack {
HStack {
ScoreBoardView(playerName: "Player 1")
.padding(.leading, 20)
.padding(.bottom, 7)
.padding(.top,5)
Spacer()
ScoreBoardView(playerName: "Player 2")
.padding(.trailing, 20)
.padding(.bottom, 7)
.padding(.top,5)
}
HStack{
ScoreBoardView(playerName: "Player 3")
.padding(.leading, 20)
.padding(.top,10)
.padding(.bottom,5)
Spacer()
ScoreBoardView(playerName: "Player 4")
.padding(.trailing,20)
.padding(.top,10)
.padding(.bottom,5)
}
}
}
}
}
}
I'm learning SwiftUI and had a very simple view with only one shape with a onTapGesture. What I'm expecting the onTapGesture should be called only when I click on the shape. However I've noticed that when I click outside of the shape (not too far away) the onTapGesture is also fired. Any one has any idea why this is happening?
struct ContentView: View {
var body: some View {
RoundedRectangle(cornerRadius: 10)
.fill(Color.yellow)
.frame(width: 100, height: 100, alignment: .leading)
.onTapGesture {
print("Clicked")
}
}
}
Update:
I've tried having multiple element inside a Vstack. When you try to click on the very bottom of test view2 you can see in the console that it prints click on view 3.
var body: some View {
VStack {
ZStack {
RoundedRectangle(cornerRadius: 20)
.foregroundColor(.red)
Text("test view1")
}
.frame(width: 200, height: 100, alignment: .center)
ZStack {
RoundedRectangle(cornerRadius: 20)
.foregroundColor(.blue)
Text("test view2")
}
.frame(width: 200, height: 100, alignment: .center)
.onTapGesture {
print("click on view 2")
}
ZStack {
RoundedRectangle(cornerRadius: 20)
.foregroundColor(.green)
Text("test view3")
}
.frame(width: 200, height: 100, alignment: .center)
.onTapGesture {
print("click on view 3")
}
}
.frame( maxWidth: .infinity, maxHeight: .infinity, alignment: .bottom)
.background(Color.black)
}
I am creating a simple SwiftUI view for a Catalyst Mac app like so:
var body: some View {
ZStack {
Color(envColor.getColor())
HStack {
Spacer()
VStack {
HStack {
TextField("First", text: $envColor.stringR)
TextField("Second", text: $envColor.stringG)
}
}
.frame(minWidth: 0, maxWidth: .infinity, minHeight: 100, maxHeight: 200)
.background(Color.gray)
Spacer()
VStack {
Text("Right Side")
}
.frame(minWidth: 0, maxWidth: .infinity, minHeight: 100, maxHeight: 200)
Spacer()
}
}
}
When I run the App it just looks like this:
A simple view with 2 text boxes. Both of them you can freely type into without issue.
You can highlight and edit either 255 without issue.
However, when I add a shadow to my VStack like so:
var body: some View {
ZStack {
Color(envColor.getColor())
HStack {
Spacer()
VStack {
HStack {
TextField("First", text: $envColor.stringR)
TextField("Second", text: $envColor.stringG)
}
}
.frame(minWidth: 0, maxWidth: .infinity, minHeight: 100, maxHeight: 200)
.background(Color.gray)
.shadow(radius: 5)
Spacer()
VStack {
Text("Right Side")
}
.frame(minWidth: 0, maxWidth: .infinity, minHeight: 100, maxHeight: 200)
Spacer()
}
}
}
The app looks exactly the same but I can't type in the TextFields at all. They don't highlight and I can't type in them. I looked at the Debug View Hierarchy and it looks fine with the TextFields in the front.
Here's a video of me using it with the shadow. As you can see the cursor doesn't change to let me edit.
Does adding a shadow to a VStack actually cause issue? And I doing something incorrect? Or is this a bug?
Probably this is a defect - you can submit feedback to Apple. Meanwhile I can propose solution - put shadow into background:
Tested with Xcode 11.4 / macOS 10.15.4
VStack {
HStack {
TextField("First", text: $first)
TextField("Second", text: $second)
}
}
.frame(minWidth: 0, maxWidth: .infinity, minHeight: 100, maxHeight: 200)
.background(Color.gray.shadow(radius: 5)) // << here !!
Just add clipped() and it will work:
var body: some View {
HStack {
TextField(
placeholder,
text: $text,
onEditingChanged: {
isEditing = $0
}
)
....
}
.background(Colors.shared.background.primary)
.clipped()
.shadow(color: .black.opacity(0.3), radius: 0, x: 0, y: 0.33)
.padding(.bottom, 1)
}
The following change to my code solved the problem in addition to #Asperi's solution. I added .clipped() and now the TextFields work.
var body: some View {
ZStack {
Color(envColor.getColor())
HStack {
Spacer()
VStack {
HStack {
TextField("First", text: $envColor.stringR)
TextField("Second", text: $envColor.stringG)
}
}
.frame(minWidth: 0, maxWidth: .infinity, minHeight: 100, maxHeight: 200)
.clipped()
.background(Color.gray)
Spacer()
VStack {
Text("Right Side")
}
.frame(minWidth: 0, maxWidth: .infinity, minHeight: 100, maxHeight: 200)
Spacer()
}
}
}