Created
December 21, 2019 11:24
-
-
Save OlesenkoViktor/76845c5448b421ead0a2303af2b1161d to your computer and use it in GitHub Desktop.
UIView with embedded slot animation using scrollview
This file contains hidden or 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 UIKit | |
class SlotView: UIView { | |
enum Item { | |
case success | |
case failure | |
case number | |
} | |
// MARK: - Outlets | |
@IBOutlet private var scrollView : UIScrollView! | |
@IBOutlet private var contentView: UIStackView! | |
// MARK: - Variables | |
private let rowHeight: CGFloat = 29 | |
private var space : CGFloat { contentView.spacing } | |
private var halfSpace: CGFloat { space / 2 } | |
var number: Int! | |
private var items: Array<Item> = [ | |
.number, .success, .failure, | |
.number, .success, .failure, | |
.number | |
] | |
// MARK: - Init | |
override init(frame: CGRect) { | |
super.init(frame: frame) | |
initialize() | |
} | |
required init?(coder aDecoder: NSCoder) { | |
super.init(coder: aDecoder) | |
initialize() | |
} | |
override func initialize() { | |
super.initialize() | |
generateContent() | |
scrollView.contentInset = UIEdgeInsets.init(top: halfSpace, left: 0, bottom: halfSpace, right: 0) | |
resetScrollPosition() | |
} | |
private func generateContent() { | |
for item in items { | |
let containerView = UIView.init(frame: CGRect.init(x: 0, y: 0, width: contentView.bounds.width, height: rowHeight)) | |
containerView.translatesAutoresizingMaskIntoConstraints = false | |
containerView.backgroundColor = .clear | |
containerView.heightAnchor.constraint(equalToConstant: rowHeight).isActive = true | |
let imageView = UIImageView.init() | |
imageView.translatesAutoresizingMaskIntoConstraints = false | |
switch item { | |
case .number : imageView.image = UIImage.init(named: "slot_number") | |
case .success: imageView.image = UIImage.init(named: "slot_check") | |
case .failure: imageView.image = UIImage.init(named: "slot_cross") | |
} | |
containerView.addSubview(imageView) | |
imageView.centerYAnchor.constraint(equalTo: containerView.centerYAnchor).isActive = true | |
imageView.centerXAnchor.constraint(equalTo: containerView.centerXAnchor).isActive = true | |
self.contentView.addArrangedSubview(containerView) | |
} | |
contentView.layoutIfNeeded() | |
} | |
// MARK: - Actions | |
private var isRolling: Bool = false | |
func startScroll() { | |
isRolling = true | |
UIView.animate( | |
withDuration: 0.05, | |
delay: 0, | |
options: .curveLinear, | |
animations: { | |
self.scrollView.contentOffset.y -= self.rowHeight + self.space | |
}, | |
completion: { _ in | |
if self.isRolling { | |
if self.scrollView.contentOffset.y <= 0 { | |
self.resetScrollPosition() | |
} | |
self.startScroll() | |
} else { | |
self.scrollView.contentOffset.y = self.scrollView.contentSize.height - (self.rowHeight + self.halfSpace) | |
UIView.animate( | |
withDuration: 0.7, | |
delay: 0, | |
options: .curveEaseOut, | |
animations: { | |
self.scrollView.contentOffset.y -= 6 * (self.rowHeight + self.space) | |
}, | |
completion: nil | |
) | |
} | |
}) | |
} | |
private func resetScrollPosition() { | |
self.scrollView.contentOffset.y = 3 * (rowHeight + space) - halfSpace | |
} | |
func stopScroll() { | |
isRolling = false | |
} | |
} |
This file contains hidden or 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
<?xml version="1.0" encoding="UTF-8"?> | |
<document type="com.apple.InterfaceBuilder3.CocoaTouch.XIB" version="3.0" toolsVersion="15505" targetRuntime="iOS.CocoaTouch" propertyAccessControl="none" useAutolayout="YES" useTraitCollections="YES" useSafeAreas="YES" colorMatched="YES"> | |
<device id="retina6_1" orientation="portrait" appearance="light"/> | |
<dependencies> | |
<deployment identifier="iOS"/> | |
<plugIn identifier="com.apple.InterfaceBuilder.IBCocoaTouchPlugin" version="15510"/> | |
<capability name="Named colors" minToolsVersion="9.0"/> | |
<capability name="documents saved in the Xcode 8 format" minToolsVersion="8.0"/> | |
</dependencies> | |
<objects> | |
<placeholder placeholderIdentifier="IBFilesOwner" id="-1" userLabel="File's Owner" customClass="SlotView" customModule="Boxiz" customModuleProvider="target"> | |
<connections> | |
<outlet property="contentView" destination="hOu-DZ-dEc" id="0ga-FE-T8a"/> | |
<outlet property="scrollView" destination="8Td-7J-sbt" id="GKv-iN-UUS"/> | |
</connections> | |
</placeholder> | |
<placeholder placeholderIdentifier="IBFirstResponder" id="-2" customClass="UIResponder"/> | |
<view contentMode="scaleToFill" insetsLayoutMarginsFromSafeArea="NO" id="OzF-A2-QeO"> | |
<rect key="frame" x="0.0" y="0.0" width="60" height="34"/> | |
<autoresizingMask key="autoresizingMask" flexibleMaxX="YES" flexibleMaxY="YES"/> | |
<subviews> | |
<view clipsSubviews="YES" contentMode="scaleToFill" translatesAutoresizingMaskIntoConstraints="NO" id="B7s-rc-aHU"> | |
<rect key="frame" x="0.0" y="0.0" width="60" height="34"/> | |
<subviews> | |
<scrollView clipsSubviews="YES" multipleTouchEnabled="YES" contentMode="scaleToFill" showsHorizontalScrollIndicator="NO" showsVerticalScrollIndicator="NO" translatesAutoresizingMaskIntoConstraints="NO" id="8Td-7J-sbt"> | |
<rect key="frame" x="0.0" y="0.0" width="60" height="34"/> | |
<subviews> | |
<stackView opaque="NO" contentMode="scaleToFill" axis="vertical" distribution="fillEqually" spacing="5" translatesAutoresizingMaskIntoConstraints="NO" id="hOu-DZ-dEc"> | |
<rect key="frame" x="0.0" y="0.0" width="60" height="34"/> | |
<constraints> | |
<constraint firstAttribute="height" constant="34" placeholder="YES" id="Yh2-E0-P1n"/> | |
</constraints> | |
</stackView> | |
</subviews> | |
<constraints> | |
<constraint firstItem="hOu-DZ-dEc" firstAttribute="leading" secondItem="8Td-7J-sbt" secondAttribute="leading" id="3s2-7g-7N2"/> | |
<constraint firstItem="hOu-DZ-dEc" firstAttribute="top" secondItem="8Td-7J-sbt" secondAttribute="top" id="9Ls-3E-KUt"/> | |
<constraint firstItem="hOu-DZ-dEc" firstAttribute="centerX" secondItem="8Td-7J-sbt" secondAttribute="centerX" id="MiD-2e-yXL"/> | |
<constraint firstAttribute="bottom" secondItem="hOu-DZ-dEc" secondAttribute="bottom" id="QOs-Ac-tNw"/> | |
<constraint firstAttribute="trailing" secondItem="hOu-DZ-dEc" secondAttribute="trailing" id="tUn-hE-b70"/> | |
</constraints> | |
</scrollView> | |
</subviews> | |
<color key="backgroundColor" name="Base_Blue"/> | |
<constraints> | |
<constraint firstAttribute="trailing" secondItem="8Td-7J-sbt" secondAttribute="trailing" id="9jI-uA-E1s"/> | |
<constraint firstItem="8Td-7J-sbt" firstAttribute="leading" secondItem="B7s-rc-aHU" secondAttribute="leading" id="PYl-3H-y9r"/> | |
<constraint firstItem="8Td-7J-sbt" firstAttribute="top" secondItem="B7s-rc-aHU" secondAttribute="top" id="b0F-pS-Whd"/> | |
<constraint firstAttribute="bottom" secondItem="8Td-7J-sbt" secondAttribute="bottom" id="tCz-Gv-7Zo"/> | |
</constraints> | |
<userDefinedRuntimeAttributes> | |
<userDefinedRuntimeAttribute type="number" keyPath="cornerRadius"> | |
<real key="value" value="6"/> | |
</userDefinedRuntimeAttribute> | |
</userDefinedRuntimeAttributes> | |
</view> | |
</subviews> | |
<color key="backgroundColor" white="0.0" alpha="0.0" colorSpace="custom" customColorSpace="genericGamma22GrayColorSpace"/> | |
<constraints> | |
<constraint firstItem="B7s-rc-aHU" firstAttribute="top" secondItem="OzF-A2-QeO" secondAttribute="top" id="8cz-0u-PKn"/> | |
<constraint firstAttribute="trailing" secondItem="B7s-rc-aHU" secondAttribute="trailing" id="LUp-xU-tlb"/> | |
<constraint firstItem="B7s-rc-aHU" firstAttribute="leading" secondItem="OzF-A2-QeO" secondAttribute="leading" id="OSt-o7-o5K"/> | |
<constraint firstAttribute="bottom" secondItem="B7s-rc-aHU" secondAttribute="bottom" id="vlQ-ie-dpF"/> | |
</constraints> | |
<nil key="simulatedTopBarMetrics"/> | |
<nil key="simulatedBottomBarMetrics"/> | |
<freeformSimulatedSizeMetrics key="simulatedDestinationMetrics"/> | |
<point key="canvasLocation" x="-418" y="-6"/> | |
</view> | |
</objects> | |
<resources> | |
<namedColor name="Base_Blue"> | |
<color red="0.098039215686274508" green="0.13725490196078433" blue="0.25098039215686274" alpha="1" colorSpace="custom" customColorSpace="sRGB"/> | |
</namedColor> | |
</resources> | |
</document> |
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment