Created
February 14, 2021 02:54
-
-
Save notoroid/5f9aef867129222b072faaa2d4c717ba to your computer and use it in GitHub Desktop.
Sample of using SwifUI's rotationEffect modifier.
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
import SwiftUI | |
enum MechanicalArm { | |
static let colors: [Color] = [Color(UIColor(red: 0.349, green: 0.671, blue: 0.914, alpha: 1.000)) /*.red, .green, .yellow, .blue, .yellow*/] | |
static let manipulatorJointEdge = CGFloat(16.5); static let manipulatorRootEdge = CGFloat(37.5) | |
static let manipulatorWidth = CGFloat(9); static let manipulatorFirstLength = CGFloat(60); static let manipulatorOtherLength = CGFloat(37.5) | |
static let armLength = CGFloat(105); static let armWidth = CGFloat(37.5); static let armJointEdge = CGFloat(16.5) | |
static let standWidth = CGFloat(75); static let standHeighth = CGFloat(60) | |
static let defaultArmAngle = Double(0); static let defaultWristAngle = Double(-45); static let defaultFingerAngle = Double(40) | |
} | |
struct ArmShape: Shape { | |
func path(in rect: CGRect) -> Path { | |
let bezierPath = UIBezierPath() | |
bezierPath.move(to: CGPoint(x: rect.maxX - 5, y: rect.minY + 14)) | |
bezierPath.addLine(to: CGPoint(x: rect.maxX, y: rect.maxY - 19)) | |
bezierPath.addCurve(to: CGPoint(x: rect.minX + 0.50000 * rect.width, y: rect.maxY), controlPoint1: CGPoint(x: rect.maxX, y: rect.maxY - 8.51), controlPoint2: CGPoint(x: rect.minX + 0.77614 * rect.width, y: rect.maxY)) | |
bezierPath.addCurve(to: CGPoint(x: rect.minX, y: rect.maxY - 19), controlPoint1: CGPoint(x: rect.minX + 0.22386 * rect.width, y: rect.maxY), controlPoint2: CGPoint(x: rect.minX, y: rect.maxY - 8.51)) | |
bezierPath.addLine(to: CGPoint(x: rect.minX + 5, y: rect.minY + 14)) | |
bezierPath.addCurve(to: CGPoint(x: rect.minX + 9.2, y: rect.minY + 4), controlPoint1: CGPoint(x: rect.minX + 5, y: rect.minY + 10.08), controlPoint2: CGPoint(x: rect.minX + 6.61, y: rect.minY + 6.54)) | |
bezierPath.addCurve(to: CGPoint(x: rect.minX + 0.50000 * rect.width, y: rect.minY), controlPoint1: CGPoint(x: rect.minX + 11.72, y: rect.minY + 1.53), controlPoint2: CGPoint(x: rect.minX + 0.39957 * rect.width, y: rect.minY)) | |
bezierPath.addCurve(to: CGPoint(x: rect.maxX - 5, y: rect.minY + 14), controlPoint1: CGPoint(x: rect.minX + 0.70347 * rect.width, y: rect.minY), controlPoint2: CGPoint(x: rect.maxX - 5, y: rect.minY + 6.27)) | |
bezierPath.close() | |
return Path(bezierPath.cgPath) | |
} | |
} | |
struct ContentView: View { | |
@State var armAngle = MechanicalArm.defaultArmAngle | |
@State var wristAngle = MechanicalArm.defaultWristAngle | |
@State var fingerAngle = MechanicalArm.defaultFingerAngle | |
func fingerView(length: CGFloat) -> some View { | |
Rectangle().foregroundColor(MechanicalArm.colors[3 % MechanicalArm.colors.count]).frame(width: MechanicalArm.manipulatorWidth, height: length) | |
.overlay( | |
Circle().foregroundColor(MechanicalArm.colors[4 % MechanicalArm.colors.count]).frame(width: MechanicalArm.manipulatorJointEdge, height: MechanicalArm.manipulatorJointEdge) | |
.offset(x: 0, y: MechanicalArm.manipulatorJointEdge * 0.5) | |
, alignment: .bottom) | |
} | |
static let manipulatorVector: [Double] = [1,-1] | |
func manipulatorView() -> some View { | |
Rectangle().overlay(ZStack(alignment: Alignment(horizontal: .center, vertical: .bottom)){ | |
ForEach(0..<Self.manipulatorVector.count) { index in | |
fingerView(length: MechanicalArm.manipulatorFirstLength).overlay( | |
fingerView(length: MechanicalArm.manipulatorOtherLength).overlay( | |
fingerView(length: MechanicalArm.manipulatorOtherLength) | |
.rotationEffect(Angle(degrees: -1 * Self.manipulatorVector[index] * fingerAngle), anchor: .bottom) | |
.padding(MechanicalArm.manipulatorOtherLength) | |
, alignment: .bottom) | |
.rotationEffect(Angle(degrees: -1 * Self.manipulatorVector[index] * (80-fingerAngle) ), anchor: .bottom) | |
.padding(MechanicalArm.manipulatorFirstLength) | |
, alignment: .bottom) | |
.rotationEffect(Angle(degrees: Self.manipulatorVector[index] * (fingerAngle * 0.5 + 25) ), anchor: .bottom ) | |
} | |
} | |
, alignment: .bottom) | |
.foregroundColor(.clear).frame(width: MechanicalArm.manipulatorRootEdge, height: MechanicalArm.manipulatorRootEdge) | |
} | |
func mechanicalArmView() -> some View { | |
ArmShape().foregroundColor(MechanicalArm.colors[1 % MechanicalArm.colors.count]).frame(width: MechanicalArm.armWidth, height: MechanicalArm.armLength) | |
.overlay( | |
Circle().foregroundColor(MechanicalArm.colors[2 % MechanicalArm.colors.count]).frame(width: MechanicalArm.armJointEdge, height: MechanicalArm.armJointEdge) | |
.offset(x: 0, y: 7.5) | |
, alignment: .bottom) | |
} | |
var body: some View { | |
VStack { | |
Button("Reset Parameter") { | |
withAnimation { | |
self.armAngle = MechanicalArm.defaultArmAngle | |
self.wristAngle = MechanicalArm.defaultWristAngle | |
self.fingerAngle = MechanicalArm.defaultFingerAngle | |
} | |
} | |
Spacer() | |
Rectangle().overlay( | |
mechanicalArmView().overlay( | |
mechanicalArmView().overlay( | |
manipulatorView().foregroundColor(.red) | |
.rotationEffect(Angle(degrees: wristAngle), anchor: .bottom) | |
.padding(MechanicalArm.armLength) | |
, alignment: .bottom) | |
.rotationEffect(Angle(degrees: armAngle - 90), anchor: .bottom) | |
.padding(MechanicalArm.armLength) | |
, alignment: .bottom) | |
.rotationEffect(Angle(degrees: armAngle * 1.5 + 45), anchor: .bottom) | |
.padding(MechanicalArm.standHeighth) | |
, alignment: .bottom) | |
.foregroundColor(.clear).frame(width: MechanicalArm.standWidth, height: MechanicalArm.standHeighth) | |
.background( MechanicalArm.colors[0 % MechanicalArm.colors.count]) | |
Group { | |
HStack { Text("Arm: \(armAngle)"); Spacer() }; Slider(value: $armAngle, in: -45...45); Divider() | |
HStack { Text("Wrist: \(wristAngle)"); Spacer() }; Slider(value: $wristAngle, in: -80...80); Divider() | |
HStack { Text("Finger: \(fingerAngle)"); Spacer() }; Slider(value: $fingerAngle, in: 30...60); Divider() | |
} | |
} | |
.padding(15) | |
} | |
} |
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment