teratail header banner
teratail header banner
質問するログイン新規登録

質問編集履歴

2

RAMPaperSwitch classを書き換えた結果を追記しました

2020/01/17 20:40

投稿

masayoshi555
masayoshi555

スコア9

title CHANGED
File without changes
body CHANGED
@@ -59,6 +59,24 @@
59
59
  ```error
60
60
  Could not cast value of type 'UISwitch' (0x7fff898b23a0) to 'RAMPaperSwitch.RAMPaperSwitch' (0x110049c98).
61
61
  ```
62
+ ### RAMPaperSwitch classを編集(2020/1/18 05:30追記)
63
+ 以下に記載のRAMPaperSwitch class内のUIViewであるが故に、
64
+ 今回のcellでは表示できないのではないかと思い、UIView(3箇所)を全てUITableViewCellに変更し
65
+ 実行しましたが、switchは表示されませんでした。
66
+ ```
67
+ public required init(view: UIView?, color: UIColor?) {
68
+ super.init(frame: CGRect.zero)
69
+ onTintColor = color
70
+ self.commonInit(view)
71
+ }
72
+ ```
73
+ その際、ここにエラーが出たのでsuperview as? UITableViewCellとしました
74
+ ```
75
+ override open func awakeFromNib() {
76
+ self.commonInit(parentView ?? superview)
77
+ super.awakeFromNib()
78
+ }
79
+ ```
62
80
  ###PaperSwitch
63
81
  PaperSwitch自体は本来storyboardで配置したswitchのclassをRAMPaperSwitchと
64
82
  指定し、onTintColorを指定するだけで利用できると言う優れものです。

1

RAMPaperSwitch classのコードを追記しました

2020/01/17 20:40

投稿

masayoshi555
masayoshi555

スコア9

title CHANGED
File without changes
body CHANGED
@@ -65,4 +65,174 @@
65
65
  通常の使い方(view内)での作動は確認できております。
66
66
  ![イメージ説明](7bd4ca928b91927ace024aecc8734595.png)
67
67
  ![イメージ説明](ccfc0f43b50c7edd519526863fff1d33.png)
