Digital ACT-191 ONEAPP-7013 story: Fixed Constraints issue and refactored Code
This commit is contained in:
parent
de8a2ebdee
commit
a829df86e5
@ -33,25 +33,11 @@ open class Carousel: View {
|
|||||||
//--------------------------------------------------
|
//--------------------------------------------------
|
||||||
// MARK: - Enums
|
// MARK: - Enums
|
||||||
//--------------------------------------------------
|
//--------------------------------------------------
|
||||||
/// Enum used to describe the aspect ratios used for this component.
|
|
||||||
public enum AspectRatio: String, CaseIterable {
|
|
||||||
case ratio1x1 = "1:1"
|
|
||||||
case ratio3x4 = "3:4"
|
|
||||||
case ratio4x3 = "4:3"
|
|
||||||
case ratio2x3 = "2:3"
|
|
||||||
case ratio3x2 = "3:2"
|
|
||||||
case ratio9x16 = "9:16"
|
|
||||||
case ratio16x9 = "16:9"
|
|
||||||
case ratio1x2 = "1:2"
|
|
||||||
case ratio2x1 = "2:1"
|
|
||||||
case none
|
|
||||||
}
|
|
||||||
|
|
||||||
/// Space between each tile. The default value will be 24px (6X) in tablet and 12px (3X) in mobile.
|
/// Space between each tile. The default value will be 24px (6X) in tablet and 12px (3X) in mobile.
|
||||||
public enum Gutter: String, CaseIterable {
|
public enum Gutter: String, CaseIterable {
|
||||||
case twelvePX = "12px"
|
case twelvePX = "12px"
|
||||||
case twentyFourPX = "24px"
|
case twentyFourPX = "24px"
|
||||||
|
|
||||||
var value: CGFloat {
|
var value: CGFloat {
|
||||||
switch self {
|
switch self {
|
||||||
case .twelvePX:
|
case .twelvePX:
|
||||||
@ -61,7 +47,7 @@ open class Carousel: View {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
/// Enum used to describe the pagination display for this component.
|
/// Enum used to describe the pagination display for this component.
|
||||||
public enum PaginationDisplay: String, CaseIterable {
|
public enum PaginationDisplay: String, CaseIterable {
|
||||||
case persistent, none
|
case persistent, none
|
||||||
@ -72,8 +58,7 @@ open class Carousel: View {
|
|||||||
public enum Peek: String, CaseIterable {
|
public enum Peek: String, CaseIterable {
|
||||||
case standard, minimum, none
|
case standard, minimum, none
|
||||||
}
|
}
|
||||||
|
|
||||||
// TO DO: move to model class
|
|
||||||
/// Enum used to describe the vertical of slotAlignment.
|
/// Enum used to describe the vertical of slotAlignment.
|
||||||
public enum Vertical: String, CaseIterable {
|
public enum Vertical: String, CaseIterable {
|
||||||
case top, middle, bottom
|
case top, middle, bottom
|
||||||
@ -94,11 +79,11 @@ open class Carousel: View {
|
|||||||
// MARK: - Public Properties
|
// MARK: - Public Properties
|
||||||
//--------------------------------------------------
|
//--------------------------------------------------
|
||||||
/// Aspect-ratio options for tilelet in the carousel. If 'none' is passed, the tilelet will take the height of the tallest item in the carousel.
|
/// Aspect-ratio options for tilelet in the carousel. If 'none' is passed, the tilelet will take the height of the tallest item in the carousel.
|
||||||
open var aspectRatio: AspectRatio = .ratio1x1 { didSet { setNeedsUpdate() } }
|
open var aspectRatio: Tilelet.AspectRatio = .ratio1x1 { didSet { setNeedsUpdate() } }
|
||||||
|
|
||||||
/// Data used to render tilelets in the carousel.
|
/// Data used to render tilelets in the carousel.
|
||||||
open var data: [Any] = [] { didSet { setNeedsUpdate() } }
|
open var data: [Any] = [] { didSet { setNeedsUpdate() } }
|
||||||
|
|
||||||
/// If provided, width of slots will be rendered based on this value. If omitted, default widths are rendered.
|
/// If provided, width of slots will be rendered based on this value. If omitted, default widths are rendered.
|
||||||
open var width : Width? {
|
open var width : Width? {
|
||||||
get { _width }
|
get { _width }
|
||||||
@ -129,7 +114,7 @@ open class Carousel: View {
|
|||||||
setNeedsUpdate()
|
setNeedsUpdate()
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
/// The amount of slides visible in the carousel container at one time. The default value will be 3UP in tablet and 1UP in mobile.
|
/// The amount of slides visible in the carousel container at one time. The default value will be 3UP in tablet and 1UP in mobile.
|
||||||
open var layout: CarouselScrollbar.Layout {
|
open var layout: CarouselScrollbar.Layout {
|
||||||
get { return _layout }
|
get { return _layout }
|
||||||
@ -138,9 +123,9 @@ open class Carousel: View {
|
|||||||
setNeedsUpdate()
|
setNeedsUpdate()
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
/// A callback when moving the carousel. Returns event object and selectedGroupIndex.
|
/// A callback when moving the carousel. Returns event object and selectedGroupIndex.
|
||||||
open var onChange: ((Int) -> Void)? { // TO DO: return object and index
|
open var onChange: ((Int) -> Void)? {
|
||||||
get { nil }
|
get { nil }
|
||||||
set {
|
set {
|
||||||
onChangeCancellable?.cancel()
|
onChangeCancellable?.cancel()
|
||||||
@ -161,7 +146,7 @@ open class Carousel: View {
|
|||||||
setNeedsUpdate()
|
setNeedsUpdate()
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
/// If provided, will determine the conditions to render the pagination arrows.
|
/// If provided, will determine the conditions to render the pagination arrows.
|
||||||
open var paginationDisplay: PaginationDisplay {
|
open var paginationDisplay: PaginationDisplay {
|
||||||
get { return _paginationDisplay }
|
get { return _paginationDisplay }
|
||||||
@ -170,7 +155,7 @@ open class Carousel: View {
|
|||||||
setNeedsUpdate()
|
setNeedsUpdate()
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
/// If provided, will apply margin to pagination arrows. Can be set to either positive or negative values.
|
/// If provided, will apply margin to pagination arrows. Can be set to either positive or negative values.
|
||||||
/// The default value will be 12px in tablet and 8px in mobile.
|
/// The default value will be 12px in tablet and 8px in mobile.
|
||||||
open var paginationInset: CGFloat {
|
open var paginationInset: CGFloat {
|
||||||
@ -189,19 +174,19 @@ open class Carousel: View {
|
|||||||
setNeedsUpdate()
|
setNeedsUpdate()
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
/// The initial visible slide's index in the carousel.
|
/// The initial visible slide's index in the carousel.
|
||||||
open var selectedIndex: Int? { didSet { setNeedsUpdate() } }
|
open var selectedIndex: Int? { didSet { setNeedsUpdate() } }
|
||||||
|
|
||||||
/// If provided, will set the alignment for slot content when the slots has different heights.
|
/// If provided, will set the alignment for slot content when the slots has different heights.
|
||||||
open var slotAlignment: [CarouselSlotAlignmentModel] = [] { didSet { setNeedsUpdate() } }
|
open var slotAlignment: [CarouselSlotAlignmentModel] = [] { didSet { setNeedsUpdate() } }
|
||||||
|
|
||||||
//--------------------------------------------------
|
//--------------------------------------------------
|
||||||
// MARK: - Private Properties
|
// MARK: - Private Properties
|
||||||
//--------------------------------------------------
|
//--------------------------------------------------
|
||||||
// Sizes are from InVision design specs.
|
// Sizes are from InVision design specs.
|
||||||
internal var containerSize: CGSize { CGSize(width: 320, height: 44) }
|
internal var containerSize: CGSize { CGSize(width: 320, height: 44) }
|
||||||
|
|
||||||
private let contentStackView = UIStackView().with {
|
private let contentStackView = UIStackView().with {
|
||||||
$0.translatesAutoresizingMaskIntoConstraints = false
|
$0.translatesAutoresizingMaskIntoConstraints = false
|
||||||
$0.axis = .vertical
|
$0.axis = .vertical
|
||||||
@ -231,28 +216,32 @@ open class Carousel: View {
|
|||||||
$0.backgroundColor = .clear
|
$0.backgroundColor = .clear
|
||||||
}
|
}
|
||||||
|
|
||||||
/// Previous button to show previous slide.
|
/// Previous button to show previous slide.
|
||||||
private var previousButton = ButtonIcon().with {
|
private var previousButton = ButtonIcon().with {
|
||||||
$0.kind = .lowContrast
|
$0.kind = .lowContrast
|
||||||
$0.iconName = .leftCaret
|
$0.iconName = .leftCaret
|
||||||
$0.iconOffset = .init(x: -2, y: 0)
|
$0.iconOffset = .init(x: -2, y: 0)
|
||||||
$0.customContainerSize = UIDevice.isIPad ? 40 : 28
|
$0.customContainerSize = UIDevice.isIPad ? 40 : 28
|
||||||
$0.icon.customSize = UIDevice.isIPad ? 16 : 12
|
$0.icon.customSize = UIDevice.isIPad ? 16 : 12
|
||||||
}
|
}
|
||||||
|
|
||||||
/// Next button to show next slide.
|
/// Next button to show next slide.
|
||||||
private var nextButton = ButtonIcon().with {
|
private var nextButton = ButtonIcon().with {
|
||||||
$0.kind = .lowContrast
|
$0.kind = .lowContrast
|
||||||
$0.iconName = .rightCaret
|
$0.iconName = .rightCaret
|
||||||
$0.iconOffset = .init(x: 2, y: 0)
|
$0.iconOffset = .init(x: 2, y: 0)
|
||||||
$0.customContainerSize = UIDevice.isIPad ? 40 : 28
|
$0.customContainerSize = UIDevice.isIPad ? 40 : 28
|
||||||
$0.icon.customSize = UIDevice.isIPad ? 16 : 12
|
$0.icon.customSize = UIDevice.isIPad ? 16 : 12
|
||||||
}
|
}
|
||||||
|
|
||||||
/// A publisher for when the scrubber position changes. Passes parameters (position).
|
/// A publisher for when the scrubber position changes. Passes parameters (position).
|
||||||
open var onChangePublisher = PassthroughSubject<Int, Never>()
|
open var onChangePublisher = PassthroughSubject<Int, Never>()
|
||||||
private var onChangeCancellable: AnyCancellable?
|
private var onChangeCancellable: AnyCancellable?
|
||||||
|
|
||||||
|
/// A publisher for when the carousel moves. Passes parameters (data).
|
||||||
|
open var onScrollPublisher = PassthroughSubject<Array<Any>, Never>()
|
||||||
|
private var onScrollCancellable: AnyCancellable?
|
||||||
|
|
||||||
internal var _layout: CarouselScrollbar.Layout = UIDevice.isIPad ? .threeUP : .oneUP
|
internal var _layout: CarouselScrollbar.Layout = UIDevice.isIPad ? .threeUP : .oneUP
|
||||||
internal var _pagination: CarouselPaginationModel = .init(kind: .lowContrast, floating: true)
|
internal var _pagination: CarouselPaginationModel = .init(kind: .lowContrast, floating: true)
|
||||||
internal var _paginationDisplay: PaginationDisplay = .none
|
internal var _paginationDisplay: PaginationDisplay = .none
|
||||||
@ -260,12 +249,12 @@ open class Carousel: View {
|
|||||||
internal var _gutter: Gutter = UIDevice.isIPad ? .twentyFourPX : .twelvePX
|
internal var _gutter: Gutter = UIDevice.isIPad ? .twentyFourPX : .twelvePX
|
||||||
internal var _peek: Peek = .none
|
internal var _peek: Peek = .none
|
||||||
internal var _numberOfSlides: Int = 1
|
internal var _numberOfSlides: Int = 1
|
||||||
|
|
||||||
private var _width: Width? = nil
|
private var _width: Width? = nil
|
||||||
private var selectedGroupIndex: Int? { didSet { setNeedsUpdate() } }
|
private var selectedGroupIndex: Int? { didSet { setNeedsUpdate() } }
|
||||||
private var containerStackHeightConstraint: NSLayoutConstraint?
|
private var containerStackHeightConstraint: NSLayoutConstraint?
|
||||||
private var containerViewHeightConstraint: NSLayoutConstraint?
|
private var containerViewHeightConstraint: NSLayoutConstraint?
|
||||||
|
|
||||||
// The scrollbar has top 5X space. So the expected top space is adjusted for tablet and mobile.
|
// The scrollbar has top 5X space. So the expected top space is adjusted for tablet and mobile.
|
||||||
let scrollbarTopSpace = UIDevice.isIPad ? VDSLayout.space3X : VDSLayout.space1X
|
let scrollbarTopSpace = UIDevice.isIPad ? VDSLayout.space3X : VDSLayout.space1X
|
||||||
|
|
||||||
@ -282,7 +271,7 @@ open class Carousel: View {
|
|||||||
open override func setup() {
|
open override func setup() {
|
||||||
super.setup()
|
super.setup()
|
||||||
isAccessibilityElement = false
|
isAccessibilityElement = false
|
||||||
|
|
||||||
// add containerView
|
// add containerView
|
||||||
addSubview(containerView)
|
addSubview(containerView)
|
||||||
containerView
|
containerView
|
||||||
@ -305,12 +294,12 @@ open class Carousel: View {
|
|||||||
previousButton
|
previousButton
|
||||||
.pinLeading(paginationInset)
|
.pinLeading(paginationInset)
|
||||||
.pinCenterY()
|
.pinCenterY()
|
||||||
|
|
||||||
scrollContainerView.addSubview(nextButton)
|
scrollContainerView.addSubview(nextButton)
|
||||||
nextButton
|
nextButton
|
||||||
.pinTrailing(paginationInset)
|
.pinTrailing(paginationInset)
|
||||||
.pinCenterY()
|
.pinCenterY()
|
||||||
|
|
||||||
// add scroll container view & carousel scrollbar
|
// add scroll container view & carousel scrollbar
|
||||||
contentStackView.addArrangedSubview(scrollContainerView)
|
contentStackView.addArrangedSubview(scrollContainerView)
|
||||||
contentStackView.addArrangedSubview(carouselScrollBar)
|
contentStackView.addArrangedSubview(carouselScrollBar)
|
||||||
@ -320,13 +309,15 @@ open class Carousel: View {
|
|||||||
.pinBottom()
|
.pinBottom()
|
||||||
.pinLeading()
|
.pinLeading()
|
||||||
.pinTrailing()
|
.pinTrailing()
|
||||||
.heightGreaterThanEqualTo(scrollbarTopSpace + containerSize.height)
|
.heightGreaterThanEqualTo(containerSize.height)
|
||||||
contentStackView.centerXAnchor.constraint(equalTo: centerXAnchor).activate()
|
contentStackView.centerXAnchor.constraint(equalTo: centerXAnchor).activate()
|
||||||
|
|
||||||
|
addlisteners()
|
||||||
}
|
}
|
||||||
|
|
||||||
open override func updateView() {
|
open override func updateView() {
|
||||||
super.updateView()
|
super.updateView()
|
||||||
|
|
||||||
carouselScrollBar.numberOfSlides = data.count
|
carouselScrollBar.numberOfSlides = data.count
|
||||||
carouselScrollBar.layout = _layout
|
carouselScrollBar.layout = _layout
|
||||||
carouselScrollBar.position = (carouselScrollBar.position == 0 || carouselScrollBar.position > carouselScrollBar.numberOfSlides) ? 1 : carouselScrollBar.position
|
carouselScrollBar.position = (carouselScrollBar.position == 0 || carouselScrollBar.position > carouselScrollBar.numberOfSlides) ? 1 : carouselScrollBar.position
|
||||||
@ -354,7 +345,7 @@ open class Carousel: View {
|
|||||||
for x in 0...data.count - 1 {
|
for x in 0...data.count - 1 {
|
||||||
let carouselSlot = View().with {
|
let carouselSlot = View().with {
|
||||||
$0.clipsToBounds = true
|
$0.clipsToBounds = true
|
||||||
$0.backgroundColor = UIColor(red: CGFloat(216) / 255.0, green: CGFloat(218) / 255.0, blue: CGFloat(218) / 255.0, alpha: 1)
|
$0.backgroundColor = UIColor(red: CGFloat(216) / 255.0, green: CGFloat(218) / 255.0, blue: CGFloat(218) / 255.0, alpha: 1)
|
||||||
}
|
}
|
||||||
scrollView.addSubview(carouselSlot)
|
scrollView.addSubview(carouselSlot)
|
||||||
carouselSlot
|
carouselSlot
|
||||||
@ -365,7 +356,6 @@ open class Carousel: View {
|
|||||||
.height(slotHeight)
|
.height(slotHeight)
|
||||||
xPos = xPos + minimumSlotWidth + gutter.value
|
xPos = xPos + minimumSlotWidth + gutter.value
|
||||||
}
|
}
|
||||||
scrollView.heightAnchor.constraint(equalToConstant: slotHeight).isActive = true
|
|
||||||
scrollView.contentSize = CGSize(width: xPos - gutter.value, height: slotHeight)
|
scrollView.contentSize = CGSize(width: xPos - gutter.value, height: slotHeight)
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -380,7 +370,6 @@ open class Carousel: View {
|
|||||||
containerViewHeightConstraint?.isActive = true
|
containerViewHeightConstraint?.isActive = true
|
||||||
containerStackHeightConstraint?.isActive = true
|
containerStackHeightConstraint?.isActive = true
|
||||||
|
|
||||||
addlisteners()
|
|
||||||
layoutIfNeeded()
|
layoutIfNeeded()
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -401,10 +390,10 @@ open class Carousel: View {
|
|||||||
previousButton.onClick = { _ in self.previousButtonClick() }
|
previousButton.onClick = { _ in self.previousButtonClick() }
|
||||||
|
|
||||||
//setup test page to show scrubber id was changed
|
//setup test page to show scrubber id was changed
|
||||||
// carouselScrollBar.onScrubberDrag = { [weak self] scrubberId in
|
// carouselScrollBar.onScrubberDrag = { [weak self] scrubberId in
|
||||||
// guard let self else { return }
|
// guard let self else { return }
|
||||||
// updateScrollPosition(position: scrubberId, callbackText:"onScrubberDrag")
|
// updateScrollPosition(position: scrubberId, callbackText:"onScrubberDrag")
|
||||||
// }
|
// }
|
||||||
|
|
||||||
/// will be called when the thumb move forward.
|
/// will be called when the thumb move forward.
|
||||||
carouselScrollBar.onMoveForward = { [weak self] scrubberId in
|
carouselScrollBar.onMoveForward = { [weak self] scrubberId in
|
||||||
@ -467,7 +456,7 @@ open class Carousel: View {
|
|||||||
showPaginationControls()
|
showPaginationControls()
|
||||||
updateScrollPosition(position: carouselScrollBar.position, callbackText:"pageControlClicks")
|
updateScrollPosition(position: carouselScrollBar.position, callbackText:"pageControlClicks")
|
||||||
}
|
}
|
||||||
|
|
||||||
func updateScrollPosition(position: Int, callbackText: String) {
|
func updateScrollPosition(position: Int, callbackText: String) {
|
||||||
if carouselScrollBar.numberOfSlides > 0 {
|
if carouselScrollBar.numberOfSlides > 0 {
|
||||||
let contentOffsetWidth = scrollView.contentSize.width
|
let contentOffsetWidth = scrollView.contentSize.width
|
||||||
|
|||||||
Loading…
Reference in New Issue
Block a user