Issue with Horizontal ScrollView in SwiftUI - ios

I am trying to make a 3D carousel horizontal scroll view but when you scroll, it disappears and glitches. This is very strange for a ScrollView as I have used a horizontal scroll view many times before and have not encountered such an issue. What should I consider when constructing my horizontal scroll view? Is there something in my code that is faulty? Please look at my code below:
struct TestView: View {
var body: some View {
ZStack {
Color.black.ignoresSafeArea()
ScrollView(.horizontal, showsIndicators: false) {
HStack(alignment: .center, spacing: 230) {
ForEach(0..<5, id: \.self) { item in
GeometryReader { geometry in
Rectangle()
.fill(.ultraThinMaterial)
.frame(width: 200, height: 300, alignment: .center)
.cornerRadius(16)
.shadow(color: Color.black.opacity(0.2), radius: 20, x: 0, y: 0)
.rotation3DEffect(Angle(degrees: (Double(geometry.frame(in: .global).minX) - 210) / -20), axis: (x: 0, y: 1.0, z: 0))
}
}
}
.padding(.horizontal, 210)
}
}
}
}

Related

SwiftUI - position at top leading this view at `x` and `y`

Goal:
Match SwiftUI position coordinates with Figma.
Context:
On Figma, the anchor is at the top leading of the layer.
On SwiftUI, the anchor is at the center of the layer, as the documentation mentions:
/// - Returns: A view that fixes the center of this view at `x` and `y`.
#inlinable public func position(x: CGFloat = 0, y: CGFloat = 0) -> some View
So when both SwiftUI and Figma are set to x:0 and y:0 positions, they don't match.
Question: how can I set the anchor in SwiftUI to be at the top leading corner?
import SwiftUI
struct ContentView: View {
var body: some View {
ZStack {
Circle()
.frame(width: 132.0, height: 132.0)
.position(x: 0, y: 0)
}
.frame(width: 731, height: 418)
.background(.blue)
}
}
Centering the circle at (0, 0) will make go out of bounds because of the radius. You must do one of the following:
Using HStack & VStack:
ZStack {
VStack {
HStack {
Circle()
.frame(width: 132.0, height: 132.0)
Spacer()
}
Spacer()
}
}.frame(width: 731, height: 418)
.background(.blue)
Center the circle at (x + radius, y + radius):
ZStack {
HStack {
Circle()
.frame(width: 132.0, height: 132.0)
}
.position(x: 66, y: 66)
}
.frame(width: 731, height: 418)
.background(.blue)

I want to change the direction of the ScrollView, but it reverses everything

I'm trying to get the ScrollView to start the show from right to left
I found this solution, but it reversed everything the wrong way
.flipsForRightToLeftLayoutDirection(true)
.environment(\.layoutDirection, .rightToLeft)
Adding this to ScrollView
I just want to reverse the start of ScrollView, not everything
struct AdsView: View {
var body: some View {
VStack(spacing: 1){
ScrollView(.horizontal, showsIndicators: false) {
HStack(spacing: 20) {
ForEach(0..<5) { item in
VStack(alignment: .trailing) {
Image("test")
.resizable()
.scaledToFit()
.cornerRadius(20)
.shadow(color: .black.opacity(0.1), radius: 20, x: 20, y: 20)
.frame(maxWidth: 150, maxHeight: 200)
Text("start here")
Text("new").foregroundColor(Color.red)
}
}
}.padding()
}
.flipsForRightToLeftLayoutDirection(true)
.environment(\.layoutDirection, .rightToLeft)
}
}
}
A solution is to use opposite scales for a ScrollView and content.
Tested with Xcode 13.3 / iOS 15.4
Here is main part:
.scaleEffect(CGSize(width: -1, height: 1))
}
.scaleEffect(CGSize(width: -1, height: 1))
Test module in project is here

How to clip subviews using ZStack with SwiftUI?

I need to clip the view behind a Text by using its Rectangle. When I add a Text over this 1-pixel height rectangle, I need it to "clip" the subview below, so the text can be readable.
Of course, if I use a solid background color, it's easy to do, as I just set it and it will clip the subview.
Here is a POC to test it:
struct test: View {
let gradient = Gradient(colors: [Color.blue, Color.purple])
var body: some View {
ZStack {
Rectangle()
.fill(LinearGradient(gradient: gradient, startPoint: .leading, endPoint: .trailing))
.frame(width: 200, height: 200)
ZStack {
Rectangle()
.fill(Color.white)
.frame(width: 100, height: 1, alignment: .center)
Text("XXXX")
.background(Color.green)
}
}
}
}
Any ideas? I don't think I can handle it using a mask.
Sometimes a solution might be not-to-do instead of to-do-but.
Here is a possible implementation of above principle to solve your issue.
var body: some View {
ZStack {
Rectangle()
.fill(LinearGradient(gradient: gradient, startPoint: .leading, endPoint: .trailing))
.frame(width: 200, height: 200)
HStack(spacing: 0) {
Rectangle()
.fill(Color.white)
.frame(width: 30, height: 1, alignment: .center)
Text("XXXX")
Rectangle()
.fill(Color.white)
.frame(width: 30, height: 1, alignment: .center)
}
}

how to position view base on min(X or Y) not mid(X or y) SwiftUI

I want to position blue view based on topTrailing anchor like this
not like
this is my code Xcode12 beta 3
struct Test: View {
var body: some View {
ZStack(alignment:.topLeading){
Color.black
Rectangle()
.frame(width:100, height: 100, alignment: .topLeading)
.position(CGPoint(x: 0, y: 0))
.foregroundColor(.blue)
}
.frame(width: 250, height: 250, alignment: .topLeading)
}
}
how do I do that
To position relative to the top leading origin:
Use
.offset(x: 0, y: 0)
in place of
.position(CGPoint(x: 0, y: 0))
Just remove position, it disables automatic layout, because specifies explicit defined location in parent coordinates relative to own anchor point.
struct Test: View {
var body: some View {
ZStack(alignment:.topLeading){
Color.black
Rectangle()
.frame(width:100, height: 100, alignment: .topLeading)
.foregroundColor(.blue)
}
.frame(width: 250, height: 250, alignment: .topLeading)
}
}

how to make subview shadow bleeding out from parent view in SwiftUI?

As the title explained, I need make the shadow of subview bleeding out from parent bounds.
We can see the shadow is clipped by the container (parent view). How to ignore it?
ScrollView(axis, showsIndicators: false) {
HStack{
ForEach(d_keys.indices) { index -> DownloadOptionView in
let d_key = d_keys[index]
let d_info = asset.downloads[d_key]!
return DownloadOptionView(d_key: d_key, d_info: d_info)
}.padding(.vertical, 10) // ForEach
}
}.frame(minHeight:130)
// View structure for DownloadOptionView, modified, may not compile
struct DownloadOptionView: View {
let d_key: String
let d_info: DownloadInfo
// some #ObservedObject ...........
// some #State ...........
var body: some View {
return NavigationLink(destination: SceneKitCanvas(textureMap: textureMap), isActive: self.$present) {
Button(action: {
// Download / storage / animation
}) {
ZStack{
LinearGradient(gradient: Gradient(colors: [Neumorphism.background, Neumorphism.light]),
startPoint: .topLeading, endPoint: .bottomTrailing)
Color.green.scaleEffect(x: 1.0, y: CGFloat(scale), anchor: .bottom) // progress bar
Color.green.scaleEffect(x: 1.0, y: CGFloat(increased), anchor: lineAnchor)
VStack(alignment: .leading, spacing: 5) {
HStack(alignment: .center) {
Image(systemName: imageName).aspectRatio(contentMode: .fit)
Text(file_type).fontWeight(.light)
}.padding(.bottom, 5)
Text(d_key).font(.footnote).fontWeight(.light)
Text(size_final).font(.footnote).fontWeight(.light)
}.padding() // VStack
} // ZStack
}
.cornerRadius(20)
.shadow(color: Color.gray, radius: 3, x: 3, y: 3)
.shadow(color: Color.white, radius: 3, x: -3, y: -3)
}
}
}
I have done some guesswork about how you created DownloadOptionView but the answer can be used in your context as it's a general technique.
Where you are creating DownloadOptionView you need to add the .blendMode(.overlay) modifier:
struct DownloadOptionView: Shape {
func path(in rect: CGRect) -> Path {
return RoundedRectangle(cornerRadius: 8, style: .continuous).path(in: rect)
}
var body: some View {
RoundedRectangle(cornerSize: CGSize(width: 8, height: 8))
.frame(minWidth: 200, minHeight: 200)
.shadow(radius: 10)
.blendMode(.overlay) //Add here.
}
}

Resources