68
- ![イメージ説明](332de4af429318409922a753e3eb7afe.gif)
68
+ ![イメージ説明](332de4af429318409922a753e3eb7afe.gif)
69
+ ```
70
+ open class RAMPaperSwitch: UISwitch, CAAnimationDelegate {
71
+
72
+ struct Constants {
73
+ static let scale = "transform.scale"
74
+ static let up = "scaleUp"
75
+ static let down = "scaleDown"
76
+ }
77
+
78
+ /// The total duration of the animations, measured in seconds. Default 0.35
79
+ @IBInspectable open var duration: Double = 0.35
80
+
81
+ /// Closuer call when animation start
82
+ open var animationDidStartClosure = {(onAnimation: Bool) -> Void in }
83
+
84
+ /// Closuer call when animation finish
85
+ open var animationDidStopClosure = {(onAnimation: Bool, finished: Bool) -> Void in }
86
+
87
+ fileprivate var shape: CAShapeLayer! = CAShapeLayer()
88
+ fileprivate var radius: CGFloat = 0.0
89
+ fileprivate var oldState = false
90
+
91
+ fileprivate var defaultTintColor: UIColor?
92
+ @IBOutlet open var parentView: UIView? {
93
+ didSet {
94
+ defaultTintColor = parentView?.backgroundColor
95
+ }
96
+ }
97
+
98
+ // MARK: - Initialization
99
+
100
+ /**
101
+ Returns an initialized switch object.
102
+
103
+ - parameter view: animatable view
104
+ - parameter color: The color which fill view.
105
+
106
+ - returns: An initialized UISwitch object.
107
+ */
108
+ public required init(view: UIView?, color: UIColor?) {
109
+ super.init(frame: CGRect.zero)
110
+ onTintColor = color
111
+ self.commonInit(view)
112
+ }
113
+
114
+ public required init?(coder aDecoder: NSCoder) {
115
+ super.init(coder: aDecoder)
116
+ }
117
+
118
+ override open func awakeFromNib() {
119
+ self.commonInit(parentView ?? superview)
120
+ super.awakeFromNib()
121
+ }
122
+
123
+ // MARK: Helpers
124
+ fileprivate func commonInit(_ parentView: UIView?) {
125
+ guard let onTintColor = self.onTintColor else {
126
+ fatalError("set tint color")
127
+ }
128
+ self.parentView = parentView
129
+ defaultTintColor = parentView?.backgroundColor
130
+
131
+ layer.borderWidth = 0.5
132
+ layer.borderColor = UIColor.white.cgColor
133
+ layer.cornerRadius = frame.size.height / 2
134
+
135
+ shape.fillColor = onTintColor.cgColor
136
+ shape.masksToBounds = true
137
+
138
+ parentView?.layer.insertSublayer(shape, at: 0)
139
+ parentView?.layer.masksToBounds = true
140
+
141
+ showShapeIfNeed()
142
+
143
+ addTarget(self, action: #selector(RAMPaperSwitch.switchChanged), for: UIControl.Event.valueChanged)
144
+ }
145
+
146
+ override open func layoutSubviews() {
147
+
148
+ if let parentView = self.parentView {
149
+ let x:CGFloat = max(center.x, parentView.frame.size.width - frame.midX)
150
+ let y:CGFloat = max(center.y, parentView.frame.size.height - frame.midY)
151
+ radius = sqrt(x*x + y*y)
152
+ }
153
+
154
+ let additional = parentView == superview ? CGPoint.zero : (superview?.frame.origin ?? CGPoint.zero)
155
+
156
+ shape.frame = CGRect(x: center.x - radius + additional.x - 2, y: center.y - radius + additional.y, width: radius * 2, height: radius * 2)
157
+ shape.anchorPoint = CGPoint(x: 0.5, y: 0.5)
158
+ shape.path = UIBezierPath(ovalIn: CGRect(x: 0, y: 0, width: radius * 2, height: radius * 2)).cgPath
159
+ }
160
+
161
+ // MARK: - Public
162
+ open override func setOn(_ on: Bool, animated: Bool) {
163
+ let changed:Bool = on != self.isOn
164
+
165
+ super.setOn(on, animated: animated)
166
+
167
+ if changed {
168
+ switchChangeWithAnimation(animated)
169
+ }
170
+ }
171
+
172
+ // MARK: - Private
173
+ fileprivate func showShapeIfNeed() {
174
+ shape.transform = isOn ? CATransform3DMakeScale(1.0, 1.0, 1.0) : CATransform3DMakeScale(0.0001, 0.0001, 0.0001)
175
+ }
176
+
177
+ @objc internal func switchChanged() {
178
+ switchChangeWithAnimation(true)
179
+ }
180
+
181
+ // MARK: - Animations
182
+ fileprivate func animateKeyPath(_ keyPath: String, fromValue from: CGFloat?, toValue to: CGFloat, timing timingFunction: String) -> CABasicAnimation {
183
+
184
+ let animation:CABasicAnimation = CABasicAnimation(keyPath: keyPath)
185
+
186
+ animation.fromValue = from
187
+ animation.toValue = to
188
+ animation.repeatCount = 1
189
+ animation.timingFunction = CAMediaTimingFunction(name: convertToCAMediaTimingFunctionName(timingFunction))
190
+ animation.isRemovedOnCompletion = false
191
+ animation.fillMode = CAMediaTimingFillMode.forwards
192
+ animation.duration = duration
193
+ animation.delegate = self
194
+
195
+ return animation
196
+ }
197
+
198
+ fileprivate func switchChangeWithAnimation(_ animation: Bool) {
199
+ guard let onTintColor = self.onTintColor else {
200
+ return
201
+ }
202
+
203
+ shape.fillColor = onTintColor.cgColor
204
+
205
+ if isOn {
206
+ let scaleAnimation:CABasicAnimation = animateKeyPath(Constants.scale,
207
+ fromValue: 0.01,
208
+ toValue: 1.0,
209
+ timing:convertFromCAMediaTimingFunctionName(CAMediaTimingFunctionName.easeIn));
210
+ if animation == false { scaleAnimation.duration = 0.0001 }
211
+
212
+ shape.add(scaleAnimation, forKey: Constants.up)
213
+ } else {
214
+ let scaleAnimation:CABasicAnimation = animateKeyPath(Constants.scale,
215
+ fromValue: 1.0,
216
+ toValue: 0.01,
217
+ timing:convertFromCAMediaTimingFunctionName(CAMediaTimingFunctionName.easeOut));
218
+ if animation == false { scaleAnimation.duration = 0.0001 }
219
+
220
+ shape.add(scaleAnimation, forKey: Constants.down)
221
+ }
222
+ }
223
+
224
+ //MARK: - CAAnimation Delegate
225
+ open func animationDidStart(_ anim: CAAnimation) {
226
+ parentView?.backgroundColor = defaultTintColor
227
+ animationDidStartClosure(isOn)
228
+ }
229
+
230
+ open func animationDidStop(_ anim: CAAnimation, finished flag: Bool) {
231
+ if flag == true {
232
+ parentView?.backgroundColor = isOn == true ? onTintColor : defaultTintColor
233
+ }
234
+
235
+ animationDidStopClosure(isOn, flag)
236
+ }
237
+ }
238
+ ```