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.
}
}
Related
In the LargeMetarView which is a Large Size Widget view I added the Link definition to make each airport returned a link and when I click each line entry they act like a link, but just go to the main app start page, not the WidgetStationView I want it to open to show the detail of the selected airport. I have not built the entire view to show all data, I'm just trying to get the link to work and open the WidgetStaionview swiftui view that located in the main app.
struct LargeMetarView: View {
#ObservedObject var metarservice = MetarService()
#State private var skyImage = String()
var entry: MetarEntry
var counter: Int = 0
var body: some View {
ZStack(alignment: .topLeading) {
LinearGradient(gradient: Gradient(colors: [.black.opacity(1), .black.opacity(0.7), .black.opacity(1)]), startPoint: .bottomLeading, endPoint: .topTrailing)
HStack(alignment: .top) {
Text("FRAT Metars")
Text("Updated: ")
Text(entry.date, style: .time)
}
.frame(maxWidth: .infinity)
.padding(10)
.background(.blue)
.foregroundColor(.white)
.clipped()
.shadow(radius: 8)
HStack(alignment: .top, spacing: 8) {
VStack(alignment: .leading, spacing: 5){
Spacer()
ForEach(entry.metars) { entries in
**Link(destination: URL(string: "frat://metar/\(entries.mairport)")!)**{
HStack(spacing: 5){
switch entries.mfltcat {
case "VFR":
Image(systemName: entries.metarImage)
.renderingMode(.original)
.font(.system(size: 25))
.foregroundColor(.green)
.shadow(color: .black, radius: 1, x: 0.5, y: 0.5)
case "MVFR":
Image(systemName: entries.metarImage)
.renderingMode(.original)
.font(.system(size: 25))
.foregroundColor(.cyan)
.shadow(color: .black, radius: 1, x: 0.5, y: 0.5)
case "IFR":
Image(systemName: entries.metarImage)
.renderingMode(.original)
.font(.system(size: 25))
.foregroundColor(.red)
.shadow(color: .black, radius: 1, x: 0.5, y: 0.5)
case "LIFR":
Image(systemName: entries.metarImage)
.renderingMode(.original)
.font(.system(size: 25))
.foregroundColor(.purple)
.shadow(color: .black, radius: 1, x: 0.5, y: 0.5)
default:
Image(systemName: entries.metarImage)
.renderingMode(.original)
.font(.system(size: 25))
.foregroundColor(.green)
.shadow(color: .black, radius: 1, x: 0.5, y: 0.5)
}
Text(entries.mairport)
switch entries.mfltcat {
case "VFR":
Text(entries.mfltcat).bold()
.foregroundColor(Color.green)
case "MVFR":
Text(entries.mfltcat).bold()
.foregroundColor(Color.cyan)
case "IFR":
Text(entries.mfltcat).bold()
.foregroundColor(Color.red)
case "LIFR":
Text(entries.mfltcat).bold()
.foregroundColor(Color.purple)
default:
Text(entries.mfltcat)
.foregroundColor(Color.white).bold()
}
Text(entries.mobstime + "Z")
Text(entries.mvis)
Text(entries.mwind)
} // End of HSTACK
}
.foregroundColor(.white)
.font(.subheadline)
Divider()
.frame(height: 2)
.overlay(.white)
}
}
.padding(20)
}.onAppear(perform: WidgetCenter.shared.reloadAllTimelines) // HSTACK
Spacer()
} // ZSTACK
//.widgetURL(URL(string: "metarnav"))
} // End of someview
struct LargeMetarView_Previews: PreviewProvider {
static var previews: some View {
LargeMetarView(entry: MetarEntry(date: .now, metars: tempData))
.previewContext(WidgetPreviewContext(family: .systemLarge))
}
}
}
import SwiftUI
import WidgetKit
struct WidgetStationView: View {
var mdm: MetarDataModel
var selectedStation: MetarDataModel?
var metarservice = MetarService()
var body: some View {
HStack {
Text("Metar Data")
}
GroupBox {
VStack(alignment: .leading) {
Text("\(mdm.mairport)")
.font(.headline)
}
} label: {
Label("Metar #\(mdm.mairport)", systemImage: "person")
} // Link(destination: URL(string: "frat://metar/\(entries.mairport)")!)
.padding()
.onOpenURL { url in
guard
url.scheme == "frat",
url.host == "metar",
url.path == mdm.mairport else {
return
}
Task {
// do {
let stationWx = await getStation(with: mdm.mairport)
DispatchQueue.main.async {
print(stationWx)
}
// } catch {
// }
}
} // end of open url
} // end of view
}
func getStation(with apt: String) async -> [MetarDataModel] {
let metarservice = MetarService()
var metars = [MetarDataModel]()
do {
metars = try await metarservice.fetchMetars(metarAPTs: apt)
} catch {
}
return metars
}
I have tried several solutions from stack, reddit, medium, etc., but nothing seems to open the swiftui view I want to. I am new to swiftui as most of my app was developed with UIKit and think I'm dropping the ball with defining the url sheme, host and path? Any help would be appreciated.
I have encountered this problem during the Swift programming. I have this long frame that I created, here it is.
The main idea that this frame will be used in a horizontal Scroll View in different view, like this. It will be opening different view on tap.
Here's the catch. If we want to transition to different view, we need NavigationLink. In order to work NavigationLink needs NavigationView. When we add our LongFrame in NavigationView, this happens
If we tap on it, it will display View, but in small frame
And If we, for example, add our LongFrameScrollView somewhere, It won't even show up sometimes
I will provide the code here. My guess that should be connected to .frame, but without this line of code I can't create this frame(.
// FRAME ITSELF
import SwiftUI
struct LongFrameView: View {
var body: some View {
NavigationView {
NavigationLink {
PlayerView()
} label: {
ZStack {
Rectangle()
.fill(LinearGradient(gradient: Gradient(colors: [Color(red: 0.268, green: 0.376, blue: 0.587), Color(red: 0.139, green: 0.267, blue: 0.517)]),
startPoint: .leading,
endPoint: .trailing))
.frame(width: 310, height: 62)
.cornerRadius(8)
HStack {
Image("mountains")
.resizable()
.aspectRatio(contentMode: .fill)
.frame(width: 70, height: 62)
.cornerRadius(8, corners: [.topLeft, .bottomLeft])
VStack(alignment: .leading) {
Text("Sense of anxiety")
.font(.custom("Manrope-Bold", size: 14))
.foregroundColor(.white)
Text("11 MIN")
.font(.custom("Manrope-Medium", size: 12))
.foregroundColor(.white)
}
Spacer()
}
}
.frame(width: 310, height: 62)
}
}
}
}
struct LongFrameView_Previews: PreviewProvider {
static var previews: some View {
LongFrameView()
}
}
// MARK: - WITH THIS CODE WE CAN DEFINE WHERE CORNER RADIUS WILL BE CHANGED OR NOT. DO NOT MODIFY
extension View {
func cornerRadius(_ radius: CGFloat, corners: UIRectCorner) -> some View {
clipShape( RoundedCorner(radius: radius, corners: corners) )
}
}
struct RoundedCorner: Shape {
var radius: CGFloat = .infinity
var corners: UIRectCorner = .allCorners
func path(in rect: CGRect) -> Path {
let path = UIBezierPath(roundedRect: rect, byRoundingCorners: corners, cornerRadii: CGSize(width: radius, height: radius))
return Path(path.cgPath)
}
}
// SCROLL VIEW WITH FRAMES
import SwiftUI
struct LongFrameScrollView: View {
let rows = Array(repeating: GridItem(.fixed(60), spacing: 10, alignment: .leading), count: 2)
var body: some View {
ScrollView(.horizontal, showsIndicators: false) {
LazyHGrid(rows: rows, spacing: 10) {
// PLACEHOLDER UNTIL API IS READY
LongFrameView()
LongFrameView()
LongFrameView()
LongFrameView()
}
}
.padding([.horizontal, .bottom], 10)
}
}
struct LongFrameScrollView_Previews: PreviewProvider {
static var previews: some View {
LongFrameScrollView()
}
}
NavigationView should be added as the first/top view. So embed your ScrollView with NavigationView inside LongFrameScrollView and removed it from LongFrameView. Inside LongFrameView you just need NavigationLink.
NavigationView {
ScrollView(.horizontal, showsIndicators: false) {
LazyHGrid(rows: rows, spacing: 10) {
// PLACEHOLDER UNTIL API IS READY
LongFrameView()
LongFrameView()
LongFrameView()
LongFrameView()
}
}
.padding([.horizontal, .bottom], 10)
}
I designed a SwiftUI view which is a scrollview. Now I need to add a vertical swipe gesture to it which shall take it to a different view. I tried to do it using the tabView and adding a rotating effect of -90 degrees to it. But that rotates my original view too and that's not what I want. I couldn't find any relevant help in SwiftUI which deals with swiping up a scrollview to a new view.
Here's my code..
the vertical swipe I achieved using this. But my view get rotated. Setting other angles disappears the view somehow. I am new to SwiftUI, I am stuck on it for a week now.1
GeometryReader { proxy in
TabView {
ScrollView {
VStack(alignment: .center) {
ZStack(alignment: .leading) {
Image("Asset 13").resizable().frame(width: percentWidth(percentage: 100), height: percentHeight(percentage: 50), alignment: .top)
HStack {
Spacer()
Image("Asset 1")//.padding(.bottom, 130)
Spacer()
}.padding(.bottom, 150)
HStack {
VStack(spacing:2) {
Text("followers").foregroundColor(.white).padding(.leading, 20)
HStack {
Image("Asset 3")
Text("10.5k").foregroundColor(.white)
}
}
Spacer()
VStack {
Image("Asset 10").padding(.trailing)
Text("300K Review ").foregroundColor(.white)
}
}.background(Image("Asset 2").resizable().frame(width: percentWidth(percentage: 100), height: percentHeight(percentage: 6), alignment: .leading))
.padding(.top, 410)
HStack {
Spacer()
Image("Asset 14").resizable().frame(width: percentWidth(percentage: 50), height: percentHeight(percentage: 25), alignment: .center)
Spacer()
}.padding(.top, 390)
}
VStack(spacing: 4) {
Text("Karuna Ahuja | Yoga Instructor").font(Font.custom(FontName.bold, size: 22))
Text("12 Years of Experience with Bhartiya Yog Sansthan").tracking(-1).font(Font.custom(FontName.light, size: 16)).opacity(0.4)
}
Divider()
HStack {
ZStack {
Image("Asset 6").resizable().frame(width: percentWidth(percentage: 30), height: percentHeight(percentage: 12), alignment: .center)
VStack {
Image("Asset 5").resizable().frame(width: percentWidth(percentage: 8), height: percentHeight(percentage: 4), alignment: .center)
Text("245").font(Font.custom(FontName.bold, size: 16))
Text("Video").font(Font.custom(FontName.medium, size: 16)).opacity(0.5)
}
}
ZStack {
Image("Asset 6").resizable().frame(width: percentWidth(percentage: 30), height: percentHeight(percentage: 12), alignment: .center)
VStack {
Image("Asset 7").resizable().frame(width: percentWidth(percentage: 8), height: percentHeight(percentage: 4), alignment: .center)
Text("45").font(Font.custom(FontName.bold, size: 16))
Text("Live Class").font(Font.custom(FontName.medium, size: 16)).opacity(0.5)
}
}
ZStack {
Image("Asset 6").resizable().frame(width: percentWidth(percentage: 30), height: percentHeight(percentage: 12), alignment: .center)
VStack {
Image("Asset 9").resizable().frame(width: percentWidth(percentage: 8), height: percentHeight(percentage: 4), alignment: .center)
Text("245").font(Font.custom(FontName.bold, size: 16))
Text("Sessions").font(Font.custom(FontName.medium, size: 16)).opacity(0.5)
}
}
}
Divider()
Text("Shine bright so that your light leads other. I'm a fitness junkie, high-energy yoga instructor. Let's make fitness FUN!").font(Font.custom(FontName.normal, size: 16)).tracking(-1).opacity(0.7).padding([.leading,.trailing], 6)
VideoPlayer(player: AVPlayer(url: videoUrl))
.frame(height: 320)
Spacer()
}.gesture(DragGesture(minimumDistance: 20, coordinateSpace: .global)
.onEnded { value in
let horizontalAmount = value.translation.width as CGFloat
let verticalAmount = value.translation.height as CGFloat
if abs(horizontalAmount) > abs(verticalAmount) {
print(horizontalAmount < 0 ? "left swipe" : "right swipe")
} else {
print(verticalAmount < 0 ? "up swipe" : "down swipe")
}
})
}.edgesIgnoringSafeArea(.all)
.ignoresSafeArea()
Text("this")
Text("this")
Text("this")
// ForEach(colors, id: \.self) { color in
// color // Your cell content
// }
// .rotationEffect(.degrees(-90)) // Rotate content
// .frame(
// width: proxy.size.width,
// height: proxy.size.height
// )
}
.frame(
width: proxy.size.height, // Height & width swap
height: proxy.size.width
)
.rotationEffect(.degrees(90), anchor: .topLeading) // Rotate TabView
.offset(x: proxy.size.width) // Offset back into screens bounds
.tabViewStyle(
PageTabViewStyle(indexDisplayMode: .never)
)
}
The only pure SwiftUI way I see is to do your own ScrollView implementation, which is not too complicated. This example has two views on top of each other. If you drag the first view further up than to the middle of the screen, it swipes away to reveal the second view.
struct ContentView: View {
#State private var offset = CGFloat.zero
#State private var dragOffset = CGFloat.zero
#State private var viewHeight = CGFloat.zero
var body: some View {
GeometryReader { fullgeo in
ZStack(alignment: .top) {
SecondView()
// necessary for second view to resize individually
.frame(height: fullgeo.size.height)
ScrollingView()
.overlay( GeometryReader { geo in Color.clear.onAppear { viewHeight = geo.size.height }})
.offset(y: offset + dragOffset)
.gesture(DragGesture()
.onChanged { value in
dragOffset = value.translation.height
}
.onEnded { value in
withAnimation(.easeOut) {
dragOffset = .zero
offset += value.predictedEndTranslation.height
// if bottom dragged higher than 50% of screen > second view
if offset < -(viewHeight - fullgeo.size.height/2) {
dragOffset = -viewHeight
return
}
// else constrain to top / bottom of ScrollingView
offset = max(min(offset, 0), -(viewHeight - fullgeo.size.height))
}
}
)
}
}
}
}
struct ScrollingView: View {
var body: some View {
VStack {
Text("View Top").font(.headline)
ForEach(0..<10) { _ in
Text("Content")
.frame(width: 200, height: 100)
.background(.white)
}
}
.frame(maxWidth: .infinity, maxHeight: .infinity)
.background(.gray)
}
}
struct SecondView: View {
var body: some View {
Text("View Bottom").font(.headline)
.frame(maxWidth: .infinity, maxHeight: .infinity)
.background(.orange)
}
}
Use this code:
import SwiftUI
struct PullToRefreshView: View
{
private static let minRefreshTimeInterval = TimeInterval(0.2)
private static let triggerHeight = CGFloat(100)
private static let indicatorHeight = CGFloat(100)
private static let fullHeight = triggerHeight + indicatorHeight
let backgroundColor: Color
let foregroundColor: Color
let isEnabled: Bool
let onRefresh: () -> Void
#State private var isRefreshIndicatorVisible = false
#State private var refreshStartTime: Date? = nil
init(bg: Color = .neutral0, fg: Color = .neutral90, isEnabled: Bool = true, onRefresh: #escaping () -> Void)
{
self.backgroundColor = bg
self.foregroundColor = fg
self.isEnabled = isEnabled
self.onRefresh = onRefresh
}
var body: some View
{
VStack(spacing: 0)
{
LazyVStack(spacing: 0)
{
Color.clear
.frame(height: Self.triggerHeight)
.onAppear
{
if isEnabled
{
withAnimation
{
isRefreshIndicatorVisible = true
}
refreshStartTime = Date()
}
}
.onDisappear
{
if isEnabled, isRefreshIndicatorVisible, let diff = refreshStartTime?.distance(to: Date()), diff > Self.minRefreshTimeInterval
{
onRefresh()
}
withAnimation
{
isRefreshIndicatorVisible = false
}
refreshStartTime = nil
}
}
.frame(height: Self.triggerHeight)
indicator
.frame(height: Self.indicatorHeight)
}
.background(backgroundColor)
.ignoresSafeArea(edges: .all)
.frame(height: Self.fullHeight)
.padding(.top, -Self.fullHeight)
}
private var indicator: some View
{
ProgressView()
.progressViewStyle(CircularProgressViewStyle(tint: foregroundColor))
.opacity(isRefreshIndicatorVisible ? 1 : 0)
}
}
sample:
ScrollView{
VStack(spacing:0) {
//top of scrollView
PullToRefreshView{
//todo
}
}
}
Help me please to catch how to draw circles on random position in view borders.
Red View options
.background(Color.red)
.padding(40)
Circles:
var body: some View
{
Circle()
.strokeBorder(Color.blue, lineWidth: 2.0, antialiased: true)
.frame(width: 50, height: 50, alignment: .center)
.overlay(Text(title))
}
I try to add circles on red view in random position using .position option, but you can see its not working:
The main problem is how to know width and height of red view on any device and set .position of circles.
You can use GeometryReader for reading the size of View, like in the example:
struct ContentView: View {
var body: some View {
GeometryReader { proxy in
ForEach(0...50, id:\.self) { index in
CirclesView(index: index)
.offset(x: CGFloat.random(in: 0.0...proxy.size.width), y: CGFloat.random(in: 0.0...proxy.size.height))
}
}
.background(Color.red)
.ignoresSafeArea()
}
}
struct CirclesView: View {
let index: Int
var body: some View {
Circle()
.strokeBorder(Color.blue, lineWidth: 2.0, antialiased: true)
.frame(width: 50, height: 50, alignment: .center)
.overlay(Text(String(describing: index)))
}
}
Update:
struct ContentView: View {
var body: some View {
GeometryReader { proxy in
ForEach(0...50, id:\.self) { index in
CirclesView(index: index, offset: logicalFunction(size: proxy.size))
}
}
.background(Color.red)
.ignoresSafeArea()
}
func logicalFunction(size: CGSize) -> CGSize {
// Do your works here!
let width: CGFloat = CGFloat.random(in: 0.0...size.width)
let height: CGFloat = CGFloat.random(in: 0.0...size.height)
return CGSize(width: width, height: height)
}
}
struct CirclesView: View {
let index: Int
let offset: CGSize
var body: some View {
Circle()
.strokeBorder(Color.blue, lineWidth: 2.0, antialiased: true)
.frame(width: 50, height: 50, alignment: .center)
.overlay(Text(String(describing: index)))
.offset(offset)
}
}
I need to make such a simple thing, but can't figure out how.
So I need to create a View which I already have inside another view. Here how it looks like now ↓
Here's my button:
struct CircleButton: View {
var body: some View {
Button(action: {
self
}, label: {
Text("+")
.font(.system(size: 42))
.frame(width: 57, height: 50)
.foregroundColor(Color.white)
.padding(.bottom, 7)
})
.background(Color(#colorLiteral(red: 0.4509803922, green: 0.8, blue: 0.5490196078, alpha: 1)))
.cornerRadius(50)
.padding()
.shadow(color: Color.black.opacity(0.15),
radius: 3,
x: 0,
y: 4)
}
}
Here's a view which I want to place when I tap the button ↓
struct IssueCardView: View {
var body: some View {
ZStack (alignment: .leading) {
Rectangle()
.fill(Color.white)
.frame(height: 50)
.shadow(color: .black, radius: 20, x: 0, y: 4)
.cornerRadius(8)
VStack (alignment: .leading) {
Rectangle()
.fill(Color(#colorLiteral(red: 0.6550863981, green: 0.8339114785, blue: 0.7129291892, alpha: 1)))
.frame(width: 30, height: 8)
.cornerRadius(8)
.padding(.horizontal, 10)
Text("Some text on card here")
.foregroundColor(Color(UIColor.dark.main))
.font(.system(size: 14))
.fontWeight(.regular)
.padding(.horizontal, 10)
}
}
}
}
Here's a view where I want to place this IssueCardView ↓. Instead of doing it manually like now I want to generate this View with button.
struct TaskListView: View {
var body: some View {
ScrollView(.vertical, showsIndicators: false, content: {
VStack (alignment: .leading, spacing: 8) {
**IssueCardView()
IssueCardView()
IssueCardView()
IssueCardView()
IssueCardView()**
}
.frame(minWidth: 320, maxWidth: 500, minHeight: 500, maxHeight: .infinity, alignment: .topLeading)
.padding(.horizontal, 0)
})
}
}
Although it works with scrollView and stack, You should use a List for these kind of UI issues (as you already mentioned in the name of TaskListView)
struct TaskListView: View {
typealias Issue = String // This is temporary, because I didn't have the original `Issue` type
#State var issues: [Issue] = ["Some issue", "Some issue"]
var body: some View {
ZStack {
List(issues, id: \.self) { issue in
IssueCardView()
}
CircleButton {
self.issues += ["new issue"]
}
}
}
}
I have added let action: ()->() to CircleButton. So I can pass the action to it.