Skip to content

Instantly share code, notes, and snippets.

@andreamazz
Last active January 31, 2020 14:26
Show Gist options
  • Save andreamazz/732f0432ab9a0058a9872d0babbc909c to your computer and use it in GitHub Desktop.
Save andreamazz/732f0432ab9a0058a9872d0babbc909c to your computer and use it in GitHub Desktop.
Card UI prototype made with SwiftUI
//
// ProjectsScene.swift
// Fancytracker
//
// Created by Andrea Mazzini on 26/01/2020.
// Copyright © 2020 Fancy Pixel S.r.l. All rights reserved.
//
import SwiftUI
fileprivate let Padding = 16
fileprivate let Offset = 100
struct Item {
var hex: String
var color: Color
}
let colors: [Item] = [
Item(hex: "#1abc9c", color: Color(red: 0.00, green: 0.77, blue: 0.68)),
Item(hex: "#f1c40f", color: Color(red: 0.96, green: 0.81, blue: 0.18)),
Item(hex: "#3498db", color: Color(red: 0.21, green: 0.66, blue: 0.88)),
Item(hex: "#9b59b6", color: Color(red: 0.69, green: 0.44, blue: 0.76)),
Item(hex: "#34495e", color: Color(red: 0.26, green: 0.36, blue: 0.44)),
Item(hex: "#e74c3c", color: Color(red: 0.95, green: 0.40, blue: 0.31))
]
struct CardsScene: View {
@State var selected: Int?
func offsetFor(outer: GeometryProxy, inner: GeometryProxy, index: Int) -> CGFloat {
var padding = 0
if index > 1 {
padding = (index - 1) * Padding
}
return -(outer.frame(in: .global).minY - inner.frame(in: .global).minY) + CGFloat((Padding + Offset) * index - padding)
}
var body: some View {
ZStack {
Color("background")
.edgesIgnoringSafeArea(.all)
VStack {
Text("Colors").foregroundColor(Color.white)
GeometryReader { outsideProxy in
ScrollView {
Group {
VStack {
ForEach(0..<colors.endIndex, id: \.self) { index in
GeometryReader { insideProxy in
return CardView(color: colors[index], index: index, selected: self.$selected, scrollOffset: self.offsetFor(outer: outsideProxy, inner: insideProxy, index: index), screenHeight: outsideProxy.frame(in: .global).size.height)
.onTapGesture {
withAnimation {
self.selected = index
}
}
}
}
}
Spacer().frame(height: CGFloat(colors.count * Offset + Offset))
}
.frame(maxWidth: .infinity, maxHeight: .infinity)
}
}
}
}
}
}
struct CardsScene_Previews: PreviewProvider {
static var previews: some View {
return CardsScene()
}
}
struct CardView: View {
@State var dragPosition: CGFloat = 0
var color: Item
var index: Int
@Binding var selected: Int?
var scrollOffset: CGFloat
var screenHeight: CGFloat
var body: some View {
var isSelected = false
var shouldLeave = false
if let selected = selected {
isSelected = selected == index
shouldLeave = index > selected
}
return VStack {
Text(color.hex)
.foregroundColor(Color.white)
.font(.system(size: 24, weight: .bold, design: .rounded))
Spacer()
}
.padding()
.frame(maxWidth: .infinity, alignment: .top)
.frame(height: isSelected ? screenHeight : 300)
.background(color.color)
.clipShape(RoundedRectangle(cornerRadius: 10, style: .continuous))
.shadow(radius: 4)
.padding(isSelected ? 0 : 16)
.offset(x: 0, y: CGFloat(index) * CGFloat(Offset))
.offset(x: 0, y: isSelected ? -scrollOffset + CGFloat(Padding) : 0)
.offset(x: 0, y: shouldLeave ? screen.height : 0)
.offset(x: 0, y: dragPosition)
.animation(Animation.spring())
.gesture(isSelected ?
DragGesture().onChanged { (value) in
self.dragPosition = value.translation.height
}
.onEnded { (value) in
withAnimation {
self.selected = nil
self.dragPosition = 0
}
}
: nil)
}
}
let screen = UIScreen.main.bounds
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment