i have this card thing in the picture to build, here're the code:
struct ArticleCard: View {
var article: Article
var body: some View {
ZStack {
Color.white
.border(Color(red: 0, green: 0, blue: 0, opacity: 0.2))
.shadow(color: Color(red: 0, green: 0, blue: 0, opacity: 0.2), radius: 0.0, x: 5, y: 5)
VStack{
Text(article.title)
.padding(.top, 5)
.padding(.leading)
.padding(.trailing)
.font(.title2)
Image(article.coverUrl).resizable()
.frame(height: 200)
.padding(.leading)
.padding(.trailing)
Text(article.title)
.padding(.leading)
.padding(.trailing)
.padding(.bottom)
}
}
}
}
in the ZStack i put a Color.white there as a background of the card, and give this color view a shadow, but the color seems to be transparent, therefor i got unwanted lines on the top and the left inside the borders, how do i get rid of them?
You are using border and shadow in wrong place, try this:
PS: there is no reason of using Color(red: 0, green: 0, blue: 0, opacity: 0.2) you can use this: Color.black.opacity(0.2)
import SwiftUI
struct ContentView: View {
var body: some View {
ZStack {
Color.white
VStack {
Text("article.title")
.padding()
Image(systemName: "star")
.resizable()
.scaledToFit()
Text("article.title")
.padding()
}
}
.frame(width: 300, height: 300, alignment: .center)
.border(Color(red: 0, green: 0, blue: 0, opacity: 0.2))
.compositingGroup()
.shadow(color: Color(red: 0, green: 0, blue: 0, opacity: 0.2), radius: 0.0, x: 5, y: 5)
}
}
I refactored your code for better and less code as possible you can use Image instead of Text in your App.
import SwiftUI
struct ContentView: View {
var body: some View {
VStack {
Text("your custom Text")
.padding()
Text("🥩")
.font(Font.system(size: 150))
Text("your custom Text")
.padding()
}
.frame(width: 300, height: 300, alignment: .center)
.background(Color.white)
.border(Color.black.opacity(0.2))
.compositingGroup()
.shadow(color: Color.black.opacity(0.2), radius: 0.0, x: 5, y: 5)
}
}
Related
Currently, my code uses a series of switch result cases that asks questions and presents different answer choices. For example, when the user clicks Evening, the code will present a new question with the answer choices being "Sweet" and "Savory". How can I put a cool transition where the "Morning" and "Evening" choices turn into the "Sweet" and "Savory" choices? Open to any transitions that you'd recommend.
var body: some View {
let cardWidth = 300
let cardWidthValue = CGFloat(cardWidth)
let cardHeight = 300
let cardHeightValue = CGFloat(cardHeight)
VStack {
ZStack {
Rectangle()
.fill(Color(red: 0.0, green: 0.5, blue: 1.0, opacity: 0.4))
.frame(width: 350, height: 250)
.cornerRadius(20)
.shadow(color: .gray, radius: 20)
switch result {
case "Start":
VStack{
Text("What time is it?")
.padding()
.foregroundColor(Color.white)
.font(.system(size: 30.0, weight: .bold))
HStack {
Button {
result = "M"
} label: {
Text("Morning🌥")
.foregroundColor(Color.white)
.frame(width: 165, height: 100)
.background(Color(red: 0.0, green: 0.0, blue: 1.0, opacity: 1.0))
.cornerRadius(10)
}
Button {
result = "E"
} label: {
Text("Evening☀️")
.foregroundColor(Color.white)
.frame(width: 165, height: 100)
.background(Color(red: 0.0, green: 0.0, blue: 1.0, opacity: 1.0))
.cornerRadius(10)
}
}
}
case "E":
VStack{
Text("Sweet or Savory?")
.padding()
.foregroundColor(Color.white)
.font(.system(size: 30.0, weight: .bold))
HStack {
Button {
result = "EveningSweet"
} label: {
Text("Sweet🍦")
}
.foregroundColor(Color.white)
.frame(width: 165, height: 100)
.background(Color(red: 0.0, green: 0.0, blue: 1.0, opacity: 1.0))
.cornerRadius(10)
Button {
result = "EveningSavory"
} label: {
Text("Savory🧂")
}
.foregroundColor(Color.white)
.frame(width: 165, height: 100)
.background(Color(red: 0.0, green: 0.0, blue: 1.0, opacity: 1.0))
.cornerRadius(10)
}
}
Using withAnimation{} to animate your event.
Let's say you want to animate views after you click on Evening:
Button {
withAnimation { //here
result = "E"
}
} label: {
Text("Evening☀️")
.foregroundColor(Color.white)
.frame(width: 165, height: 100)
.background(Color(red: 0.0, green: 0.0, blue: 1.0, opacity: 1.0))
.cornerRadius(10)
}
This mean that all views that are related to this event of result = "E" shall be animated. The default transition of all animation is .opacity.
After trying the first case, if you want to change transition type, use .transition()
case "E":
VStack {
}.transition(.slide)
You will see a different animation from the first time that you did not set transition equals to slide.
I would recommend you try the first option without .slide first to see the difference.
I've created a progress circle for my App, that will count down from 28 to 0 (number of days until Payday)
I've got the circles to display how I'd like, but I want it to animate when I navigate to the view, is there a way to do this?
More a UI question, but do you think maybe an arrow within the circle to indicate the direction would look any good?
P.s - any ideas how to truncate all the zeros off my Double?
image of how this looks
Thanks!
ZStack {
let progressPeriod = Double(PayData.daysUntilPay) ?? 0
let progressPeriod2 = 1 - (progressPeriod / 28)
Circle()
.stroke(lineWidth: 30.0)
.opacity(0.3)
.foregroundColor(Color(red: 0.941, green: 0.426, blue: 0.004))
.frame(width:150)
.frame(height: 200)
Circle()
.trim(from: 0.0, to: progressPeriod2)
.stroke(style: StrokeStyle(lineWidth: 30.0, lineCap: .round, lineJoin: .round))
.foregroundColor(Color(red: 0.941, green: 0.426, blue: 0.004))
.rotationEffect(Angle(degrees: 270.0))
.frame(width:150)
.frame(height: 200)
Text("\(progressPeriod) days")
.bold()
}
Try to combine following code with your countdown:
struct ContentView: View {
#State var progressValue: Float = 0.0
var body: some View {
ZStack {
Color.yellow
.opacity(0.1)
.edgesIgnoringSafeArea(.all)
VStack {
ProgressBar(progress: self.$progressValue)
.frame(width: 150.0, height: 150.0)
.padding(40.0)
Button(action: {
self.incrementProgress()
}) {
HStack {
Image(systemName: "plus.rectangle.fill")
Text("Increment")
}
.padding(15.0)
.overlay(
RoundedRectangle(cornerRadius: 15.0)
.stroke(lineWidth: 2.0)
)
}
Spacer()
}
}
}
func incrementProgress() {
let randomValue = Float([0.012, 0.022, 0.034, 0.016, 0.11].randomElement()!)
self.progressValue += randomValue
}
}
struct ProgressBar: View {
#Binding var progress: Float
var body: some View {
ZStack {
Circle()
.stroke(lineWidth: 20.0)
.opacity(0.3)
.foregroundColor(Color.red)
Circle()
.trim(from: 0.0, to: CGFloat(min(self.progress, 1.0)))
.stroke(style: StrokeStyle(lineWidth: 20.0, lineCap: .round, lineJoin: .round))
.foregroundColor(Color.red)
.rotationEffect(Angle(degrees: 270.0))
.animation(.linear)
Text(String(format: "%.0f %%", min(self.progress, 1.0)*100.0))
.font(.largeTitle)
.bold()
}
}
}
I have the following code:
struct ViewA: View {
var body: some View {
Rectangle()
.fill(Color(.yellow))
}
}
struct ViewB: View {
var body: some View {
Rectangle()
.fill(Color(.white))
}
}
struct ViewC: View {
var body: some View {
Rectangle()
.fill(Color(.blue))
}
}
struct TestView: View {
var body: some View {
GeometryReader { geo in
VStack(spacing: 0) {
ViewA()
.frame(width: geo.size.width, height: geo.size.width/4, alignment: .center)
.shadow(color: .black, radius: 10, x: 0, y: 10)
ViewB()
ViewC()
.frame(width: geo.size.width, height: 100, alignment: .center)
.shadow(color: .black, radius: 10, x: 0, y: 0)
.opacity(0.8)
}
}
}
}
It draws:
The shadow at the bottom Blue over White view (ViewC over ViewB) shows up.
I want the yellow view (ViewA) to drop a shadow on top of the white view.
I want the white view to appear as if it were under both the top view (yellow) and the bottom view (blue).
I am not sure how to organize the views so that the top view also drops shadow on the middle view.
How would I accomplish this?
You could apply zindex modifier to ViewA. For example .zIndex(.infinity). It will put ViewA on top of everything.
https://developer.apple.com/documentation/swiftui/view/zindex(_:)
If you place the views in a ZStack with ViewB behind ViewA and ViewC you will see the shadow:
GeometryReader { geo in
ZStack {
ViewB()
VStack(spacing: 0) {
ViewA()
.frame(
width: geo.size.width,
height: geo.size.width/4,
alignment: .center)
.shadow(
color: .black,
radius: 10,
x: 0, y: 0)
Spacer()
ViewC()
.frame(
width: geo.size.width,
height: 100,
alignment: .center)
.shadow(
color: .black,
radius: 10,
x: 0, y: 0)
.opacity(0.8)
}
}
}
I am trying to create a medium Widget like in YouTube Music, but I am don't understand how to create an interaction with the particular item in a Widget. How my app should understand when user press on first or second item and then how I am must handle this action inside app. My app use Swift not SwiftUI, only for a Widget I use SwiftUI. In past I didn't have experience with a SwityUI.
My code for Widget:
struct WidgetTestEntryView : View {
var entry: Provider.Entry
var body: some View {
VStack {
HStack(spacing: 100){
Text("Favourite").foregroundColor(.white).font(.system(size: 16, weight: .bold, design: .default))
Image("Label").resizable().frame(width: 80, height: 15, alignment: /*#START_MENU_TOKEN#*/.center/*#END_MENU_TOKEN#*/)
}.frame(maxWidth: .infinity, maxHeight: 50, alignment: .center).background(Color.black).offset(y: -9)
HStack {
Spacer()
Button(action: {}) {
Image("").resizable().frame(width: 70, height: 70)
.cornerRadius(10)
.background(Color(red: 0.218, green: 0.215, blue: 0.25))
}.cornerRadius(10).onTapGesture {
let a = ViewController()
a.data.text = "Tap"
}
Button(action: {}) {
Image("").resizable().frame(width: 70, height: 70)
.cornerRadius(10)
.background(Color(red: 0.218, green: 0.215, blue: 0.25))
}.cornerRadius(10).onTapGesture {
let a = ViewController()
a.data.text = "Tap"
}
Button(action: {}) {
Image("").resizable().frame(width: 70, height: 70)
.cornerRadius(10)
.background(Color(red: 0.218, green: 0.215, blue: 0.25))
}.cornerRadius(10).onTapGesture {
let a = ViewController()
a.data.text = "Tap"
}
Button(action: {}) {
Image("").resizable().frame(width: 70, height: 70)
.cornerRadius(10)
.background(Color(red: 0.218, green: 0.215, blue: 0.25))
}.cornerRadius(10).onTapGesture {
let a = ViewController()
a.data.text = "Tap"
}
Spacer().frame(width: 10, height: 10, alignment: .center)
}.background(Color(red: 0.118, green: 0.118, blue: 0.15)).offset(y: -9)
}.frame(maxWidth: .infinity, maxHeight: .infinity, alignment: .center).background(Color(red: 0.118, green: 0.118, blue: 0.15))
}
}
You can do this using Link in SwiftUI.
Link(destination: url, label: {
// add your UI components in this block on which you want to perform click action.
}
url: Provide a unique string to identify widget action in the main app.
Now In the main app, use below method in AppDelegate.swift file:
func application(_ app: UIApplication, open url: URL, options: [UIApplication.OpenURLOptionsKey : Any] = [:]) -> Bool {
}
In this method, you can identify the URL that comes from the WidgetKit action.
It seems there is a potential bug in SwiftUI. I am trying to put a rectangle with opacity 0.5 on top of an image.
When I try to fix the transparent rectangle on top, from 100px width, it goes down instead of sticking to the top.
Here is the code:
ZStack {
VStack {
Image("movistar")
.resizable(capInsets: EdgeInsets(), resizingMode: .stretch)
.scaledToFit()
.cornerRadius(8)
.padding(15)
.frame(minWidth: Global.SCREEN_WIDTH)
}
VStack {
HStack {
Rectangle()
.fill(Color(red: 0, green: 0, blue: 0, opacity: 0.5))
.frame(width: 110, height: Global.SCREEN_WIDTH / 4)
}
Spacer()
}
.scaledToFit()
.cornerRadius(8)
.padding(15)
.frame(width: Global.SCREEN_WIDTH, height: Global.SCREEN_WIDTH)
There is no bug here. If you add a .background to all of your layers, you will see that because of the way you set up the view (ie. Spacer, scaledToFit, etc.) the actual frames of the views are not necessarily the edges of the image. You also have not set the alignment of any of the Stacks or Frames.
There are many ways to do what you are trying to do, but I believe this is the simplest:
var body: some View {
Image("movistar")
.resizable(capInsets: EdgeInsets(), resizingMode: .stretch)
.scaledToFit()
.cornerRadius(8)
.frame(minWidth: UIScreen.main.bounds.width)
.overlay(
Rectangle()
.fill(Color(red: 0, green: 0, blue: 0, opacity: 0.5))
.frame(width: 110, height: UIScreen.main.bounds.width / 4)
, alignment: .top
)
}
Finally got into a solution: .scaleToFit() was messing with the VStack(). After deleting, it worked perfectly. I also got rid of the HStack().