{"componentChunkName":"component---src-templates-article-js","path":"/article/swiftui-movie-tickets-app-design","result":{"data":{"contentfulArticle":{"title":"Movie Tickets UI","image":"https://res.cloudinary.com/liquidcoder/image/upload/v1597489598/MovieTicketApp/jgjtf33tygx9qqju4b7s.png","createdDate":"Friday, 08 November 2019","videoUrl":"rg108K4pzWk","updatedDate":"3 years ago","isNewLayout":null,"previews":null,"slug":"swiftui-movie-tickets-app-design","author":{"email":"john@liquidcoder.com","name":"John"},"tags":[{"title":"Article"},{"title":"Free"},{"title":"Swift UI"},{"title":"UI Design"}],"allChapters":null,"code":null,"explanation":null,"downloads":[{"name":"Project source code","url":"https://github.com/liquidcoder1/MovieTicketDesignApp/archive/master.zip"}],"resources":[{"name":"Apple developer documentation","url":"https://developer.apple.com/documentation/swiftui"},{"name":"Hacking with swift","url":"https://www.hackingwithswift.com"},{"name":"Swift by sundell","url":"https://www.swiftbysundell.com"}],"body":{"childMdx":{"tableOfContents":{"items":[{"url":"#introduction","title":"Introduction"},{"url":"#requirements","title":"Requirements"},{"url":"#get-started","title":"Get started"},{"url":"#create-the-top-part","title":"Create the top part."},{"url":"#create-the-bottom-part","title":"Create the bottom part."},{"url":"#create-the-ticketview","title":"Create the TicketView"},{"url":"#dashed-separator-shape","title":"Dashed Separator Shape"},{"url":"#ticket-shape","title":"Ticket Shape"},{"url":"#scrolling-with-3d-effect","title":"Scrolling with 3D effect"}]},"body":"function _extends() { _extends = Object.assign || function (target) { for (var i = 1; i < arguments.length; i++) { var source = arguments[i]; for (var key in source) { if (Object.prototype.hasOwnProperty.call(source, key)) { target[key] = source[key]; } } } return target; }; return _extends.apply(this, arguments); }\n\nfunction _objectWithoutProperties(source, excluded) { if (source == null) return {}; var target = _objectWithoutPropertiesLoose(source, excluded); var key, i; if (Object.getOwnPropertySymbols) { var sourceSymbolKeys = Object.getOwnPropertySymbols(source); for (i = 0; i < sourceSymbolKeys.length; i++) { key = sourceSymbolKeys[i]; if (excluded.indexOf(key) >= 0) continue; if (!Object.prototype.propertyIsEnumerable.call(source, key)) continue; target[key] = source[key]; } } return target; }\n\nfunction _objectWithoutPropertiesLoose(source, excluded) { if (source == null) return {}; var target = {}; var sourceKeys = Object.keys(source); var key, i; for (i = 0; i < sourceKeys.length; i++) { key = sourceKeys[i]; if (excluded.indexOf(key) >= 0) continue; target[key] = source[key]; } return target; }\n\n/* @jsxRuntime classic */\n\n/* @jsx mdx */\nvar _frontmatter = {};\nvar layoutProps = {\n  _frontmatter: _frontmatter\n};\nvar MDXLayout = \"wrapper\";\nreturn function MDXContent(_ref) {\n  var components = _ref.components,\n      props = _objectWithoutProperties(_ref, [\"components\"]);\n\n  return mdx(MDXLayout, _extends({}, layoutProps, props, {\n    components: components,\n    mdxType: \"MDXLayout\"\n  }), mdx(\"h2\", null, \"Introduction\"), mdx(\"p\", null, \"In this article, you will learn how to :\"), mdx(\"ul\", null, mdx(\"li\", {\n    parentName: \"ul\"\n  }, \"Create custom shapes with paths\"), mdx(\"li\", {\n    parentName: \"ul\"\n  }, \"Clip a existing view using the shape that you\\u2019ll create\"), mdx(\"li\", {\n    parentName: \"ul\"\n  }, \"Create a 3D Scroll effect\"), mdx(\"li\", {\n    parentName: \"ul\"\n  }, \"And more \\u2026 Enjoy!\")), mdx(\"h2\", null, \"Requirements\"), mdx(\"ul\", null, mdx(\"li\", {\n    parentName: \"ul\"\n  }, \"Xcode 12 or greater\"), mdx(\"li\", {\n    parentName: \"ul\"\n  }, \"MacOS Catalina or greater\"), mdx(\"li\", {\n    parentName: \"ul\"\n  }, \"Swift 5.0 or greater\"), mdx(\"li\", {\n    parentName: \"ul\"\n  }, \"iOS 14 or greater\")), mdx(\"h2\", null, \"Get started\"), mdx(\"ul\", null, mdx(\"li\", {\n    parentName: \"ul\"\n  }, \"Open Xcode\"), mdx(\"li\", {\n    parentName: \"ul\"\n  }, \"Create a new Xcode project\"), mdx(\"li\", {\n    parentName: \"ul\"\n  }, \"Select single view app and click next\"), mdx(\"li\", {\n    parentName: \"ul\"\n  }, \"Name your app and make sure the user interface is Swift UI\"), mdx(\"li\", {\n    parentName: \"ul\"\n  }, \"Last, click Finish.\\nRename the \", mdx(\"inlineCode\", {\n    parentName: \"li\"\n  }, \"ContentView\"), \" filename and struct to \", mdx(\"inlineCode\", {\n    parentName: \"li\"\n  }, \"MovieTicketApp\\xA0\"), \", and make sure you rename its reference in \", mdx(\"inlineCode\", {\n    parentName: \"li\"\n  }, \"SceneDelegate\"))), mdx(\"pre\", null, mdx(\"code\", _extends({\n    parentName: \"pre\"\n  }, {\n    \"className\": \"language-swift\"\n  }), \"func scene(_ scene: UIScene, willConnectTo session: UISceneSession, options connectionOptions: UIScene.ConnectionOptions) {\\n    // Use this method to optionally configure and attach the UIWindow `window` to the provided UIWindowScene `scene`.\\n    // If using a storyboard, the `window` property will automatically be initialized and attached to the scene.\\n    // This delegate does not imply the connecting scene or session are new (see `application:configurationForConnectingSceneSession` instead).\\n\\n    // Create the SwiftUI view that provides the window contents.\\n    let movieTicketApp = MovieTicketApp()\\n\\n    // Use a UIHostingController as window root view controller.\\n    if let windowScene = scene as? UIWindowScene {\\n        let window = UIWindow(windowScene: windowScene)\\n        window.rootViewController = UIHostingController(rootView: movieTicketApp)\\n        self.window = window\\n        window.makeKeyAndVisible()\\n    }\\n}\\n\")), mdx(\"p\", null, \"Change everywhere you see \", mdx(\"inlineCode\", {\n    parentName: \"p\"\n  }, \"ContentView\"), \" referenced to \", mdx(\"inlineCode\", {\n    parentName: \"p\"\n  }, \"MovieTicketApp\\xA0\"), \".\"), mdx(\"p\", null, \"As always, I will go through creating this design step by step. Let\\u2019s get started.\"), mdx(\"h2\", null, \"Create the top part.\"), mdx(\"p\", null, \"Create a folder named Views and inside it add a swiftUI file named \", mdx(\"inlineCode\", {\n    parentName: \"p\"\n  }, \"TopTicketView\"), \". Replace everything inside the body block with the following:\"), mdx(\"pre\", null, mdx(\"code\", _extends({\n    parentName: \"pre\"\n  }, {\n    \"className\": \"language-swift\"\n  }), \"   VStack{\\n            VStack(alignment: .leading) {\\n                Text(studioName)\\n                    .font(.system(size: 20, weight: .bold))\\n                    .foregroundColor(Color.gray)\\n                Text(movieTitle)\\n                    .font(.system(size: 30, weight: .black))\\n                \\n            }.frame(minWidth: 0.0, maxWidth:.infinity, alignment: .leading)\\n                .padding(.top, 30)\\n                .padding(.horizontal)\\n        \\n            Image(uiImage: UIImage(named: imageName)!)\\n                .resizable().modifier(FullWidthModifier())\\n                .frame(height: 200)\\n                .scaledToFit()\\n                \\n            HStack{\\n                DetailsView(detail1: \\\"SCREEN\\\", detail2: \\\"18\\\", detail3: \\\"PRICE\\\", detail4: \\\"$5.68\\\")\\n                DetailsView(detail1: \\\"ROW\\\", detail2: \\\"H\\\", detail3: \\\"DATE\\\", detail4: \\\"23/05/13\\\")\\n                DetailsView()\\n            }.padding(.vertical)\\n        }\\n\")), mdx(\"p\", null, \"And add this at the top of the file:\"), mdx(\"pre\", null, mdx(\"code\", _extends({\n    parentName: \"pre\"\n  }, {\n    \"className\": \"language-swift\"\n  }), \"    var studioName = \\\"studio\\\"\\n    var movieTitle = \\\"ONLY GOD FORGIVES\\\"\\n    var imageName = \\\"terminator.jpg\\\"\\n\")), mdx(\"p\", null, \"The above code just creates a vertical stack of Views and the last view is a HStack containing  the \", mdx(\"inlineCode\", {\n    parentName: \"p\"\n  }, \"DetailsView\"), \" which does not exist yet. Let\\u2019s us now create that view. \"), mdx(\"p\", null, \"In the same \", mdx(\"inlineCode\", {\n    parentName: \"p\"\n  }, \"Views\"), \" folder, add a new swiftUI file named \", mdx(\"inlineCode\", {\n    parentName: \"p\"\n  }, \"DetailsView\"), \" and replace everything inside with the following code:\"), mdx(\"pre\", null, mdx(\"code\", _extends({\n    parentName: \"pre\"\n  }, {\n    \"className\": \"language-swift\"\n  }), \"import SwiftUI\\n\\nstruct DetailsView: View {\\n    var detail1  = \\\"SEAT\\\"\\n    var detail2 = \\\"34\\\"\\n    var detail3 = \\\"TIME\\\"\\n    var detail4 = \\\"18:15\\\"\\n    \\n    var body: some View {\\n        VStack(spacing: 10){\\n            VStack {\\n                Text(detail1)\\n                    .font(.system(size: 15, weight: .bold))\\n                    .foregroundColor(Color.gray)\\n                Text(detail2)\\n                .font(.system(size: 30, weight: .black))\\n\\n            }\\n                \\n            VStack {\\n                Text(detail3)\\n                    .font(.system(size: 15, weight: .bold))\\n                    .foregroundColor(Color.gray)\\n                Text(detail4).font(.system(size: 15, weight: .bold))\\n            }\\n        }.modifier(FullWidthModifier())\\n    }\\n}\\n\\nstruct DetailsView_Previews: PreviewProvider {\\n    static var previews: some View {\\n        DetailsView()\\n    }\\n}\\n\\n\")), mdx(\"p\", null, mdx(\"strong\", {\n    parentName: \"p\"\n  }, \"Preview\")), mdx(\"p\", null, mdx(\"img\", _extends({\n    parentName: \"p\"\n  }, {\n    \"src\": \"https://res.cloudinary.com/liquidcoder/image/upload/v1573243470/MovieTicketApp/irfxot02kfyy4sigzolb.png\",\n    \"alt\": null\n  }))), mdx(\"h2\", null, \"Create the bottom part.\"), mdx(\"p\", null, \"This  view will just be a simple \", mdx(\"inlineCode\", {\n    parentName: \"p\"\n  }, \"Image\"), \" showing the barcode which in our case will be static, but for a real world project this must be dynamic.\"), mdx(\"p\", null, \"In the Views folder, add a swiftUI file \", mdx(\"inlineCode\", {\n    parentName: \"p\"\n  }, \"BottomTicketView\"), \" and add the following code inside:\"), mdx(\"pre\", null, mdx(\"code\", _extends({\n    parentName: \"pre\"\n  }, {\n    \"className\": \"language-swift\"\n  }), \"import SwiftUI\\n\\nstruct BottomTicketView: View {\\n    var body: some View {\\n         Image(\\\"Barcode\\\")\\n                       .resizable()\\n                       .scaledToFit()\\n                       .padding(30)\\n                       .modifier(FullWidthModifier())\\n    }\\n}\\n\\nstruct BottomTicketView_Previews: PreviewProvider {\\n    static var previews: some View {\\n        BottomTicketView()\\n    }\\n}\\n\\n\")), mdx(\"p\", null, \"You get an error caused by the \", mdx(\"inlineCode\", {\n    parentName: \"p\"\n  }, \"FullWidthModifier\"), \", So  add a folder named modifiers and add a swift file inside it named \", mdx(\"inlineCode\", {\n    parentName: \"p\"\n  }, \"FullWidthModifier\"), \". Add the\\nfollowing code inside the file you\\u2019ve just created:\"), mdx(\"pre\", null, mdx(\"code\", _extends({\n    parentName: \"pre\"\n  }, {\n    \"className\": \"language-swift\"\n  }), \"import SwiftUI\\n\\nstruct FullWidthModifier: ViewModifier {\\n    func body(content: Content) -> some View {\\n        content.frame(minWidth: 0.0, maxWidth: .infinity)\\n    }\\n}\\n\\n\")), mdx(\"p\", null, mdx(\"strong\", {\n    parentName: \"p\"\n  }, \"Preview\")), mdx(\"p\", null, mdx(\"img\", _extends({\n    parentName: \"p\"\n  }, {\n    \"src\": \"https://res.cloudinary.com/liquidcoder/image/upload/v1573244225/MovieTicketApp/enlibfrb2lvb6xlhgnno.png\",\n    \"alt\": null\n  }))), mdx(\"h2\", null, \"Create the TicketView\"), mdx(\"p\", null, \"Let\\u2019s now put the 2 parts together to create the \", mdx(\"inlineCode\", {\n    parentName: \"p\"\n  }, \"TicketView\"), \". Inside the Views folder, add the following code:\"), mdx(\"pre\", null, mdx(\"code\", _extends({\n    parentName: \"pre\"\n  }, {\n    \"className\": \"language-swift\"\n  }), \"import SwiftUI\\n\\nstruct TicketView: View {\\n    var studioName = \\\"studio\\\"\\n    var movieTitle = \\\"ONLY GOD FORGIVES\\\"\\n    var imageName = \\\"terminator.jpg\\\"\\n    \\n    var body: some View {\\n      VStack(spacing: 0) {\\n                  TopTicketView(studioName: studioName, movieTitle: movieTitle, imageName: imageName)\\n                      .background(Color.white)\\n                  .modifier(CardStyleModifier())\\n                  \\n                  BottomTicketView()\\n                      .background(Color(\\\"barcodeBG\\\"))\\n                  .modifier(CardStyleModifier())\\n\\n              }.padding()\\n    }\\n}\\n\\nstruct TicketView_Previews: PreviewProvider {\\n    static var previews: some View {\\n        TicketView()\\n    }\\n}\\n\")), mdx(\"p\", null, \"Then in the Modifiers folder, add a new swiftUI file \", mdx(\"inlineCode\", {\n    parentName: \"p\"\n  }, \"CardStyleModifier\"), \" containing the following code inside:\"), mdx(\"pre\", null, mdx(\"code\", _extends({\n    parentName: \"pre\"\n  }, {\n    \"className\": \"language-swift\"\n  }), \"import SwiftUI\\n\\nstruct CardStyleModifier: ViewModifier {\\n    func body(content: Content) -> some View {\\n        content\\n            .shadow(color: Color.black.opacity(0.2), radius: 10, x: 0, y: 10)\\n    }\\n}\\n\\n\")), mdx(\"p\", null, \"The above code just put the 2 ticket parts together and apply a shadow to them individually. Here is the resulting view:\"), mdx(\"p\", null, mdx(\"strong\", {\n    parentName: \"p\"\n  }, \"Preview\"), \"\\n\", mdx(\"img\", _extends({\n    parentName: \"p\"\n  }, {\n    \"src\": \"https://res.cloudinary.com/liquidcoder/image/upload/v1573245535/MovieTicketApp/mz42rb2rk2odqyo7zqhv.png\",\n    \"alt\": null\n  }))), mdx(\"p\", null, \"Let\\u2019s now design the ticket to look like a movie ticket. To do that, we will need to create 2 custom shapes:\"), mdx(\"ol\", null, mdx(\"li\", {\n    parentName: \"ol\"\n  }, \"The Dashed Separator which will be between the top and bottom parts\"), mdx(\"li\", {\n    parentName: \"ol\"\n  }, \"The Ticket Shape that we will use to clip the ticket View.\")), mdx(\"h2\", null, \"Dashed Separator Shape\"), mdx(\"p\", null, \"Create a new folder named \", mdx(\"inlineCode\", {\n    parentName: \"p\"\n  }, \"Shapes\"), \" and inside that folder add a new swift file named, then add the following code inside:\"), mdx(\"pre\", null, mdx(\"code\", _extends({\n    parentName: \"pre\"\n  }, {\n    \"className\": \"language-swift\"\n  }), \"\\nimport SwiftUI\\n\\nstruct DashedSeperator: Shape {\\n    func path(in rect: CGRect) -> Path {\\n        var path = Path()\\n        path.move(to: CGPoint(x: rect.origin.x, y: rect.origin.y))\\n        path.addLine(to: CGPoint(x: rect.size.width, y: rect.origin.y ))\\n        path.closeSubpath()\\n        return path\\n    }\\n}\\n\\n\")), mdx(\"p\", null, mdx(\"em\", {\n    parentName: \"p\"\n  }, \"Illustration\"), \"\\nThis code just creates and straight horizontal line from across the provided width.\"), mdx(\"h2\", null, \"Ticket Shape\"), mdx(\"p\", null, \"Inside the same folder, create a new swift file named \", mdx(\"inlineCode\", {\n    parentName: \"p\"\n  }, \"TicketShape\"), \" and add the following inside:\"), mdx(\"pre\", null, mdx(\"code\", _extends({\n    parentName: \"pre\"\n  }, {\n    \"className\": \"language-swift\"\n  }), \"import SwiftUI\\n\\nstruct TicketShape: Shape {\\n    func path(in rect: CGRect) -> Path {\\n        let arcRadius: CGFloat = 20\\n        let smallArcRadius:CGFloat = 10\\n        \\n        var path = Path()\\n        path.move(to: CGPoint(x: rect.origin.x, y: rect.origin.y + arcRadius))\\n        path.addArc(center: CGPoint.zero, radius: arcRadius, startAngle: Angle(degrees: 90), endAngle: Angle(degrees: 0) , clockwise: true)\\n        \\n        path.addArc(center: CGPoint(x: rect.midX, y: rect.origin.y) , radius: arcRadius, startAngle: Angle(degrees: 180), endAngle: Angle(degrees: 0) , clockwise: true)\\n        \\n        path.addLine(to:  CGPoint(x: rect.size.width - arcRadius, y: rect.origin.y))\\n        path.addArc(center: CGPoint(x: rect.size.width , y: rect.origin.y), radius: arcRadius, startAngle: Angle(degrees: 180), endAngle: Angle(degrees: 90) , clockwise: true)\\n        \\n        path.addLine(to:  CGPoint(x: rect.size.width, y: rect.size.height - smallArcRadius))\\n        path.addArc(center: CGPoint(x: rect.size.width , y: rect.size.height), radius: smallArcRadius, startAngle: Angle(degrees: 270), endAngle: Angle(degrees: 180) , clockwise: true)\\n            \\n        path.addLine(to:  CGPoint(x: rect.origin.x + smallArcRadius, y: rect.size.height))\\n        path.addArc(center: CGPoint(x: rect.origin.x , y: rect.size.height), radius: smallArcRadius, startAngle: Angle(degrees: 360), endAngle: Angle(degrees: 270) , clockwise: true)\\n             \\n        path.closeSubpath()\\n        return path\\n    }\\n}\\n\\n\")), mdx(\"p\", null, \"This code goes around and draws the shape that we will use to cut the top and bottom parts of the tickets. \"), mdx(\"p\", null, \"It\\u2019s now time to clip the 2 views.  Open the Views folder and inside the \", mdx(\"inlineCode\", {\n    parentName: \"p\"\n  }, \"TicketView\"), \" file, replace the content of the body with the following:\"), mdx(\"pre\", null, mdx(\"code\", _extends({\n    parentName: \"pre\"\n  }, {\n    \"className\": \"language-swift\"\n  }), \"      VStack(spacing: 0) {\\n                  TopTicketView(studioName: studioName, movieTitle: movieTitle, imageName: imageName)\\n                      .background(Color.white)\\n                      .clipShape(TicketShape())\\n                  .modifier(CardStyleModifier())\\n\\n                  DashedSeperator()\\n                      .stroke(Color.gray, style: StrokeStyle(lineWidth: 1,dash: [4,8], dashPhase: 4))\\n                      .frame(height: 0.4)\\n                      .padding(.horizontal)\\n                  \\n                  BottomTicketView()\\n                      .background(Color(\\\"barcodeBG\\\"))\\n                   .clipShape(TicketShape().rotation(Angle(degrees: 180)))\\n                  .modifier(CardStyleModifier())\\n\\n              }.padding()\\n\")), mdx(\"p\", null, \"This is the same code but contains some additions which are the following:\"), mdx(\"ol\", null, mdx(\"li\", {\n    parentName: \"ol\"\n  }, \"After the  \", mdx(\"inlineCode\", {\n    parentName: \"li\"\n  }, \"background\"), \" modifier, I a \", mdx(\"inlineCode\", {\n    parentName: \"li\"\n  }, \"clipShape\"), \" modifier with \", mdx(\"inlineCode\", {\n    parentName: \"li\"\n  }, \"TickerShape()\"), \" passed in.\"), mdx(\"li\", {\n    parentName: \"ol\"\n  }, \"Then I put the \", mdx(\"inlineCode\", {\n    parentName: \"li\"\n  }, \"DashedSeperator()\"), \" between the 2 parts in order to separate them and create an effect of small cuts. Notice how I set the height to be 0.4 otherwise it would take a third of the height of the parent container.\"), mdx(\"li\", {\n    parentName: \"ol\"\n  }, \"And last, after \", mdx(\"inlineCode\", {\n    parentName: \"li\"\n  }, \"background\"), \" modifier applied to the \", mdx(\"inlineCode\", {\n    parentName: \"li\"\n  }, \"BottomTicketView\"), \", I add also a \", mdx(\"inlineCode\", {\n    parentName: \"li\"\n  }, \"clipShape\"), \" modifier but this time I flip the  \", mdx(\"inlineCode\", {\n    parentName: \"li\"\n  }, \"TicketShape\"), \" by applying a rotation effect of 180 degrees because I want the top of the \", mdx(\"inlineCode\", {\n    parentName: \"li\"\n  }, \"TicketShape\"), \" to be the bottom when clipping the \", mdx(\"inlineCode\", {\n    parentName: \"li\"\n  }, \"BottomTicketView\"), \".\\nHere is the result:\")), mdx(\"p\", null, mdx(\"strong\", {\n    parentName: \"p\"\n  }, \"Preview\")), mdx(\"p\", null, mdx(\"img\", _extends({\n    parentName: \"p\"\n  }, {\n    \"src\": \"https://res.cloudinary.com/liquidcoder/image/upload/v1573286061/MovieTicketApp/zxxeer9lcwwaqbxpubmw.png\",\n    \"alt\": \"SwiftUI - Movie Ticket Preview\"\n  }))), mdx(\"h2\", null, \"Scrolling with 3D effect\"), mdx(\"p\", null, \"First, we will need some sample data, so create a new folder named Models and add a swift file inside named \", mdx(\"inlineCode\", {\n    parentName: \"p\"\n  }, \"Ticket\"), \" with the following code: \"), mdx(\"pre\", null, mdx(\"code\", _extends({\n    parentName: \"pre\"\n  }, {\n    \"className\": \"language-swift\"\n  }), \"import Foundation\\n\\nstruct Ticket: Hashable, Identifiable {\\n    var id = UUID()\\n    let studioName: String\\n    let movieTitle: String\\n    let imageName: String\\n    \\n    static func data() -> [Ticket] {\\n        return [\\n            Ticket(studioName: \\\"\\u200EWalt Disney Pictures\\\", movieTitle: \\\"ALADDIN\\\", imageName: \\\"aladdin.jpg\\\"),\\n            Ticket(studioName: \\\"\\u200EWalt Disney Pictures\\\", movieTitle: \\\"CARS\\\", imageName: \\\"cars.jpg\\\"),\\n            Ticket(studioName: \\\"\\u200E\\u200ESeven Bucks Productions\\u200E\\\", movieTitle: \\\"HOBBS AND SHAW\\\", imageName: \\\"hobbsandshaw.jpg\\\"),\\n            Ticket(studioName: \\\"\\u200ELin Pictures\\\", movieTitle: \\\"IT\\\", imageName: \\\"it.jpg\\\"),\\n            Ticket(studioName: \\\"\\u200EWarner Bros. Pictures\\\", movieTitle: \\\"JOKER\\\", imageName: \\\"joker.jpg\\\"),\\n            Ticket(studioName: \\\"\\u200EWalt Disney Pictures\\\", movieTitle: \\\"LION KING\\\", imageName: \\\"lionking.jpg\\\"),\\n            Ticket(studioName: \\\"\\u200EParamount Pictures\\\", movieTitle: \\\"TERMINATOR\\\", imageName: \\\"terminator.jpg\\\"),\\n            Ticket(studioName: \\\"\\u200EMarvel Studios\\\", movieTitle: \\\"X-MEN\\\", imageName: \\\"xmen.jpg\\\"),\\n        ]\\n    }\\n}\\n\\n\")), mdx(\"p\", null, \"You will need to download the completed project and use the images in the Images folder.\"), mdx(\"p\", null, \"Then replace the content in the \", mdx(\"inlineCode\", {\n    parentName: \"p\"\n  }, \"MovieTicketApp\"), \"\\u2019s body with the following code:\"), mdx(\"pre\", null, mdx(\"code\", _extends({\n    parentName: \"pre\"\n  }, {\n    \"className\": \"language-swift\"\n  }), \"ScrollView(.horizontal, showsIndicators: false) {\\n     HStack {\\n           ForEach(Ticket.data(), id: \\\\.id) {  ticket in\\n                     GeometryReader { gr in\\n                    self.renderTicket(ticket, angle: gr.frame(in: .global).minX / -10)\\n                        }.frame(width: UIScreen.main.bounds.width)\\n                    }\\n                }\\n            }.frame(minHeight: 0.0, maxHeight: .infinity)\\n            .background(Color(\\\"bg\\\"))\\n            .edgesIgnoringSafeArea(.all)\\n\")), mdx(\"p\", null, \"You will need to add the following function below the \", mdx(\"inlineCode\", {\n    parentName: \"p\"\n  }, \"body\"), \" block to silence that error:\"), mdx(\"pre\", null, mdx(\"code\", _extends({\n    parentName: \"pre\"\n  }, {\n    \"className\": \"language-swift\"\n  }), \"    \\n    func renderTicket(_ ticket: Ticket, angle: CGFloat) -> some View {\\n        return TicketView(studioName: ticket.studioName, movieTitle: ticket.movieTitle, imageName: ticket.imageName)\\n               .frame(width: UIScreen.main.bounds.width)\\n        .frame(minHeight: 0.0, maxHeight: .infinity)\\n         .rotation3DEffect(Angle(degrees: Double(angle)) , axis: (x: 0, y: 10.0, z: 0))\\n    }\\n\")), mdx(\"p\", null, \"The bit to note here is the \", mdx(\"inlineCode\", {\n    parentName: \"p\"\n  }, \"rotation3DEffect\"), \" modifier. The effect works like this:\"), mdx(\"ul\", null, mdx(\"li\", {\n    parentName: \"ul\"\n  }, \"We put each \", mdx(\"inlineCode\", {\n    parentName: \"li\"\n  }, \"TicketView\"), \" in \", mdx(\"inlineCode\", {\n    parentName: \"li\"\n  }, \"GeometryReader\"), \" container in order to get its individual size and coordinate space.\"), mdx(\"li\", {\n    parentName: \"ul\"\n  }, \"Then we apply a 3D rotation effect on the Y axis of each \", mdx(\"inlineCode\", {\n    parentName: \"li\"\n  }, \"TicketView\"), \" by  setting the angle to the \", mdx(\"inlineCode\", {\n    parentName: \"li\"\n  }, \"TicketView\"), \"\\u2019s \", mdx(\"inlineCode\", {\n    parentName: \"li\"\n  }, \"minX\"), \" and the axis to \", mdx(\"inlineCode\", {\n    parentName: \"li\"\n  }, \"(x: 0, y: 10.0, z: 0))\"))), mdx(\"p\", null, \"That\\u2019s it folks. Feel free to share this article. Happy coding!\"));\n}\n;\nMDXContent.isMDXComponent = true;","excerpt":"Introduction In this article, you will learn how to : Create custom shapes with paths Clip a existing view using the shape that you’ll create Create a 3D Scroll effect And more … Enjoy! Requirements Xcode 12 or greater MacOS Catalina or greater Swift 5.0 or greater iOS 14 or greater Get started Open…"}}}},"pageContext":{"slug":"swiftui-movie-tickets-app-design"}},"staticQueryHashes":["1047155515","1278771865","2517639938","2517639938","2537039069","3452127246","3566879862","3891201089","439617394","670651827"]}