Digital ACT-191 ONEAPP-7013 story: removing width prop, and passing selectedGroupIndex through onChange
This commit is contained in:
parent
928db0f1fc
commit
4ae07b6402
@ -81,31 +81,6 @@ open class Carousel: View {
|
||||
/// views used to render view in the carousel slots.
|
||||
open var views: [UIView] = [] { didSet { setNeedsUpdate() } }
|
||||
|
||||
/// If provided, width of slots will be rendered based on this value. If omitted, default widths are rendered.
|
||||
open var width: Width? {
|
||||
get { _width }
|
||||
set {
|
||||
if let newValue {
|
||||
switch newValue {
|
||||
case .percentage(let percentage):
|
||||
if percentage >= 10 && percentage <= 100.0 {
|
||||
let expectedWidth = safeAreaLayoutGuide.layoutFrame.size.width * (percentage/100)
|
||||
if expectedWidth > carouselScrollbarMinWidth {
|
||||
_width = newValue
|
||||
}
|
||||
}
|
||||
case .value(let value):
|
||||
if value > carouselScrollbarMinWidth {
|
||||
_width = newValue
|
||||
}
|
||||
}
|
||||
} else {
|
||||
_width = nil
|
||||
}
|
||||
setNeedsUpdate()
|
||||
}
|
||||
}
|
||||
|
||||
/// Space between each tile. The default value will be 24px (6X) in tablet and 12px (3X) in mobile.
|
||||
open var gutter: Gutter = UIDevice.isIPad ? .twentyFourPX : .twelvePX { didSet { setNeedsUpdate() } }
|
||||
|
||||
@ -117,7 +92,7 @@ open class Carousel: View {
|
||||
}
|
||||
}
|
||||
|
||||
/// A callback when moving the carousel. Returns initial visible slide's index in the carousel.
|
||||
/// A callback when moving the carousel. Returns selectedGroupIndex.
|
||||
open var onChange: ((Int) -> Void)? {
|
||||
get { nil }
|
||||
set {
|
||||
@ -150,12 +125,6 @@ open class Carousel: View {
|
||||
/// If provided, will set the alignment for slot content when the slots has different heights.
|
||||
open var slotAlignment: CarouselSlotAlignmentModel? = nil { didSet { setNeedsUpdate() } }
|
||||
|
||||
/// Render item style. If provided, the slot gets the background, width, height, border-radius.
|
||||
open var renderItemStyle: CarouselRenderItemStyle? = nil { didSet { setNeedsUpdate() } }
|
||||
|
||||
// /// Render item. It passes a data array object and expects the styled component to apply in return.
|
||||
// open var renderItem: CarouselSlotItemModel? = nil { didSet { setNeedsUpdate() } }
|
||||
|
||||
//--------------------------------------------------
|
||||
// MARK: - Private Properties
|
||||
//--------------------------------------------------
|
||||
@ -207,15 +176,10 @@ open class Carousel: View {
|
||||
$0.icon.customSize = UIDevice.isIPad ? 16 : 12
|
||||
}
|
||||
|
||||
/// A publisher for when the scrubber position changes. Passes parameters (position).
|
||||
/// A publisher for when moving the carousel. Passes parameters selectedGroupIndex (position).
|
||||
open var onChangePublisher = PassthroughSubject<Int, Never>()
|
||||
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?
|
||||
private var _width: Width? = nil
|
||||
private var selectedGroupIndex: Int? = nil
|
||||
private var containerStackHeightConstraint: NSLayoutConstraint?
|
||||
private var containerViewHeightConstraint: NSLayoutConstraint?
|
||||
private var prevButtonLeadingConstraint: NSLayoutConstraint?
|
||||
@ -225,7 +189,7 @@ open class Carousel: View {
|
||||
// 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
|
||||
|
||||
var slotHeight = 50.0
|
||||
var slotDefaultHeight = 50.0
|
||||
var peekMinimum = 24.0
|
||||
var minimumSlotWidth = 0.0
|
||||
var carouselScrollbarMinWidth = 96.0
|
||||
@ -248,13 +212,10 @@ open class Carousel: View {
|
||||
containerView
|
||||
.pinTop()
|
||||
.pinBottom()
|
||||
.pinLeadingGreaterThanOrEqualTo()
|
||||
.pinLeading()
|
||||
.pinTrailing()
|
||||
.heightGreaterThanEqualTo(containerSize.height)
|
||||
|
||||
containerView.centerYAnchor.constraint(equalTo: centerYAnchor).activate()
|
||||
containerLeadingConstraint = containerView.leadingAnchor.constraint(equalTo: safeAreaLayoutGuide.leadingAnchor, constant: 0)
|
||||
containerLeadingConstraint?.activate()
|
||||
|
||||
// Add content stackview
|
||||
containerView.addSubview(contentStackView)
|
||||
@ -293,23 +254,6 @@ open class Carousel: View {
|
||||
open override func updateView() {
|
||||
super.updateView()
|
||||
|
||||
if containerView.frame.size.width > 0 {
|
||||
if let width {
|
||||
containerLeadingConstraint?.deactivate()
|
||||
switch width {
|
||||
case .value(let value):
|
||||
var expectedWidth = value
|
||||
let fullWidth = safeAreaLayoutGuide.layoutFrame.size.width
|
||||
expectedWidth = expectedWidth > fullWidth ? fullWidth : expectedWidth
|
||||
containerLeadingConstraint?.constant = safeAreaLayoutGuide.layoutFrame.size.width - expectedWidth
|
||||
case .percentage(let percentage):
|
||||
let expectedWidth = safeAreaLayoutGuide.layoutFrame.size.width * (percentage/100)
|
||||
containerLeadingConstraint?.constant = safeAreaLayoutGuide.layoutFrame.size.width - expectedWidth
|
||||
}
|
||||
containerLeadingConstraint?.activate()
|
||||
}
|
||||
}
|
||||
|
||||
carouselScrollBar.numberOfSlides = views.count
|
||||
carouselScrollBar.layout = layout
|
||||
if (carouselScrollBar.position == 0 || carouselScrollBar.position > carouselScrollBar.numberOfSlides) {
|
||||
@ -347,7 +291,6 @@ open class Carousel: View {
|
||||
paginationInset = UIDevice.isIPad ? VDSLayout.space3X : VDSLayout.space2X
|
||||
gutter = UIDevice.isIPad ? .twentyFourPX : .twelvePX
|
||||
peek = .standard
|
||||
width = nil
|
||||
}
|
||||
|
||||
//--------------------------------------------------
|
||||
@ -412,17 +355,16 @@ open class Carousel: View {
|
||||
return estItemSize.height
|
||||
}
|
||||
|
||||
private func fetchCarouselHeight() {
|
||||
private func fetchCarouselHeight() -> CGFloat {
|
||||
var height = slotDefaultHeight
|
||||
if views.count > 0 {
|
||||
var height = slotHeight
|
||||
for x in 0...views.count - 1 {
|
||||
// Add received component
|
||||
let item : CarouselSlotItemModel = .init(style: renderItemStyle, component: views[x])
|
||||
slotHeight = estimateHeightFor(item: item, with: minimumSlotWidth)
|
||||
height = slotHeight > height ? slotHeight : height
|
||||
let item : CarouselSlotItemModel = .init(component: views[x])
|
||||
let estHeight = estimateHeightFor(item: item, with: minimumSlotWidth)
|
||||
height = estHeight > height ? estHeight : height
|
||||
}
|
||||
slotHeight = height
|
||||
}
|
||||
return height
|
||||
}
|
||||
|
||||
// Add carousel slots and load data if any
|
||||
@ -431,14 +373,13 @@ open class Carousel: View {
|
||||
if containerView.frame.size.width > 0 {
|
||||
containerViewHeightConstraint?.isActive = false
|
||||
containerStackHeightConstraint?.isActive = false
|
||||
let slotHeight = fetchCarouselHeight()
|
||||
|
||||
// Perform a loop to iterate each subView
|
||||
scrollView.subviews.forEach { subView in
|
||||
// Removing subView from its parent view
|
||||
subView.removeFromSuperview()
|
||||
}
|
||||
|
||||
fetchCarouselHeight()
|
||||
|
||||
// Add carousel items
|
||||
if views.count > 0 {
|
||||
@ -452,7 +393,7 @@ open class Carousel: View {
|
||||
}
|
||||
scrollView.addSubview(carouselSlot)
|
||||
scrollView.delegate = self
|
||||
|
||||
|
||||
carouselSlot
|
||||
.pinTop()
|
||||
.pinBottom()
|
||||
@ -463,7 +404,7 @@ open class Carousel: View {
|
||||
xPos = xPos + minimumSlotWidth + gutter.value
|
||||
|
||||
// Add received component
|
||||
let item : CarouselSlotItemModel = .init(style: renderItemStyle, component: views[x])
|
||||
let item : CarouselSlotItemModel = .init(component: views[x])
|
||||
let contentViewHeight = estimateHeightFor(item: item, with: minimumSlotWidth)
|
||||
|
||||
// Add subview for content to Carousel Slot
|
||||
@ -471,7 +412,7 @@ open class Carousel: View {
|
||||
$0.clipsToBounds = true
|
||||
}
|
||||
carouselSlot.addSubview(contentView)
|
||||
|
||||
|
||||
if let component = item.component {
|
||||
if slotAlignment != nil {
|
||||
// If slotAlignment exist, should use expected height
|
||||
@ -479,12 +420,15 @@ open class Carousel: View {
|
||||
contentView.heightAnchor.constraint(equalToConstant: contentViewHeight).activate()
|
||||
setSlotAlignment(contentView: contentView, parentView: carouselSlot)
|
||||
} else {
|
||||
// // If no slotAlignment, should use full slot
|
||||
// If no slotAlignment, should use full slot
|
||||
contentView.pinToSuperView()
|
||||
}
|
||||
carouselSlot.backgroundColor = .clear
|
||||
carouselSlot.layer.cornerRadius = 0
|
||||
contentView.addSubview(component)
|
||||
component.pinToSuperView()
|
||||
if var surfacedView = component as? Surfaceable {
|
||||
contentView.surface = surface
|
||||
surfacedView.surface = surface
|
||||
}
|
||||
}
|
||||
@ -628,9 +572,7 @@ open class Carousel: View {
|
||||
let yPos = scrollView.contentOffset.y
|
||||
scrollView.setContentOffset(CGPoint(x: xPos, y: yPos), animated: true)
|
||||
showPaginationControls()
|
||||
selectedIndex = ((position-1) * layout.value) + 1
|
||||
onChangePublisher.send(selectedIndex ?? 1)
|
||||
selectedGroupIndex = position
|
||||
onChangePublisher.send(position-1)
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
@ -11,23 +11,13 @@ import VDSCoreTokens
|
||||
|
||||
/// A custom data type that holds the style and component for a slot of the 'Carousel' component.
|
||||
public struct CarouselSlotItemModel {
|
||||
|
||||
/// Style props if provided any
|
||||
public var style: CarouselRenderItemStyle?
|
||||
|
||||
public let defaultHeight: CGFloat = 50.0
|
||||
|
||||
/// Component to be show on Carousel slot
|
||||
public var component: UIView?
|
||||
|
||||
public init(style: CarouselRenderItemStyle? = nil, component: UIView? = nil) {
|
||||
self.style = style
|
||||
public init(component: UIView? = nil) {
|
||||
self.component = component
|
||||
if let color = style?.backgroundColor {
|
||||
self.component?.backgroundColor = .init(hexString: color)
|
||||
}
|
||||
if let borderRadius = style?.borderRadius {
|
||||
self.component?.layer.cornerRadius = borderRadius
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
Loading…
Reference in New Issue
Block a user