Skip to content

Instantly share code, notes, and snippets.

@heestand-xyz
Created November 6, 2019 15:22
Show Gist options
  • Save heestand-xyz/3f7a17e065127c01ae9056d63d9c9f7b to your computer and use it in GitHub Desktop.
Save heestand-xyz/3f7a17e065127c01ae9056d63d9c9f7b to your computer and use it in GitHub Desktop.
Dile View
import SwiftUI
struct DileView<Content: View>: View {
let kColCount: Int = 3
let scale: CGFloat
let defaultIndex: Int
let options: () -> ([Content])
let selected: (Int) -> ()
@State var index: Int = 0
@State var open: Bool = false
init(scale: CGFloat, defaultIndex: Int = 0, @DileBuilder<Content> with options: @escaping () -> ([Content]), selected: @escaping (Int) -> ()) {
self.scale = scale
self.defaultIndex = defaultIndex
self.options = options
self.selected = selected
}
var body: some View {
ZStack {
Button(action: {
withAnimation {
self.open = false
}
}) {
Circle()
.frame(width: scale / 6, height: scale / 6)
.opacity(open ? 1.0 : 0.0)
}
ForEach(0..<options().count) { i in
Button(action: {
if !self.open {
withAnimation {
self.open = true
}
} else {
self.index = i
self.selected(i)
withAnimation {
self.open = false
}
}
}) {
self.options()[i]
}
.offset(x: self.offset(for: i).x, y: self.offset(for: i).y)
.opacity(self.open ? 1.0 : self.index == i ? 1.0 : 0.0)
}
}
.onAppear {
self.index = self.defaultIndex
}
}
func offset(for index: Int) -> CGPoint {
if !open && self.index == index { return .zero }
let count = self.options().count
let rowCount = Int(CGFloat(count) / CGFloat(kColCount))
let reverseIndex = count - index - 1
let ix = reverseIndex % kColCount
let iy = Int(CGFloat(reverseIndex) / CGFloat(kColCount))
let leftCount = min(count - iy * kColCount, kColCount)
let xCenter = CGFloat(ix) - CGFloat(leftCount - 1) / 2
let x = xCenter * -scale
let y = CGFloat(iy) * scale - scale - CGFloat(rowCount) * scale
return CGPoint(x: x, y: y)
}
}
@_functionBuilder
public struct DileBuilder<Content: View> {
public static func buildBlock(_ children: Content...) -> [Content] {
children
}
}
struct DileView_Previews: PreviewProvider {
static var previews: some View {
DileView(scale: 30, defaultIndex: 0, with: {
Image(systemName: "a.circle")
Image(systemName: "b.circle")
Image(systemName: "c.circle")
Image(systemName: "d.circle")
Image(systemName: "e.circle")
Image(systemName: "f.circle")
Image(systemName: "g.circle")
Image(systemName: "h.circle")
}, selected: { i in })
}
}
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment