SwiftUI issue on iOS 14 with Scrollview HStack content being cut off - ios

I have a list of buttons that display perfectly on iOS 13 using SwiftUI, but on iOS 14 it cuts the content off where the screen ends.
Has anything changed with regards to how HStacks renders what isn't on the screen? I used to scroll and be able to see all the buttons.
I will attach some screenshots and the code.
var body: some View {
VStack(alignment: .leading, spacing: 0){
Text("Select a venue type")
.font(.custom("MavenProBold", size: 16))
.padding(.leading, 16)
.padding(.top, 18)
.foregroundColor(Color.black)
ScrollView(.horizontal, showsIndicators: false) {
HStack(alignment: .center, spacing: 4, content: {
Button(action: {
self.selectedButtonIndex = 0
})
{
VStack(alignment: .center, spacing: 0, content: {
ZStack(alignment: .bottomTrailing){
Image(systemName: "star.fill")
.frame(width: circleFrameSize, height: circleFrameSize, alignment: .center)
.font(.title)
.background(Color(hexString: "#1A88FF"))
.foregroundColor(Color.white)
.clipShape(Circle())
}
Text("Things to do")
.padding(.top, 8)
.font(.custom("MavenProBold", size: 12))
.multilineTextAlignment(.center)
.lineLimit(50)
})
.frame(width: 80, height: 80, alignment: .center)
.padding(.all, 10)
.foregroundColor(Color.black)
}
Button(action: {
self.selectedButtonIndex = 0
})
{
VStack(alignment: .center, spacing: 0, content: {
ZStack(alignment: .bottomTrailing){
Image(systemName: "star.fill")
.frame(width: circleFrameSize, height: circleFrameSize, alignment: .center)
.font(.title)
.background(Color(hexString: "#1A88FF"))
.foregroundColor(Color.white)
.clipShape(Circle())
}
Text("Things to do")
.padding(.top, 8)
.font(.custom("MavenProBold", size: 12))
.multilineTextAlignment(.center)
.lineLimit(50)
})
.frame(width: 80, height: 80, alignment: .center)
.padding(.all, 10)
.foregroundColor(Color.black)
}
Button(action: {
self.selectedButtonIndex = 0
})
{
VStack(alignment: .center, spacing: 0, content: {
ZStack(alignment: .bottomTrailing){
Image(systemName: "star.fill")
.frame(width: circleFrameSize, height: circleFrameSize, alignment: .center)
.font(.title)
.background(Color(hexString: "#1A88FF"))
.foregroundColor(Color.white)
.clipShape(Circle())
}
Text("Things to do")
.padding(.top, 8)
.font(.custom("MavenProBold", size: 12))
.multilineTextAlignment(.center)
.lineLimit(50)
})
.frame(width: 80, height: 80, alignment: .center)
.padding(.all, 10)
.foregroundColor(Color.black)
}
Button(action: {
self.selectedButtonIndex = 0
})
{
VStack(alignment: .center, spacing: 0, content: {
ZStack(alignment: .bottomTrailing){
Image(systemName: "star.fill")
.frame(width: circleFrameSize, height: circleFrameSize, alignment: .center)
.font(.title)
.background(Color(hexString: "#1A88FF"))
.foregroundColor(Color.white)
.clipShape(Circle())
}
Text("Things to do")
.padding(.top, 8)
.font(.custom("MavenProBold", size: 12))
.multilineTextAlignment(.center)
.lineLimit(50)
})
.frame(width: 80, height: 80, alignment: .center)
.padding(.all, 10)
.foregroundColor(Color.black)
}
Button(action: {
self.selectedButtonIndex = 0
})
{
VStack(alignment: .center, spacing: 0, content: {
ZStack(alignment: .bottomTrailing){
Image(systemName: "star.fill")
.frame(width: circleFrameSize, height: circleFrameSize, alignment: .center)
.font(.title)
.background(Color(hexString: "#1A88FF"))
.foregroundColor(Color.white)
.clipShape(Circle())
}
Text("Things to do")
.padding(.top, 8)
.font(.custom("MavenProBold", size: 12))
.multilineTextAlignment(.center)
.lineLimit(50)
})
.frame(width: 80, height: 80, alignment: .center)
.padding(.all, 10)
.foregroundColor(Color.black)
}
})
.padding(.leading, 8)
.padding(.trailing, 8)
.padding(.bottom, 8)
}
}
}

