I made a struct that styles my buttons by passing a type and size parameters. I would like the button to change style when it's disabled, but it's not working. The button does toggle between disabled and enabled, but the style is always the enabled style.
struct CustomButton: ButtonStyle {
enum ButtonStyle {
case button, destructive, light
}
enum ButtonSize {
case normal, large, small
}
#Environment(\.isEnabled) var isEnabled
private var maxWidth : CGFloat
private var padding : CGFloat
private var foreground : Color
private var foregroundDisabled : Color
private var strokeColor : Color
private var strokeDisabled : Color
private var strokeWidth : CGFloat
private var background : Color
private var backgroundDisabled : Color
private var fontSize : Font
init(style: ButtonStyle, size: ButtonSize) {
switch size {
case .large:
self.maxWidth = .infinity
self.padding = 15.0
self.fontSize = Font.system(.title3, design: .rounded).weight(.bold)
case .small:
self.maxWidth = 200
self.padding = 8.0
self.fontSize = Font.system(.callout, design: .rounded)
default:
self.maxWidth = .infinity
self.padding = 12.0
self.fontSize = Font.system(.body, design: .rounded)
}
switch style {
case .light:
strokeColor = .main
strokeDisabled = .gray
strokeWidth = size == .small ? strokeSmall: strokeLarge
foreground = .main
foregroundDisabled = .gray
background = .clear
backgroundDisabled = .clear
case .destructive:
strokeColor = .destructive
strokeDisabled = .gray
strokeWidth = size == .small ? strokeSmall : strokeLarge
foreground = .destructive
foregroundDisabled = .destructive
background = .clear
backgroundDisabled = .clear
default:
strokeColor = .clear
strokeDisabled = .clear
strokeWidth = 0.0
foreground = .white
foregroundDisabled = .white
backgroundDisabled = .gray
background = .main
}
}
func makeBody(configuration: Self.Configuration) -> some View {
return configuration.label
.frame(maxWidth: maxWidth)
.font(fontSize)
.foregroundColor(isEnabled ? foreground : Color.red)
.padding(padding)
.background(RoundedRectangle(cornerRadius: roundedCorner)
.strokeBorder(isEnabled ? strokeColor : strokeDisabled, lineWidth: strokeWidth)
.background(isEnabled ? background : backgroundDisabled)
)
.clipShape(RoundedRectangle(cornerRadius: roundedCorner))
.opacity(configuration.isPressed ? 0.8 : 1.0)
.scaleEffect(configuration.isPressed ? 0.98 : 1.0)
}
}
And it's added to a view like this:
Button(action: {
//Some logic here
}, label: {
Text(NSLocalizedString("Add Group", comment: "button"))
})
.disabled(selections.count < 2) //the button does become disabled (but doesn't change style)
.buttonStyle(CustomButton(style: .button, size: .normal))
The #Environment is not injected in style, it is only for views, so here a demo of possible solution - based on internal helping wrapper view.
struct CustomButton: ButtonStyle {
enum ButtonStyle {
case button, destructive, light
}
enum ButtonSize {
case normal, large, small
}
private var maxWidth : CGFloat
private var padding : CGFloat
private var foreground : Color
private var foregroundDisabled : Color
private var strokeColor : Color
private var strokeDisabled : Color
private var strokeWidth : CGFloat
private var background : Color
private var backgroundDisabled : Color
private var fontSize : Font
init(style: ButtonStyle, size: ButtonSize) {
switch size {
case .large:
self.maxWidth = .infinity
self.padding = 15.0
self.fontSize = Font.system(.title3, design: .rounded).weight(.bold)
case .small:
self.maxWidth = 200
self.padding = 8.0
self.fontSize = Font.system(.callout, design: .rounded)
default:
self.maxWidth = .infinity
self.padding = 12.0
self.fontSize = Font.system(.body, design: .rounded)
}
switch style {
case .light:
strokeColor = .main
strokeDisabled = .gray
strokeWidth = size == .small ? strokeSmall: strokeLarge
foreground = .main
foregroundDisabled = .gray
background = .clear
backgroundDisabled = .clear
case .destructive:
strokeColor = .destructive
strokeDisabled = .gray
strokeWidth = size == .small ? strokeSmall : strokeLarge
foreground = .destructive
foregroundDisabled = .destructive
background = .clear
backgroundDisabled = .clear
default:
strokeColor = .clear
strokeDisabled = .clear
strokeWidth = 0.0
foreground = .white
foregroundDisabled = .white
backgroundDisabled = .gray
background = .main
}
}
private struct EnvReaderView<Content: View>: View { // << this one !!
let content: (Bool) -> Content
#Environment(\.isEnabled) var isEnabled // read environment
var body: some View {
content(isEnabled) // transfer into builder
}
}
func makeBody(configuration: Self.Configuration) -> some View {
EnvReaderView { isEnabled in // now we can use it !!
configuration.label
.frame(maxWidth: maxWidth)
.font(fontSize)
.foregroundColor(isEnabled ? foreground : Color.red)
.padding(padding)
.background(RoundedRectangle(cornerRadius: roundedCorner)
.strokeBorder(isEnabled ? strokeColor : strokeDisabled, lineWidth: strokeWidth)
.background(isEnabled ? background : backgroundDisabled)
)
.clipShape(RoundedRectangle(cornerRadius: roundedCorner))
.opacity(configuration.isPressed ? 0.8 : 1.0)
.scaleEffect(configuration.isPressed ? 0.98 : 1.0)
}
}
}
Related
I have my own Button control, very similar to swift 5.
My protocol:
public protocol RoundedButtonDelegate {
func click(button:RoundedButton)
}
My control:
public struct RoundedButton : View {
public var text:String = ""
public var backgroundColor:String = ""
public var borderColor:String = ""
public var textColor:String = ""
public var width:CGFloat = 0
public var height:CGFloat = 0
public var fontSize:CGFloat = 0
public var delegate:RoundedButtonDelegate?
public var controlId:String = ""
init(id:String = "", text:String, width:CGFloat, height:CGFloat, fontSize:CGFloat = 19, theme: Theme = Theme.light, delegate:RoundedButtonDelegate?) {
if theme == Theme.light {
self.backgroundColor = LightColorSchema.mainColor.rawValue
self.borderColor = LightColorSchema.mainText.rawValue
self.textColor = LightColorSchema.mainText.rawValue
}
if theme == Theme.dark {
self.backgroundColor = DarkColorSchema.mainColor.rawValue
self.borderColor = DarkColorSchema.mainText.rawValue
self.textColor = DarkColorSchema.mainText.rawValue
}
self.controlId = id
self.text = text
self.width = width
self.height = height
self.fontSize = fontSize
self.delegate = delegate
}
public var body: some View {
ZStack {
Button(action: {
print(">Redirect to next page")
self.delegate?.click(button: self)
}) {
HStack(alignment: .center, spacing: 5.0) {
Text(self.text)
.font(.custom("Montserrat-SemiBold", size: self.fontSize))
.foregroundColor(Color.init(hex: self.textColor))
.padding(.all, 10.0)
}
//.frame(width: UIScreen.main.bounds.width - 80, height: 48, alignment: .center)
}
.padding(.all, 10)
.frame(width: self.width, height: self.height, alignment: .center)
.overlay(
RoundedRectangle(cornerRadius: self.height / 2)
.stroke(Color.init(hex: self.borderColor), lineWidth: 1)
).background(RoundedRectangle(cornerRadius: 40).fill(Color.init(hex: self.backgroundColor)))
}
.frame(width: self.width, height: self.height, alignment: .center)
}
}
This is not an special control, is just to define some UI componentes. Well, in my view I have the implementation like:
func click(button: RoundedButton) {
print("Execute protocol")
switch button.controlId {
case "btnSesion":
return
case "btnTarjeta":
return self.redirectSeleccionarTarjeta() //Here is accessing!
default:
print("No defined action")
}
}
And this is the method that I need to solve:
func redirectSeleccionarTarjeta() {
print(">Redirect")
self.showLinkTarget = true
//self.navigate(to: InicioSolicitarTarjetaView(), when: $showLinkTarget)
self.fullScreenCover(isPresented: $showLinkTarget, content: {
InicioSolicitarTarjetaView()
})
// NavigationLink(destination: InicioSolicitarTarjetaView(), isActive: self.$showLinkTarget ) {
// Spacer().fixedSize()
// }
}
How can I redirect to another view from a delegate action? Is that possible?
I tried in several ways, but no luck
Rather than using self.fullScreenCover in your button callback, you need to actually use it in your view hierarchy. Then, just change the showLinkTarget value in your callback. The next time the view is rendered, the fullScreenCover should be presented.
Simplified example:
#State var showWindow = false
Button(action: {
showWindow.toggle()
}) {
Text("Open window")
}.fullScreenCover(isPresented: $showWindow, content: {
Text("Content")
})
Note that this is within the view hierarchy -- not the button's action callback.
See more detailed info about using fullScreenCover: https://www.hackingwithswift.com/quick-start/swiftui/how-to-present-a-full-screen-modal-view-using-fullscreencover
Can you please help updating the code to move the green image text "One thing is for sure ....." just above its original position only once the first animation has terminated ?
(for instance just below the "Toggle" text)
Thanks,
Olivier
Can you please help updating the code to move the green image text "One thing is for sure ....." just above its original position only once the first animation has terminated ?
(for instance just below the "Toggle" text)
import SwiftUI
struct ContentView : View {
// #EnvironmentObject var showBack: Bool
#State var showBack = false
var body : some View {
VStack() {
ContentViewTest()
Spacer()
Text(String(self.showBack))
}
}
}
struct ContentViewTest : View {
#State var showBack = false
let sample1 = "If you know you have an unpleasant nature and dislike people, this is no obstacle to work."
let sample2 = "One thing is for sure – a sheep is not a creature of the air."
var body : some View {
let front = CardFace(text: sample1, background: Color.yellow)
let back = CardFace(text: sample2, background: Color.green)
let resetBackButton = Button(action: { self.showBack = true }) { Text("Back")}.disabled(showBack == true)
let resetFrontButton = Button(action: { self.showBack = false }) { Text("Front")}.disabled(showBack == false)
let animatedToggle = Button(action: {
withAnimation(Animation.linear(duration: 0.8)) {
self.showBack.toggle()
}
}) { Text("Toggle")}
return
VStack() {
HStack() {
resetFrontButton
Spacer()
animatedToggle
Spacer()
resetBackButton
}.padding()
Spacer()
Spacer()
Spacer()
Spacer()
FlipView(front: front, back: back, showBack: $showBack)
}
}
}
struct FlipView<SomeTypeOfViewA : View, SomeTypeOfViewB : View> : View {
var front : SomeTypeOfViewA
var back : SomeTypeOfViewB
#State private var flipped = false
#Binding var showBack : Bool
var body: some View {
return VStack {
Spacer()
ZStack() {
front.opacity(flipped ? 0.0 : 1.0)
back.opacity(flipped ? 1.0 : 0.0)
}
.modifier(FlipEffect(flipped: $flipped, angle: showBack ? 180 : 0, axis: (x: 1, y: 0)))
.onTapGesture {
withAnimation(Animation.linear(duration: 0.8)) {
self.showBack.toggle()
}
}
Spacer()
}
}
}
struct CardFace<SomeTypeOfView : View> : View {
var text : String
var background: SomeTypeOfView
var body: some View {
Text(text)
.multilineTextAlignment(.center)
.padding(5).frame(width: 250, height: 150).background(background)
}
}
struct FlipEffect: GeometryEffect {
var animatableData: Double {
get { angle }
set { angle = newValue }
}
#Binding var flipped: Bool
var angle: Double
let axis: (x: CGFloat, y: CGFloat)
func effectValue(size: CGSize) -> ProjectionTransform {
DispatchQueue.main.async {
self.flipped = self.angle >= 90 && self.angle < 270
}
let tweakedAngle = flipped ? -180 + angle : angle
let a = CGFloat(Angle(degrees: tweakedAngle).radians)
var transform3d = CATransform3DIdentity;
transform3d.m34 = -1/max(size.width, size.height)
transform3d = CATransform3DRotate(transform3d, a, axis.x, axis.y, 0)
transform3d = CATransform3DTranslate(transform3d, -size.width/2.0, -size.height/2.0, 0)
let affineTransform = ProjectionTransform(CGAffineTransform(translationX: size.width/2.0, y: size.height / 2.0))
return ProjectionTransform(transform3d).concatenating(affineTransform)
}
}
struct ContentView_Previews: PreviewProvider {
static var previews: some View {
ContentView()
}
}
I have text but it's not fit. I want use marquee when text not fit in my default frame.
Text(self.viewModel.soundTrack.title)
.font(.custom("Avenir Next Regular", size: 24))
.multilineTextAlignment(.trailing)
.lineLimit(1)
.foregroundColor(.white)
.fixedSize(horizontal: false, vertical: true)
//.frame(width: 200.0, height: 30.0)
Try below code....
In MarqueeText.swift
import SwiftUI
struct MarqueeText: View {
#State private var leftMost = false
#State private var w: CGFloat = 0
#State private var previousText: String = ""
#State private var contentViewWidth: CGFloat = 0
#State private var animationDuration: Double = 5
#Binding var text : String
var body: some View {
let baseAnimation = Animation.linear(duration: self.animationDuration)//Animation duration
let repeated = baseAnimation.repeatForever(autoreverses: false)
return VStack(alignment:.center, spacing: 0) {
GeometryReader { geometry in//geometry.size.width will provide container/superView width
Text(self.text).font(.system(size: 24)).lineLimit(1).foregroundColor(.clear).fixedSize(horizontal: true, vertical: false).background(TextGeometry()).onPreferenceChange(WidthPreferenceKey.self, perform: {
self.w = $0
print("textWidth:\(self.w)")
print("geometry:\(geometry.size.width)")
self.contentViewWidth = geometry.size.width
if self.text.count != self.previousText.count && self.contentViewWidth < self.w {
let duration = self.w/50
print("duration:\(duration)")
self.animationDuration = Double(duration)
self.leftMost = true
} else {
self.animationDuration = 0.0
}
self.previousText = self.text
}).fixedSize(horizontal: false, vertical: true)// This Text is temp, will not be displayed in UI. Used to identify the width of the text.
if self.animationDuration > 0.0 {
Text(self.text).font(.system(size: 24)).lineLimit(nil).foregroundColor(.green).fixedSize(horizontal: true, vertical: false).background(TextGeometry()).onPreferenceChange(WidthPreferenceKey.self, perform: { _ in
if self.text.count != self.previousText.count && self.contentViewWidth < self.w {
} else {
self.leftMost = false
}
self.previousText = self.text
}).modifier(self.makeSlidingEffect().ignoredByLayout()).animation(repeated, value: self.leftMost).clipped(antialiased: true).offset(y: -8)//Text with animation
}
else {
Text(self.text).font(.system(size: 24)).lineLimit(1).foregroundColor(.blue).fixedSize(horizontal: true, vertical: false).background(TextGeometry()).fixedSize(horizontal: false, vertical: true).frame(maxWidth: .infinity, alignment: .center).offset(y: -8)//Text without animation
}
}
}.fixedSize(horizontal: false, vertical: true).layoutPriority(1).frame(maxHeight: 50, alignment: .center).clipped()
}
func makeSlidingEffect() -> some GeometryEffect {
return SlidingEffect(
xPosition: self.leftMost ? -self.w : self.w,
yPosition: 0).ignoredByLayout()
}
}
struct MarqueeText_Previews: PreviewProvider {
#State static var myCoolText = "myCoolText"
static var previews: some View {
MarqueeText(text: $myCoolText)
}
}
struct SlidingEffect: GeometryEffect {
var xPosition: CGFloat = 0
var yPosition: CGFloat = 0
var animatableData: CGFloat {
get { return xPosition }
set { xPosition = newValue }
}
func effectValue(size: CGSize) -> ProjectionTransform {
let pt = CGPoint(
x: xPosition,
y: yPosition)
return ProjectionTransform(CGAffineTransform(translationX: pt.x, y: pt.y)).inverted()
}
}
struct TextGeometry: View {
var body: some View {
GeometryReader { geometry in
return Rectangle().fill(Color.clear).preference(key: WidthPreferenceKey.self, value: geometry.size.width)
}
}
}
struct WidthPreferenceKey: PreferenceKey {
static var defaultValue = CGFloat(0)
static func reduce(value: inout CGFloat, nextValue: () -> CGFloat) {
value = nextValue()
}
typealias Value = CGFloat
}
struct MagicStuff: ViewModifier {
func body(content: Content) -> some View {
Group {
content.alignmentGuide(.underlineLeading) { d in
return d[.leading]
}
}
}
}
extension HorizontalAlignment {
private enum UnderlineLeading: AlignmentID {
static func defaultValue(in d: ViewDimensions) -> CGFloat {
return d[.leading]
}
}
static let underlineLeading = HorizontalAlignment(UnderlineLeading.self)
}
In your existing SwiftUI struct.
(The below sample code will check 3 cases 1.Empty string, 2.Short string that doesn't need to marquee, 3.Lengthy marquee string)
#State var value = ""
#State var counter = 0
var body: some View {
VStack {
Spacer(minLength: 0)
Text("Monday").background(Color.yellow)
HStack {
Spacer()
VStack {
Text("One").background(Color.blue)
}
VStack {
MarqueeText(text: $value).background(Color.red).padding(.horizontal, 8).clipped()
}
VStack {
Text("Two").background(Color.green)
}
Spacer()
}
Text("Tuesday").background(Color.gray)
Spacer(minLength: 0)
Button(action: {
self.counter = self.counter + 1
if (self.counter % 2 == 0) {
self.value = "1Hello World! Hello World! Hello World! Hello World! Hello World!"
} else {
self.value = "1Hello World! Hello"
}
}) {
Text("Button")
}
Spacer()
}
}
Install https://github.com/SwiftUIKit/Marquee 0.2.0 above
with Swift Package Manager and try below code....
struct ContentView: View {
var body: some View {
Marquee {
Text("Hello World!")
.font(.system(size: 40))
}
// This is the key point.
.marqueeWhenNotFit(true)
}
}
When you keep increasing the length of the text until it exceeds the width of the marquee, the marquee animation will automatically start.
I was looking for the same thing, but every solution I tried either did not meet my specifications or caused layout/rendering issues, especially when the text changed or the parent view was refreshed. I ended up just writing something from scratch. It is quite hack-y, but it seems to be working now. I would welcome any suggestions on how it can be improved!
import SwiftUI
struct Marquee: View {
#ObservedObject var controller:MarqueeController
var body: some View {
VStack {
if controller.changing {
Text("")
.font(Font(controller.font))
} else {
if !controller.shouldAnimate {
Text(controller.text)
.font(Font(controller.font))
} else {
AnimatedText(controller: controller)
}
}
}
.onAppear() {
self.controller.checkForAnimation()
}
.onReceive(controller.$text) {_ in
self.controller.checkForAnimation()
}
}
}
struct AnimatedText: View {
#ObservedObject var controller:MarqueeController
var body: some View {
Text(controller.text)
.font(Font(controller.font))
.lineLimit(1)
.fixedSize()
.offset(x: controller.animate ? controller.initialOffset - controller.offset : controller.initialOffset)
.frame(width:controller.maxWidth)
.mask(Rectangle())
}
}
class MarqueeController:ObservableObject {
#Published var text:String
#Published var animate = false
#Published var changing = true
#Published var offset:CGFloat = 0
#Published var initialOffset:CGFloat = 0
var shouldAnimate:Bool {text.widthOfString(usingFont: font) > maxWidth}
let font:UIFont
var maxWidth:CGFloat
var textDoubled = false
let delay:Double
let duration:Double
init(text:String, maxWidth:CGFloat, font:UIFont = UIFont.systemFont(ofSize: 12), delay:Double = 1, duration:Double = 3) {
self.text = text
self.maxWidth = maxWidth
self.font = font
self.delay = delay
self.duration = duration
}
func checkForAnimation() {
if shouldAnimate {
let spacer = " "
if !textDoubled {
self.text += (spacer + self.text)
self.textDoubled = true
}
let textWidth = self.text.widthOfString(usingFont: font)
self.initialOffset = (textWidth - maxWidth) / 2
self.offset = (textWidth + spacer.widthOfString(usingFont: font)) / 2
}
DispatchQueue.main.asyncAfter(deadline: .now() + 0.1) {
self.changing = false
DispatchQueue.main.asyncAfter(deadline: .now() + 0.1) {
withAnimation(Animation.linear(duration:self.duration).delay(self.delay).repeatForever(autoreverses: false)) {
self.animate = self.shouldAnimate
}
}
}
}
}
I get below code in a SwiftUI tutorial, how to understand this line? I know the purpose is to set the seat color as accent color (blue) if selected otherwise leave it as default gray color.
But how to comprehend this syntax and what it is called as any terminology in Swift?
.foregroundColor(isSelectable ? isSelected ? accentColor : Color.gray.opacity(0.5) : accentColor)
struct ChairView: View {
var width: CGFloat = 50
var accentColor: Color = .blue
var seat = Seat.default
#State var isSelected = false
var isSelectable = true
var onSelect: ((Seat)->()) = {_ in }
var onDeselect: ((Seat)->()) = {_ in }
var body: some View {
VStack(spacing: 2) {
Rectangle()
.frame(width: self.width, height: self.width * 2/3)
.foregroundColor(isSelectable ? isSelected ? accentColor : Color.gray.opacity(0.5) : accentColor)
.cornerRadius(width / 5)
Rectangle()
.frame(width: width - 10, height: width / 5)
.foregroundColor(isSelectable ? isSelected ? accentColor : Color.gray.opacity(0.5) : accentColor)
.cornerRadius(width / 5)
}
}
}
struct ChairView_Previews: PreviewProvider {
static var previews: some View {
ChairView()
}
}
Is is a nested ternary operator.
Not too familiar with swift, so I don't know my code snippet will be completely in line with Swift, but let's call it psudeocode for what your example does:
if a {
if b {
c
} else {
d
}
} else {
c
}
I'm recreating an Objective-C app in SwiftUI. In my old app, I have a full-screen background image that has a slide transition between several images. Here's the Objective-C code:
- (void)viewWillAppear:(BOOL)animated{
self.output.text = [self.output.text stringByAppendingString:#"viewWillAppear\r\n"];
[self resetCardReader];
self.creditCard = [[FWCCreditCard alloc] init];
_imageArray = [[NSMutableArray alloc] initWithObjects:[UIImage imageNamed:#"Family on Beach.png"],
[UIImage imageNamed:#"Chinese Graduate.png"],
[UIImage imageNamed:#"New Car.png"],
[UIImage imageNamed:#"House Sold.png"], nil];
index = 0;
}
- (void)viewDidAppear:(BOOL)animated{
self.slideTransition = [CATransition animation]; // CATransition * slideTransition; instance variable
self.slideTransition.duration = 2.0;
self.slideTransition.timingFunction = [CAMediaTimingFunction functionWithName:kCAMediaTimingFunctionEaseInEaseOut];
self.slideTransition.type = kCATransitionPush;
self.slideTransition.delegate = self;
self.slideTransition.subtype =kCATransitionFromRight; // or kCATransitionFromLeft
self.repeatingTimer = [NSTimer scheduledTimerWithTimeInterval:10.0 target:self selector:#selector(slideShow) userInfo:nil repeats:YES];
[self.repeatingTimer fire];
}
-(void)slideShow
{
[self.BackgroundImage.layer addAnimation:self.slideTransition forKey:nil];
if (index < self.imageArray.count-1) // NSUInteger index; instance variable
{
index++;
}
else
{
index=0;
}
self.BackgroundImage.image =[self.imageArray objectAtIndex:index];
}
Here's what I have so far in SwiftUI. Can anyone give me some pointers on where to add the animation?
struct HomeView : View {
private var backgroundImages = ["Family on Beach","Chinese Graduate","New Car","House Sold"]
private var backgroundImageIndex = 0
#State private var backgroundImage = "Family on Beach"
var body: some View {
ZStack{
Image(backgroundImage)
.resizable()
.aspectRatio(contentMode: .fill)
.colorMultiply(Color(red: 0.09, green: 0.286, blue: 0.486, opacity: 0.8))
.edgesIgnoringSafeArea(.all)
.statusBar(hidden: true)
OK, I got it:
import SwiftUI
extension AnyTransition {
static var rightToLeft: AnyTransition {
let insertion = AnyTransition.move(edge: .trailing)
let removal = AnyTransition.move(edge: .leading)
return .asymmetric(insertion: insertion, removal: removal)
}
}
struct HomeView : View {
private var backgroundImages = ["Family on Beach","Chinese Graduate","New Car","House Sold"]
#State private var backgroundImageIndex = 0
#State private var backgroundImageNameEven = "Family on Beach"
#State private var backgroundImageNameOdd = "Chinese Graduate"
#State private var showImage = true
var timer: Timer {
Timer.scheduledTimer(withTimeInterval: 10, repeats: true){_ in
if(self.backgroundImageIndex < self.backgroundImages.count-1){
self.backgroundImageIndex += 1
} else
{
self.backgroundImageIndex = 0
}
if(self.backgroundImageIndex % 2 == 0){
self.backgroundImageNameEven = self.backgroundImages[self.backgroundImageIndex]
} else {
self.backgroundImageNameOdd = self.backgroundImages[self.backgroundImageIndex]
}
withAnimation{
self.showImage.toggle()
}
}
}
var OddImage: some View {
Image(backgroundImageNameOdd)
.resizable()
.clipped()
.colorMultiply(Color(red: 0.09, green: 0.286, blue: 0.486, opacity: 0.8))
.edgesIgnoringSafeArea(.top)
.aspectRatio(contentMode: .fill)
.animation(.basic(duration: 2))
.transition(.rightToLeft)
}
var EvenImage: some View {
Image(backgroundImageNameEven)
.resizable()
.clipped()
.colorMultiply(Color(red: 0.09, green: 0.286, blue: 0.486, opacity: 0.8))
.edgesIgnoringSafeArea(.top)
.aspectRatio(contentMode: .fill)
.animation(.basic(duration: 2))
.transition(.rightToLeft)
}
var body: some View {
ZStack{
if(!self.showImage){
OddImage
}
if(self.showImage){
EvenImage
}
Just add the following to any other element on the view to trigger the timer on view:
.onAppear(perform: {
let _ = self.timer
})