So, I've been using swiftUI almost from the time of it's release and playing around with it. However, I'm trying to add a new feature into my app which doesn't seem to work as desired. I want to have an Image carousel(automatic, meaning the image change after a regular interval) with transition effect. After doing a bit of research ,I could possibly find a method to do so. But, it's not coming together. Here's my code: SwipeImages.swift
import SwiftUI
struct SwipeImages:View{
@State private var difference: CGFloat = 0
@State private var index = 0
let spacing:CGFloat = 10
var timer: Timer{
Timer.scheduledTimer(withTimeInterval: 2, repeats: true) { (timer) in
if self.index < images.count - 1{
self.index += 1
}
else{
self.index = 0
}
}
}
var body:some View{
ContentView(imageData: images[self.index])
.onAppear {
let _ = self.timer
}
}
}
public struct ImageData:Identifiable{
public let id:Int
let image:String
let title:String
let country:String
}
let images = [ImageData(id:0,image:"1a.jpg",title: "String1", country: "country1"),
ImageData(id:1,image:"2a.jpg",title: "String2", country: "country2"),
ImageData(id:2,image:"3a.jpg",title: "String3", country: "country3")]
ContentView.swift
import SwiftUI
struct ContentView:View{
let imageData:ImageData
var transitionStyle:Int = 1
var transition:AnyTransition{
switch transitionStyle{
case 0:
return .opacity
case 1:
return .circular
case 2:
return .stripes(stripes:50,horizontal:true)
default:
return .opacity
}
}
var body:some View{
ZStack{
Image(uiImage: UIImage(named: "\(imageData.image)")!)
.resizable()
.transition(self.transition)
.overlay(
Rectangle()
.fill(LinearGradient(gradient: Gradient(colors: [.clear,.black]), startPoint: .center, endPoint: .bottom))
.clipped()
)
.cornerRadius(2.0)
VStack(alignment: .leading) {
Spacer()
Text("\(imageData.title)")
.font(.title)
.fontWeight(.semibold)
.foregroundColor(.white)
Text(imageData.country)
.foregroundColor(.white)
}
.padding()
}
.shadow(radius:12.0)
.cornerRadius(12.0)
}
}
extension Image{
func imageStyle(height:CGFloat) -> some View{
let shape = RoundedRectangle(cornerRadius: 15.0)
return self.resizable()
.frame(height:height)
.overlay(
Rectangle()
.fill(LinearGradient(gradient: Gradient(colors: [.clear,.black]), startPoint: .center, endPoint: .bottom))
.clipped()
)
.cornerRadius(2.0)
.clipShape(shape)
}
}
extension AnyTransition{
static var circular: AnyTransition{
get{
AnyTransition.modifier(active: ShapeClipModifier(shape: CircleClipShape(pct:1)), identity: ShapeClipModifier(shape: CircleClipShape(pct:0)))
}
}
static func stripes(stripes s:Int,horizontal isHorizontal:Bool) -> AnyTransition{
return AnyTransition.asymmetric(insertion: AnyTransition.modifier(active: ShapeClipModifier(shape:StripeShape(insertion:true,pct:1,stripes:s,horizontal:isHorizontal)), identity:
ShapeClipModifier(shape:StripeShape(insertion:true,pct:0,stripes:s,horizontal:isHorizontal))
), removal:AnyTransition.modifier(active: ShapeClipModifier(shape:StripeShape(insertion:false,pct:1,stripes:s,horizontal:isHorizontal))
, identity:
ShapeClipModifier(shape:StripeShape(insertion:false,pct:0,stripes:s,horizontal:isHorizontal)))
)
}
}
struct ShapeClipModifier<S: Shape>: ViewModifier{
let shape: S
func body(content:Content) -> some View {
content.clipShape(shape)
}
}
struct StripeShape: Shape{
let insertion: Bool
var pct: CGFloat
let stripes: Int
let horizontal: Bool
var animatableData: CGFloat{
get{pct}
set{pct = newValue}
}
func path(in rect:CGRect) -> Path{
var path = Path()
let stripeHeight = rect.height/CGFloat(stripes)
for i in 0..<stripes{
let iteratorValue = CGFloat(i)
if insertion{
path.addRect(CGRect(x: 0, y: iteratorValue * stripeHeight, width: rect.width, height: stripeHeight * (1 - pct)))
}
else{
path.addRect(CGRect(x: 0, y: iteratorValue * stripeHeight + (stripeHeight * pct), width: rect.width, height: stripeHeight * (1 - pct)))
}
}
return path
}
}
struct CircleClipShape: Shape{
var pct:CGFloat
var animatableData: CGFloat{
get{pct}
set{pct = newValue}
}
func path(in rect: CGRect) -> Path {
var path = Path()
var bigRect = rect
bigRect.size.width = bigRect.size.width * 2 * (1-pct)
bigRect.size.height = bigRect.size.height * 2 * (1-pct)
bigRect = bigRect.offsetBy(dx: -rect.width/2.0, dy: -rect.height/2.0)
path = Circle().path(in: bigRect)
return path
}
}
MainView.swift
import SwiftUI
struct MainView:View{
var body:some View{
VStack{
SwipeImages()
.padding()
}
}
}
When the app is launched the images change after scheduled interval specified ,i.e: 2s , but the required transition such as stripes or circular ,nothing seem to come in action. (Also, I tried applying regular inbuilt transitions such as slide and opacity, even they aren't working). Could you please help me identifying what's wrong, or any other alternatives to achieve the same? Thanks.