I also met this problem. It happens when you have a customized clipShape outside of ScrollView. By customized I mean customized Path of the shape.
From my test, when you use builtin shapes, it works fine, for example:
view.clipShape(Circle())
When you use customized shape but with builtin Path, it also works fine, for example:
view.clipShape(CustomShape())
// which CustomShape is something like:
struct CustomShape: Shape {
func path(in rect: CGRect) -> Path {
return Path(roundedRect: rect, cornerSize: CGSize(width: 10, height: 10)
}
}
But when you use a customized Path in your CustomShape, this issue happens:
view.clipShape(CustomShape())
// which CustomShape is something like:
struct CustomShape: Shape {
func path(in rect: CGRect) -> Path {
let path = UIBezierPath(roundedRect: rect,
byRoundingCorners: corners,
cornerRadii: CGSize(width: radius, height: radius))
return Path(path.cgPath)
}
}
I also tried to draw the path manually(use move, addLine, addArc), it doesn't work.
So the workaround is to use builtin Path in your customized Shape. I guess this is a bug of iOS 14, because it works fine on iOS 13.

Related

How to shape an Image into an circle

iam unsing a UiKit Image picker and trying to setup an Profil Pic for the User. Everything's works fine, the image gets displayed. But iam trying to make it into a Circle. I Tried using clipShape with an circle but it doesn't work. i followed the tutorial "My Images 1: Photo Picker and Camera in SwiftUI"
struct ProfileView: View {
#EnvironmentObject var appUser: User
#EnvironmentObject var appInfo: AppInformation
var body: some View {
ZStack {
Rectangle()
.frame(width: 400, height: 720)
.cornerRadius(50)
.foregroundColor(.gray)
.overlay(
HStack {
if let image = appUser.profilBild {
Image(uiImage: image)
.resizable()
.frame(width: 100, height: 100)
.scaledToFill()
.clipShape(RoundedRectangle(cornerRadius: 15))
.overlay(Circle().stroke(Color.orange, lineWidth: 10))
.onTapGesture {
appInfo.source = .library
appInfo.showPicker = true
}
.padding(20)
.shadow(radius: 10)
.overlay(
ZStack{
Rectangle()
.frame(width: 20, height: 20)
.offset(x: 35, y: -35)
.foregroundColor(.white)
Image(systemName: "plus.circle.fill")
.resizable()
.frame(width: 30, height: 30)
.offset(x: 35, y: -35)
.foregroundColor(.blue)
.shadow(radius: 10)
}
)
}
else {
Image(systemName: "person.circle")
.resizable()
.frame(width: 100, height: 100)
.onTapGesture {
appInfo.source = .library
appInfo.showPicker = true
}
.padding(20)
.shadow(radius: 10)
.overlay(
ZStack{
Rectangle()
.frame(width: 20, height: 20)
.offset(x: 35, y: -35)
.foregroundColor(.white)
Image(systemName: "plus.circle.fill")
.resizable()
.frame(width: 30, height: 30)
.offset(x: 35, y: -35)
.foregroundColor(.blue)
.shadow(radius: 10)
}
)
}
VStack {
Text(appUser.username)
.font(.largeTitle)
.frame(width: 240 ,alignment: .leading)
.offset(x: -10, y: -25)
.lineLimit(1)
Text(appUser.name)
.frame(width: 220, alignment: .leading)
.offset(x: -15,y: -20)
.lineLimit(1)
}
}
.frame(width: 400, height: 720, alignment: .topLeading)
)
.padding()
ZStack {
Rectangle()
.foregroundColor(.secondary)
.frame(width: 380, height: 510)
.cornerRadius(45)
}
.frame(width: 400, height: 700, alignment: .bottom)
.padding()
}
.sheet(isPresented: $appInfo.showPicker) {
ImagePicker(sourceType: appInfo.source == .library ? .photoLibrary : .camera, selectedImage: $appUser.profilBild)
}
.frame(maxWidth: .infinity, maxHeight: .infinity, alignment: .top)
}
}
You were almost there :)
Your only mistake was the order you placed your modifiers. ORDER MATTERS!!
Place scaledToFill() and clipShape() before the frame modifier.
Like such:
.resizable()
.scaledToFill()
.clipShape(Circle())
.frame(width: size, height: size)

SwiftUI View is taking exceeding edges

I am learning SwiftUI and was trying to replicate an app. I ran into a problem where the view is taking up space outside the frame as well.
It looks like this:
My code for the view is:
struct LessonsScreen: View {
var body: some View {
VStack (alignment: .leading) {
HStack {
Image(systemName: "arrow.left")
.font(.system(size: 30))
Spacer()
Image(systemName: "slider.horizontal.3")
.font(.system(size: 30))
}
Text("A2 - Elementary")
.font(.system(size: 28, weight: .semibold))
.padding()
LessonCompletion(lessonNum: 1, text: "How are you?", color: .purple)
Image("discussion")
.cornerRadius(20)
.frame(width: UIScreen.main.bounds.width, alignment: .center)
LessonCompletion(lessonNum: 2, text: "Pronunciation", color: .green)
LessonCompletion(lessonNum: 3, text: "Demonstrative pronouns", color: .red)
LessonCompletion(lessonNum: 4, text: "Present continuous", color: .yellow)
Button(action: {}, label: {
Text("Get started")
.foregroundColor(.white)
.frame(width: UIScreen.main.bounds.width - 150, height: 70, alignment: .center)
.background(Color.black)
.cornerRadius(10)
.frame(width: UIScreen.main.bounds.width, alignment: .center)
.padding()
})
}
}
}
Can anyone tell me where I messed up the formatting?
If you like to align the button in center in native SwiftUI way, you can use view modifier Spacer() inside HStack() instead of .frame, like this: (and same with 'discussion' Image)
...
Button(action: {}, label: {
HStack{
Spacer()
Text("Get started")
.foregroundColor(.white)
.frame(width: UIScreen.main.bounds.width - 150, height: 70, alignment: .center)
.background(Color.black)
.cornerRadius(10)
.padding()
Spacer()
}
})
...
In your button replace
.frame(width: UIScreen.main.bounds.width, alignment: .center)
with
.frame(maxWidth: .infinity, alignment: .center)

Stacking a HStack below a ZStack in SwiftUI

Disclaimer: New to SwiftUI
I know a ZStack() view allows me to overlap views, which is what I want for the heading section of the app.
I set the ZStack() to not take up the entire height and had expected an HStack(), placed after the ZStack() to do just that, appear after. Instead it also overlaps with the ZStack.
I'm sure it's a simple solution to co-exist. Image and code below.
var body: some View {
GeometryReader { geometry in
ZStack(alignment: .topLeading) {
Ellipse()
.fill(self.bgColor)
.frame(width: geometry.size.width * 1.4, height: geometry.size.height * 0.28)
.position(x: geometry.size.width / 2.35, y: geometry.size.height * 0.1)
.shadow(radius: 3)
.edgesIgnoringSafeArea(.all)
HStack(alignment: .top) {
VStack(alignment: .leading) {
Text(self.title)
.font(.title)
.fontWeight(.bold)
.foregroundColor(Color.white)
Text(self.subtitle)
.font(.subheadline)
.fontWeight(.regular)
.foregroundColor(Color.white)
}
.padding(.leading, 25)
.padding(.top, 20)
Spacer()
VStack(alignment: .trailing) {
Image("SettingsIcon")
.resizable()
.scaledToFit()
.frame(width: 30, height: 30)
}
.padding(.top, 20)
.padding(.trailing, 25)
}
}
.fixedSize(horizontal: false, vertical: true)
HStack(alignment: .top) {
Text(self.title)
.font(.title)
.fontWeight(.bold)
.foregroundColor(Color.white)
}
}
}
Try the following code using a top VStack and closing the GeometryReader before the last HStack:
var body: some View {
VStack { // <-- here
GeometryReader { geometry in
ZStack(alignment: .topLeading) {
Ellipse()
.fill(self.bgColor)
.frame(width: geometry.size.width * 1.4, height: geometry.size.height * 0.28)
.position(x: geometry.size.width / 2.35, y: geometry.size.height * 0.1)
.shadow(radius: 3)
.edgesIgnoringSafeArea(.all)
HStack(alignment: .top) {
VStack(alignment: .leading) {
Text(self.title)
.font(.title)
.fontWeight(.bold)
.foregroundColor(Color.white)
Text(self.subtitle)
.font(.subheadline)
.fontWeight(.regular)
.foregroundColor(Color.white)
}
.padding(.leading, 25)
.padding(.top, 20)
Spacer()
VStack(alignment: .trailing) {
Image("SettingsIcon")
.resizable()
.scaledToFit()
.frame(width: 30, height: 30)
}
.padding(.top, 20)
.padding(.trailing, 25)
}
}.fixedSize(horizontal: false, vertical: true)
} // <-- here end GeometryReader
HStack(alignment: .top) {
Text(self.title)
.font(.title)
.fontWeight(.bold)
.foregroundColor(Color.white)
}
} // <-- here end VStack
}

Swift/SwiftUI: Background image blocks out image and text

When I use this code, the background works fine, but the other image, text and title are completely blocked out by it.
struct MainView: View {
var body: some View {
VStack(alignment: .leading, spacing: -4.0) {
Image("acdemo")
//background
.edgesIgnoringSafeArea(.all)
.blur(radius: /*#START_MENU_TOKEN#*/40.0/*#END_MENU_TOKEN#*/)
Image("acdemo")
.renderingMode(.original)
.resizable(capInsets: EdgeInsets(top: 0.0, leading: 0.0, bottom: 0.0, trailing: 0.0))
.aspectRatio(contentMode: .fit)
.frame(width: 300.0, alignment: .top)
.cornerRadius(/*#START_MENU_TOKEN#*/40.0/*#END_MENU_TOKEN#*/)
.shadow(radius: /*#START_MENU_TOKEN#*/4/*#END_MENU_TOKEN#*/)
Spacer()
.frame(height: 30)
Text("Title")
.font(.title)
.fontWeight(.bold)
.foregroundColor(Color.white)
.multilineTextAlignment(.leading)
.padding(.leading, 6.0)
.shadow(radius: /*#START_MENU_TOKEN#*/4/*#END_MENU_TOKEN#*/)
Text("Artist")
.font(.title)
.fontWeight(.regular)
.foregroundColor(Color.white)
.multilineTextAlignment(.leading)
.padding(.leading, 6.0)
.shadow(radius: /*#START_MENU_TOKEN#*/4/*#END_MENU_TOKEN#*/)
}
}
}
It's probably a very simple fix, I'm very new to Swift.
Try it like that:
struct MainView: View {
var body: some View {
ZStack {
Image("acdemo")
//background
.edgesIgnoringSafeArea(.all)
.blur(radius: /*#START_MENU_TOKEN#*/40.0/*#END_MENU_TOKEN#*/)
VStack(alignment: .leading, spacing: -4.0) {
Image("acdemo")
.renderingMode(.original)
.resizable(capInsets: EdgeInsets(top: 0.0, leading: 0.0, bottom: 0.0, trailing: 0.0))
.aspectRatio(contentMode: .fit)
.frame(width: 300.0, alignment: .top)
.cornerRadius(/*#START_MENU_TOKEN#*/40.0/*#END_MENU_TOKEN#*/)
.shadow(radius: /*#START_MENU_TOKEN#*/4/*#END_MENU_TOKEN#*/)
Spacer()
.frame(height: 30)
Text("Title")
.font(.title)
.fontWeight(.bold)
.foregroundColor(Color.white)
.multilineTextAlignment(.leading)
.padding(.leading, 6.0)
.shadow(radius: /*#START_MENU_TOKEN#*/4/*#END_MENU_TOKEN#*/)
Text("Artist")
.font(.title)
.fontWeight(.regular)
.foregroundColor(Color.white)
.multilineTextAlignment(.leading)
.padding(.leading, 6.0)
.shadow(radius: /*#START_MENU_TOKEN#*/4/*#END_MENU_TOKEN#*/)
}
}
}
}

LazyHStack cuts off content when scrolling

I have a LazyHStack nested in a ScrollView for showing some data from an API, but everytime I scroll it, the content is being cut off like this:
Here is the full struct:
struct MovieDetailView: View {
#EnvironmentObject private var navStack: NavigationStack
#ObservedObject var viewModel: MovieDetailVM
init(viewModel: MovieDetailVM) {
self.viewModel = viewModel
//UIScrollView.appearance().bounces = false
}
var body: some View {
GeometryReader { geometry in
ZStack(alignment: .top) {
ScrollView(showsIndicators: false) {
VStack {
GeometryReader { (proxy: GeometryProxy) in
if proxy.frame(in: .global).minY <= 0 {
Image(uiImage: (UIImage(data: viewModel.backdropData) ?? UIImage(named: JWConfig.IMG_PLACEHOLDER_MOVIE_BACKDROP))!)
.resizable()
.aspectRatio(contentMode: .fill)
.frame(width: proxy.size.width, height: 330)
} else {
Image(uiImage: (UIImage(data: viewModel.backdropData) ?? UIImage(named: JWConfig.IMG_PLACEHOLDER_MOVIE_BACKDROP))!)
.resizable()
.aspectRatio(contentMode: .fill)
.offset(y: -proxy.frame(in: .global).minY)
.frame(width: proxy.size.width, height: 330 + proxy.frame(in: .global).minY)
}
}
VStack(alignment: .leading) {
FDDivider(height: 20)
HStack {
Image(uiImage: (UIImage(data: viewModel.posterData) ?? UIImage(named: JWConfig.IMG_PLACEHOLDER_MOVIE_POSTER))!)
.resizable()
.aspectRatio(contentMode: .fill)
.frame(width: 120, height: 180)
.cornerRadius(20)
.clipped()
VStack(alignment: .leading) {
Text(viewModel.title)
.font(Font.custom(JWConfig.FONT_ARIAL, size: 25).weight(.semibold))
.foregroundColor(.SAPPHIRE)
.padding([.top, .bottom], 12)
.lineLimit(3)
HStack {
ForEach(viewModel.genres.prefix(2), id: \.ID) { genre in
JWBorderPill(text: genre.name, textSize: 12, textColor: .SAPPHIRE, borderColor: .DANUBE)
}
}
}.padding([.leading], 10)
Spacer()
}.padding([.leading, .trailing], 20)
FDDivider(height: 20)
HStack(spacing: 50) {
VStack {
Text("Release Date")
.font(Font.custom(JWConfig.FONT_ARIAL, size: 15))
.foregroundColor(.gray)
.padding([.bottom], 1)
Text(viewModel.releaseDate)
.font(Font.custom(JWConfig.FONT_ARIAL, size: 18).weight(.semibold))
}
VStack() {
Text("Duration")
.font(Font.custom(JWConfig.FONT_ARIAL, size: 15))
.foregroundColor(.gray)
.padding([.bottom], 1)
Text("\(viewModel.runtime)")
.font(Font.custom(JWConfig.FONT_ARIAL, size: 18).weight(.semibold))
}
VStack() {
Text("Rating")
.font(Font.custom(JWConfig.FONT_ARIAL, size: 15))
.foregroundColor(.gray)
.padding([.bottom], 1)
Text("\(String(format: "%.1f", viewModel.voteAverage)) / 10")
.font(Font.custom(JWConfig.FONT_ARIAL, size: 18).weight(.semibold))
}
}.frame(width: geometry.size.width)
VStack(alignment: .leading) {
Text("Overview")
.font(Font.custom(JWConfig.FONT_ARIAL, size: 23).weight(.semibold))
.foregroundColor(.SAPPHIRE)
.padding([.top, .bottom], 8)
Text(viewModel.overview)
.font(Font.custom(JWConfig.FONT_ARIAL, size: 17))
.foregroundColor(.gray)
}.padding([.leading, .trailing], 24)
VStack(alignment: .leading) {
Text("Production Companies")
.font(Font.custom(JWConfig.FONT_ARIAL, size: 23).weight(.semibold))
.foregroundColor(.SAPPHIRE)
.padding([.top], 8)
ScrollView(.horizontal, showsIndicators: false) {
LazyHStack {
ForEach(viewModel.productionCompanies, id: \.ID) { company in
ProductionCompanyCell(viewModel: ProductionCompanyCellVM(company))
}
}
}
}.frame(height: 250)
.padding([.leading], 24)
FDDivider(height: 400)
}.frame(width: geometry.size.width)
.background(Color.white)
.cornerRadiusWithEachCorner(50, corners: [.topLeft, .topRight])
.offset(y: 180)
}
}
HStack {
JWBackButton()
Spacer()
}.padding(EdgeInsets(top: 50, leading: 25, bottom: 0, trailing: 0))
}
}.edgesIgnoringSafeArea(.all)
}
}
Is there something wrong with my code? Please let me know if you need the full body code, and I'm using Xcode 12.4 at the moment

Resources