{"componentChunkName":"component---src-templates-article-js","path":"/article/expense-report-ui","result":{"data":{"contentfulArticle":{"title":"Expense Report UI","image":"https://res.cloudinary.com/liquidcoder/image/upload/v1597491792/demo/xhyued1qww1v0hjuv40d.jpg","createdDate":"Saturday, 21 December 2019","videoUrl":"MA_LrhsC2qI","updatedDate":"3 years ago","isNewLayout":null,"previews":null,"slug":"expense-report-ui","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/expensesReportUI/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":"#models","title":"Models"},{"url":"#views","title":"Views"},{"url":"#put-everything-together","title":"Put everything together"},{"url":"#conclusion","title":"Conclusion"}]},"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 week\\u2019s swift ui tutorial,  we are going to build  a fairly complex ui with animations. You are going to learn how to animation various shapes in swift ui and how to animate text while designing a complex user interface. \"), mdx(\"p\", null, \"Let\\u2019s start writing some swift code, shall we?\"), mdx(\"h2\", null, \"Requirements\"), mdx(\"ul\", null, mdx(\"li\", {\n    parentName: \"ul\"\n  }, \"Xcode 11 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 12 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.\"), mdx(\"li\", {\n    parentName: \"ul\"\n  }, \"You can modifier your main \", mdx(\"em\", {\n    parentName: \"li\"\n  }, \"ContentView.swift\"), \" file  to whatever you want or leave it like that, it doesn\\u2019t really matter.\")), mdx(\"h2\", null, \"Models\"), mdx(\"p\", null, \"In your Xcode root project, create a folder named Models, and inside it, create a swift file named Expense.swift containing the following code:\"), mdx(\"pre\", null, mdx(\"code\", _extends({\n    parentName: \"pre\"\n  }, {\n    \"className\": \"language-swift\"\n  }), \"struct Expense {\\n\\n    var month: String = \\\"\\\"\\n    var budget: CGFloat = 0\\n    var consumed: CGFloat = 0\\n    var percentConsumed: CGFloat = 0\\n    private static let months = [\\\"Jan\\\", \\\"Feb\\\", \\\"Mar\\\", \\\"Apr\\\", \\\"May\\\", \\\"Jun\\\", \\\"Jul\\\", \\\"Aug\\\", \\\"Sep\\\", \\\"Oct\\\", \\\"Nov\\\", \\\"Dec\\\"]\\n\\n    static func getRandom() -> [Expense]{\\n        months.map { month in\\n            let budget = CGFloat.random(in: 2000...10000)\\n            let consumed = CGFloat.random(in: 2000...budget)\\n            let percentConsumed = consumed / budget\\n            return Expense(month: month, budget: budget , consumed: consumed, percentConsumed: percentConsumed)\\n        }\\n    }\\n\\n}\\n\\n\")), mdx(\"p\", null, \"For the sake of this tutorial, we will use dummy data. The above code generate some random expenses for each month of the year.\"), mdx(\"p\", null, \"In the same folder, create another file named ExpensesBreakDown.swift, and inside it, add the following code:\"), mdx(\"pre\", null, mdx(\"code\", _extends({\n    parentName: \"pre\"\n  }, {\n    \"className\": \"language-swift\"\n  }), \"import SwiftUI\\n\\nstruct ExpenseCategory: Identifiable {\\n    var id: UUID = UUID()\\n    var name: String = \\\"\\\"\\n    var percent: CGFloat = 0\\n    var amount: CGFloat = 0\\n    var colors: [Color] = []\\n}\\n\\nclass ExpensesBreakDown: ObservableObject {\\n\\n    @Published var categories = [ExpenseCategory]()\\n    var expense = Expense()\\n\\n    init() {\\n        generateRandom(Expense.getRandom().first(where: { $0.month == Date.month })!)\\n    }\\n\\n    func generateRandom(_ expense: Expense){\\n        let percent1 = CGFloat.random(in: 0...1)\\n        let percent2 = CGFloat.random(in: 0...(1-percent1))\\n        let percent3 = CGFloat.random(in: 0...(1-(percent2+percent1)))\\n        let percent4 = CGFloat.random(in: 0...(1-(percent2+percent1+percent3)))\\n        let percent5 = 1 - (percent4+percent2+percent1+percent3)\\n        let categories = [\\n            ExpenseCategory(name: \\\"Groceries\\\", percent: percent1, amount: expense.consumed * percent1, colors: [Color.red, Color.clearPurple]),\\n            ExpenseCategory(name: \\\"Education\\\", percent: percent2, amount: expense.consumed * percent2, colors: [Color.darkYellow, Color.lightYellow]),\\n            ExpenseCategory(name: \\\"Home\\\", percent: percent3, amount: expense.consumed * percent3, colors: [Color.darkPurple, Color.lightPurple]),\\n            ExpenseCategory(name: \\\"Health\\\", percent: percent4, amount: expense.consumed * percent4, colors: [Color.red, Color.clearPurple]),\\n            ExpenseCategory(name: \\\"Personal care\\\", percent: percent5, amount: expense.consumed * percent5, colors: [Color.darkYellow, Color.lightYellow]),\\n        ]\\n\\n        self.expense = expense\\n\\n        self.categories = categories\\n    }\\n\\n}\\n\\n\")), mdx(\"p\", null, \"The struct will hold our categories. For this  sample swift ui project, we will hard-code  5 categories which I create in the \", mdx(\"inlineCode\", {\n    parentName: \"p\"\n  }, \"ObservableObejct\"), \" class below the struct. Your code will have a compiler error because you haven\\u2019t created  the Date extension, so let\\u2019s do that. In your Xcode root project, create a folder named Extensions containing a file named _DateExt.swift\\xA0_which in turns contains the following code:\"), mdx(\"pre\", null, mdx(\"code\", _extends({\n    parentName: \"pre\"\n  }, {\n    \"className\": \"language-swift\"\n  }), \"\\nextension Date{\\n\\n    static var month: String {\\n        let formatter = DateFormatter()\\n        formatter.dateFormat = \\\"MMM\\\"\\n        return formatter.string(from: Date())\\n    }\\n\\n    static func fullMonthName(short: String)-> String{\\n        let months = [\\n            \\\"Jan\\\":\\\"January\\\",\\n            \\\"Feb\\\":\\\"February\\\",\\n            \\\"March\\\":\\\"Mar\\\",\\n            \\\"Apr\\\":\\\"April\\\",\\n            \\\"May\\\":\\\"May\\\",\\n            \\\"June\\\":\\\"June\\\",\\n            \\\"Jul\\\":\\\"July\\\",\\n            \\\"Aug\\\":\\\"August\\\",\\n            \\\"Sep\\\":\\\"September\\\",\\n            \\\"Oct\\\":\\\"October\\\",\\n            \\\"Nov\\\":\\\"November\\\",\\n            \\\"Dec\\\":\\\"December\\\",\\n        ]\\n\\n        return months[short] ?? \\\"January\\\"\\n    }\\n}\\n\")), mdx(\"p\", null, \"That\\u2019s our models.\"), mdx(\"h2\", null, \"Views\"), mdx(\"p\", null, \"In your Xcode root project, create a folder named Views, and create a swift file inside named CardView with the following code inside:\"), mdx(\"pre\", null, mdx(\"code\", _extends({\n    parentName: \"pre\"\n  }, {\n    \"className\": \"language-swift\"\n  }), \"import SwiftUI\\n\\nstruct CardView: View {\\n\\n    var category = ExpenseCategory()\\n    @State var percent: CGFloat = 0.0\\n\\n    var body: some View {\\n        VStack{\\n            HStack(spacing: 20) {\\n                renderRing()\\n                renderDetails()\\n            }.frame(maxWidth: .infinity, maxHeight: 200)\\n                 .padding()\\n                .background(LinearGradient(gradient: Gradient(colors: category.colors) , startPoint: .leading, endPoint: .trailing) )\\n                .cornerRadius(20)\\n        }.onAppear {\\n            self.percent = self.category.percent\\n        }\\n    }\\n\\n    fileprivate func renderRing() -> some View {\\n        return RingView(percent: self.$percent)\\n        .modifier(PercentIndicator(value: self.percent * 100,color: .white, suffix: \\\"%\\\").animation(.easeIn(duration: 1)))\\n    }\\n\\n    fileprivate func renderDetails() -> some View{\\n        VStack(alignment: .leading) {\\n            Text(category.name).foregroundColor(.white)\\n            Text(\\\"$\\\\(String(format: \\\"%.2f\\\", category.amount))\\\").font(.title).foregroundColor(.white)\\n        }.frame(maxWidth: .infinity, alignment: .leading)\\n    }\\n}\\n\\nstruct CardView_Previews: PreviewProvider {\\n    static var previews: some View {\\n        CardView()\\n    }\\n}\\n\\n\")), mdx(\"p\", null, \"The above swift code just creates a card and applies a beautiful gradient on it.\\nThe only thing to note here is the modifier that animates the text. To show you how to animate text in swift ui, we will need to create a new folder named \", mdx(\"em\", {\n    parentName: \"p\"\n  }, \"Modifiers\"), \" and inside it add a swift file named \", mdx(\"em\", {\n    parentName: \"p\"\n  }, \"PercentAnimator.swift\"), \" with the following code inside:\"), mdx(\"pre\", null, mdx(\"code\", _extends({\n    parentName: \"pre\"\n  }, {\n    \"className\": \"language-swift\"\n  }), \"import SwiftUI\\n\\nstruct PercentAnimator: AnimatableModifier {\\n\\n    var value: CGFloat = 0\\n    var font: Font = .system(size: 18, weight: .light, design: .rounded)\\n    var color: Color = .white\\n    var prefix = \\\"\\\"\\n    var suffix = \\\"\\\"\\n\\n    var animatableData: CGFloat{\\n        get { value }\\n        set { value = newValue }\\n    }\\n\\n    func body(content: Content) -> some View {\\n        content\\n            .overlay(TextView(value: value, font: font, color: color, prefix: prefix,suffix: suffix))\\n\\n    }\\n\\n}\\n\\nstruct TextView: View {\\n    let value: CGFloat\\n    var font: Font = .footnote\\n    var color: Color = .white\\n    var prefix = \\\"\\\"\\n    var suffix = \\\"\\\"\\n\\n    var body: some View {\\n        Text(\\\"\\\\(prefix)\\\\(Int(value))\\\\(suffix)\\\")\\n            .foregroundColor(color)\\n            .font(font)\\n    }\\n}\\n\\n\")), mdx(\"p\", null, \"As you can see, animating text in swift ui is the same as animating  shapes using animatableData with some minor differences.\"), mdx(\"p\", null, \"The above code will not compile because you still haven\\u2019t created the \", mdx(\"inlineCode\", {\n    parentName: \"p\"\n  }, \"RingView\"), \". Go ahead and add\", mdx(\"em\", {\n    parentName: \"p\"\n  }, \"\\xA0RingView.swift\\xA0\"), \" file  and add the following code inside: \"), mdx(\"pre\", null, mdx(\"code\", _extends({\n    parentName: \"pre\"\n  }, {\n    \"className\": \"language-swift\"\n  }), \"struct RingView: View {\\n\\n    var strokeWidth: CGFloat = 10\\n    var size: CGSize = CGSize(width: 70, height: 70)\\n    var color = Color.white\\n    var pathColor = Color.white.opacity(0.4)\\n    @Binding var percent: CGFloat\\n\\n    var body: some View {\\n        ZStack {\\n            Circle()\\n                .stroke(style: StrokeStyle(lineWidth: strokeWidth, lineCap: .round))\\n                .frame(width: size.width, height: size.height)\\n                .foregroundColor(pathColor)\\n\\n            Circle()\\n                .trim(from: 0, to: percent )\\n                .stroke(style: StrokeStyle(lineWidth: strokeWidth, lineCap: .round))\\n                .animation(.easeIn(duration: 1))\\n                .frame(width: size.width, height: size.height)\\n                .foregroundColor(color)\\n                .rotationEffect(Angle(degrees: -90) )\\n        }\\n    }\\n}\\n\\nstruct RingView_Previews: PreviewProvider {\\n    static var previews: some View {\\n        RingView(percent: .constant(0.7))\\n    }\\n}\\n\\n\")), mdx(\"p\", null, \"That creates the ring view and handles its progress animation. I wrote a swift ui tutorial showing how to create and animate an Apple Watch like ring in using shapes in \", mdx(\"a\", _extends({\n    parentName: \"p\"\n  }, {\n    \"href\": \"https://liquidcoder.com/swiftui-ring-animation/\",\n    \"title\": \"Ring View animation in swift ui using shapes \"\n  }), \"this tutorial\"), \", check it out!\"), mdx(\"p\", null, \"In the same folder, create a new swift file named \", mdx(\"em\", {\n    parentName: \"p\"\n  }, \"BarView.swift\"), \" with the following code inside:\"), mdx(\"pre\", null, mdx(\"code\", _extends({\n    parentName: \"pre\"\n  }, {\n    \"className\": \"language-swift\"\n  }), \"\\nstruct BarView: View {\\n    var size: CGSize = .zero\\n    var expense = Expense.getRandom().first!\\n    var isSelected = false\\n    var onSelected: ((Expense)->()) = {_ in }\\n\\n    var body: some View {\\n        VStack {\\n            ZStack(alignment: .bottom) {\\n                Capsule()\\n                    .frame(width: 3, height: size.height)\\n                    .foregroundColor(Color.lightGray)\\n                Capsule()\\n                    .frame(width: 3, height: size.height * expense.percentConsumed)\\n                    .foregroundColor(isSelected ? Color.red : Color.purpleGray)\\n            }       .animation(.easeIn(duration: 1) )\\n\\n            Text(expense.month).font(.caption).foregroundColor(isSelected ? Color.red : Color.purpleGray)\\n        }.frame(maxWidth: .infinity)\\n            .onTapGesture {\\n                self.onSelected(self.expense)\\n        }\\n    }\\n}\\n\\n\")), mdx(\"p\", null, \"In the above code , we create a single bar view that will be re-used to create a \", mdx(\"inlineCode\", {\n    parentName: \"p\"\n  }, \"barchart\"), \" view for all 12 months. We also handle the selection of this single bar and sending the corresponding expense value for the selected month.\"), mdx(\"p\", null, \"Next, we will create the \", mdx(\"inlineCode\", {\n    parentName: \"p\"\n  }, \"barchartView\"), \". In the same folder, add a swift ui file  named \", mdx(\"em\", {\n    parentName: \"p\"\n  }, \"BarchartView.swift\"), \" and inside it , put the following code: \"), mdx(\"pre\", null, mdx(\"code\", _extends({\n    parentName: \"pre\"\n  }, {\n    \"className\": \"language-swift\"\n  }), \"import SwiftUI\\n\\nstruct BarChartView: View {\\n    var expenses = Expense.getRandom()\\n    @State var selectedExpense = Expense()\\n    var onSelected: ((Expense)->()) = {_ in }\\n\\n    var body: some View {\\n        GeometryReader { gr in\\n            HStack(alignment: .bottom, spacing: 3) {\\n                ForEach(self.expenses, id: \\\\.month){ expense in\\n                    BarView(size: gr.size, expense: expense, isSelected:  self.selectedExpense.month == expense.month, onSelected: { selectedExp in\\n                        self.selectedExpense = selectedExp\\n                        self.onSelected(selectedExp)\\n                    })\\n                }\\n            }.frame(maxWidth: .infinity ,maxHeight: .infinity, alignment: .bottom)\\n            .onAppear {\\n                self.selectedExpense = Expense.getRandom().first(where: { $0.month == Date.month })!\\n            }\\n        }\\n    }\\n}\\n\\nstruct BarChartView_Previews: PreviewProvider {\\n    static var previews: some View {\\n        BarChartView()\\n    }\\n}\\n\\n\")), mdx(\"p\", null, \"In the above code, we iterate through all 12 months, and for each month, we create a \", mdx(\"inlineCode\", {\n    parentName: \"p\"\n  }, \"BarView\"), \". Notice how we set the current month to be selected in \", mdx(\"inlineCode\", {\n    parentName: \"p\"\n  }, \"onAppear\"), \" because that block will always run as soon as the \", mdx(\"inlineCode\", {\n    parentName: \"p\"\n  }, \"HStack\"), \" appears.\"), mdx(\"p\", null, \"Lets now work on the  expense category section. In the views folder, add a swift ui file named \", mdx(\"em\", {\n    parentName: \"p\"\n  }, \"ExpenseCategoryView.swift\"), \" , and inside it add the following code: \"), mdx(\"pre\", null, mdx(\"code\", _extends({\n    parentName: \"pre\"\n  }, {\n    \"className\": \"language-swift\"\n  }), \"\\nstruct ExpenseCategoryView: View {\\n\\n    var category = ExpenseCategory()\\n    @State private var percent:CGFloat = 0.0\\n\\n    var body: some View {\\n        GeometryReader{ gr in\\n            ZStack(alignment: .leading) {\\n                self.renderHorizontalChart(with: gr.size)\\n                HStack{\\n                    self.renderRingView()\\n                    Text(self.category.name).font(.system(size: 15, weight: .light))\\n                    Spacer()\\n                    Text(\\\"$\\\\(String(format: \\\"%.2f\\\", self.category.amount) )\\\").font(.system(size: 15, weight: .light))\\n                }.padding(5)\\n                    .onAppear {\\n                        self.percent = self.category.percent\\n                }\\n            }\\n        }.frame(height: 60)\\n    }\\n\\n    fileprivate func renderRingView() -> some View {\\n        return RingView(strokeWidth: CGFloat(3), size: CGSize(width: 35, height: 35), color: self.category.colors.first!, pathColor: Color.lightGray, percent: self.$percent)\\n        .modifier(PercentAnimator(value: self.percent * 100, font: .caption,color: .textColor)\\n            .animation(.easeIn(duration: 1)))\\n    }\\n\\n    fileprivate func renderHorizontalChart(with size: CGSize) -> some View {\\n        return Rectangle().frame(width: size.width * self.percent, height: size.height, alignment: .leading)\\n        .foregroundColor(Color.lightGray)\\n        .animation(.easeIn(duration: 1))\\n    }\\n}\\n\\nstruct ExpenseCategoryView_Previews: PreviewProvider {\\n    static var previews: some View {\\n        ExpenseCategoryView()\\n    }\\n}\\n\\n\")), mdx(\"p\", null, \"This code creates one category row. Let\\u2019s now create  the view that will generate the whole list of categories. \"), mdx(\"p\", null, \"So in the same folder, add swift ui file named \", mdx(\"em\", {\n    parentName: \"p\"\n  }, \"ExpensesBreakdownView.swift\"), \" , and put the following code inside:\"), mdx(\"pre\", null, mdx(\"code\", _extends({\n    parentName: \"pre\"\n  }, {\n    \"className\": \"language-swift\"\n  }), \"import SwiftUI\\n\\nstruct ExpensesBreakdownView: View {\\n\\n    @ObservedObject private var expensesBreakDown = ExpensesBreakDown()\\n    var categories = [ExpenseCategory]()\\n    @State var percent:CGFloat = 0.0\\n\\n    var body: some View {\\n        VStack{\\n            HStack{\\n                Text(\\\"Total expenses\\\").bold()\\n                Spacer()\\n                Text(\\\"$\\\\(String(format: \\\"%.2f\\\", expensesBreakDown.expense.consumed))\\\").bold()\\n            }.padding(.vertical)\\n\\n            VStack(spacing: 0) {\\n                ForEach(categories){ category in\\n                    ExpenseCategoryView(category: category)\\n                }\\n            }\\n        }\\n    }\\n}\\n\\nstruct ExpensesBreakdownView_Previews: PreviewProvider {\\n    static var previews: some View {\\n        ExpensesBreakdownView()\\n    }\\n}\\n\\n\")), mdx(\"p\", null, \"This code just iterate through the categories arrays and renders a list of \", mdx(\"inlineCode\", {\n    parentName: \"p\"\n  }, \"ExpenseCategoryView\"), \".\"), mdx(\"h2\", null, \"Put everything together\"), mdx(\"p\", null, \"In your ContentView.swift file,  replace everything inside with the following:\"), mdx(\"pre\", null, mdx(\"code\", _extends({\n    parentName: \"pre\"\n  }, {\n    \"className\": \"language-swift\"\n  }), \"\\nimport SwiftUI\\n\\nstruct ContentView: View {\\n    @ObservedObject var expensesBreakDown = ExpensesBreakDown()\\n\\n    var body: some View {\\n\\n        return VStack{\\n\\n            renderHeader()\\n            ScrollView(showsIndicators: false) {\\n                VStack{\\n                    renderCards()\\n                    renderBarchart()\\n                    ExpensesBreakdownView(categories: expensesBreakDown.categories)\\n                        .padding(.horizontal)\\n                }\\n            }\\n\\n        }.frame(maxHeight: .infinity,alignment: .top)\\n            .padding(.vertical)\\n    }\\n\\n     fileprivate func renderCards() -> some View {\\n         return ScrollView(.horizontal, showsIndicators: false) {\\n             HStack(spacing: 10) {\\n                 ForEach(expensesBreakDown.categories){ category in\\n                     CardView(category: (category))\\n                        .frame(width: 330, height: UIScreen.main.bounds.height * 0.22)\\n                 }\\n             }.padding(.horizontal)\\n         }\\n     }\\n\\n    fileprivate func renderHeader() -> some View{\\n        HStack{\\n            VStack(alignment: .leading) {\\n                Text(Date.fullMonthName(short: expensesBreakDown.expense.month)).font(.title)\\n                Text(\\\"2019\\\").foregroundColor(Color.purpleGray)\\n            }\\n            Spacer()\\n        }.padding(.horizontal)\\n    }\\n\\n    fileprivate func renderBarchart() -> some View {\\n        return BarChartView(onSelected: { selectedExp in\\n            self.expensesBreakDown.generateRandom(selectedExp)\\n        }).frame(height: 50)\\n        .padding(.vertical, 20)\\n        .padding(.horizontal)\\n    }\\n}\\n\\nstruct ContentView_Previews: PreviewProvider {\\n    static var previews: some View {\\n        ContentView()\\n    }\\n}\\n\\n\")), mdx(\"p\", null, \"Don\\u2019t be threatened by the above code. It just puts everything we have just done together.\"), mdx(\"h2\", null, \"Conclusion\"), mdx(\"p\", null, \"That\\u2019s it folks\\u2026 Later this week, I am planning to start a series showing you how to build a very complex app, and  if you guys like it, I will start releasing similar tutorial series. So make sure you are subscribed and share this tutorial. Happy Coding!!!\"));\n}\n;\nMDXContent.isMDXComponent = true;","excerpt":"Introduction In this week’s swift ui tutorial,  we are going to build  a fairly complex ui with animations. You are going to learn how to animation various shapes in swift ui and how to animate text while designing a complex user interface.  Let’s start writing some swift code, shall we…"}}}},"pageContext":{"slug":"expense-report-ui"}},"staticQueryHashes":["1047155515","1278771865","2517639938","2517639938","2537039069","3452127246","3566879862","3891201089","439617394","670651827"]}