From 8866e91caa86612da557aff4af19fe9bb6e14d14 Mon Sep 17 00:00:00 2001 From: "Pfeil, Scott Robert" Date: Thu, 11 Jul 2019 16:11:58 -0400 Subject: [PATCH] add peaking logic --- MVMCoreUI/Molecules/Carousel.swift | 127 ++++-------------- MVMCoreUI/Molecules/MVMCoreUIPagingProtocol.h | 3 + .../MoleculeCollectionViewCell.swift | 60 ++++++++- .../Media.xcassets/Contents.json | 6 + .../peakingRightArrow.imageset/Contents.json | 23 ++++ .../E_UBI_003_G.png | Bin 0 -> 168 bytes .../E_UBI_003_G@2x.png | Bin 0 -> 275 bytes .../E_UBI_003_G@3x.png | Bin 0 -> 379 bytes 8 files changed, 115 insertions(+), 104 deletions(-) create mode 100644 MVMCoreUI/SupportingFiles/Media.xcassets/Contents.json create mode 100644 MVMCoreUI/SupportingFiles/Media.xcassets/peakingRightArrow.imageset/Contents.json create mode 100644 MVMCoreUI/SupportingFiles/Media.xcassets/peakingRightArrow.imageset/E_UBI_003_G.png create mode 100644 MVMCoreUI/SupportingFiles/Media.xcassets/peakingRightArrow.imageset/E_UBI_003_G@2x.png create mode 100644 MVMCoreUI/SupportingFiles/Media.xcassets/peakingRightArrow.imageset/E_UBI_003_G@3x.png diff --git a/MVMCoreUI/Molecules/Carousel.swift b/MVMCoreUI/Molecules/Carousel.swift index cb0bbf2b..cb5d7243 100644 --- a/MVMCoreUI/Molecules/Carousel.swift +++ b/MVMCoreUI/Molecules/Carousel.swift @@ -45,7 +45,6 @@ open class Carousel: ViewConstrainingView { /// If the carousel should loop after scrolling past the first and final cells. var loop = false private var dragging = false - private var previousContentOffsetX: CGFloat = 0 // MARK: - MVMCoreViewProtocol open override func setupView() { @@ -73,6 +72,7 @@ open class Carousel: ViewConstrainingView { DispatchQueue.main.async { self.collectionView.scrollToItem(at: IndexPath(row: self.currentIndex, section: 0), at: self.itemAlignment, animated: false) self.collectionView.layoutIfNeeded() + self.showPeaking(true) } } @@ -201,6 +201,24 @@ open class Carousel: ViewConstrainingView { } self.pagingView = pagingView } + + open func showPeaking(_ peaking: Bool) { + if peaking { + // Show overlay and arrow in peaking Cell + let visibleItemsPaths = collectionView.indexPathsForVisibleItems.sorted { $0.row < $1.row } + if let firstItem = visibleItemsPaths.first, firstItem.row != currentIndex { + (collectionView.cellForItem(at: firstItem) as? MoleculeCollectionViewCell)?.setPeaking(true, animated: true) + } + if let lastItem = visibleItemsPaths.last, lastItem.row != currentIndex { + (collectionView.cellForItem(at: lastItem) as? MoleculeCollectionViewCell)?.setPeaking(true, animated: true) + } + } else { + // Hide peaking. + for item in collectionView.visibleCells { + (item as? MoleculeCollectionViewCell)?.setPeaking(false, animated: true) + } + } + } } extension Carousel: UICollectionViewDelegateFlowLayout { @@ -232,68 +250,6 @@ extension Carousel: UICollectionViewDataSource { } extension Carousel: UIScrollViewDelegate { - /*// For getting the scroll progress to set the page control color progress. - - (CGFloat)getPageControlPercentBasedOnScrollView:(UIScrollView *)scrollView { - CGFloat cardWidth = ((UICollectionViewFlowLayout *)self.collectionView.collectionViewLayout).itemSize.width; - CGFloat separatorWidth = ((UICollectionViewFlowLayout *)self.collectionView.collectionViewLayout).minimumLineSpacing; - CGFloat contentOfsetInCard = fmodf(scrollView.contentOffset.x, cardWidth + separatorWidth); - CGFloat endThresholdPageControl = cardWidth + separatorWidth - CGRectGetMaxX(self.pageControl.frame); - CGFloat progress = contentOfsetInCard - endThresholdPageControl; - CGFloat width = CGRectGetWidth(self.pageControl.bounds); - CGFloat percent = (width - progress)/width; - CGFloat cappedPercent = MAX(MIN(percent, 1), 0); - return cappedPercent; - } - - - (void)setPageControlColorsBasedOnScrollView:(UIScrollView *)scrollView { - - // Check if we will need to change colors. - BOOL needToShiftColors = NO; - NSInteger nextCardIndex = 0; - CGFloat cardWidth = ((UICollectionViewFlowLayout *)self.collectionView.collectionViewLayout).itemSize.width; - CGFloat separatorWidth = ((UICollectionViewFlowLayout *)self.collectionView.collectionViewLayout).minimumLineSpacing; - NSInteger currentCard = scrollView.contentOffset.x / (cardWidth + separatorWidth); - CGFloat cardStart = currentCard * (cardWidth + separatorWidth); - CGFloat cardEnd = cardStart + cardWidth + separatorWidth; - NSInteger pageIndicator = currentCard; - if ((self.previousContentOffsetX == NSNotFound || self.previousContentOffsetX <= cardStart) && scrollView.contentOffset.x >= cardStart) { - - // We are passed the threshold and moving right, change to right card color. - needToShiftColors = YES; - nextCardIndex = currentCard + 1; - pageIndicator = currentCard - 1; - } else if ((self.previousContentOffsetX == NSNotFound || self.previousContentOffsetX >= cardEnd) && scrollView.contentOffset.x < cardEnd) { - - // We are passed the threshold and moving left, change to left card color. - needToShiftColors = YES; - nextCardIndex = currentCard - 1; - } - - if (needToShiftColors) { - // Only shift the page control if we are dragging still, otherwise end animation will control. - if (self.dragging) { - [self.pageControl setCurrentPage:pageIndicator]; - } - - // Get the current page color - NSString *colorString = [[self.feedModules objectAtIndex:currentCard] string:KeyPageIndicatorColor]; - UIColor *currentCardPageControlColor = colorString ? [UIColor mfGetColorForHex:colorString] : [UIColor blackColor]; - - // Get the next page color and set accordingly. - colorString = [[self.feedModules dictionaryAtIndex:nextCardIndex] string:KeyPageIndicatorColor]; - UIColor *nextCardPageControlColor = colorString ? [UIColor mfGetColorForHex:colorString] : [UIColor blackColor]; - - // Which color needs to be on top or bottom depends on which direction we are moving. - if (nextCardIndex > currentCard) { - [self setPageControlColor:nextCardPageControlColor progressColor:currentCardPageControlColor]; - } else { - [self setPageControlColor:currentCardPageControlColor progressColor:nextCardPageControlColor]; - } - } - } - - */ - func handleUserOnBufferCell() { guard loop else { return @@ -302,7 +258,6 @@ extension Carousel: UIScrollViewDelegate { let lastPageIndex = numberOfPages + 1 let goToIndex = {(index: Int) in self.currentIndex = index - self.previousContentOffsetX = CGFloat(NSNotFound) self.collectionView.scrollToItem(at: IndexPath(row: self.currentIndex, section: 0), at: self.itemAlignment, animated: false) self.collectionView.layoutIfNeeded() self.pagingView?.setPage(self.pageIndex) @@ -337,24 +292,17 @@ extension Carousel: UIScrollViewDelegate { } public func scrollViewDidScroll(_ scrollView: UIScrollView) { + // Check if the user is dragging the card even further past the next card. checkForDraggingOutOfBounds(scrollView) - // Set the page control direction colors if needed. - //[self setPageControlColorsBasedOnScrollView:scrollView]; - - // Set the percent of progress. - //self.pageControl.progressView.progress = [self getPageControlPercentBasedOnScrollView:scrollView]; - - previousContentOffsetX = scrollView.contentOffset.x; + // Let the pager know our progress if needed. + pagingView?.scrollViewDidScroll?(collectionView) } public func scrollViewWillBeginDragging(_ scrollView: UIScrollView) { dragging = true - -// // Hide coverview and arrow. -// FeedBaseCollectionViewCell *peakingCell = (FeedBaseCollectionViewCell *)[self.collectionView cellForItemAtIndexPath:[NSIndexPath indexPathForItem:self.currentIndex + 1 inSection:0]]; -// [peakingCell setPeaking:NO animated:YES]; + showPeaking(false) } public func scrollViewWillEndDragging(_ scrollView: UIScrollView, withVelocity velocity: CGPoint, targetContentOffset: UnsafeMutablePointer) { @@ -363,7 +311,7 @@ extension Carousel: UIScrollViewDelegate { // This is for setting up smooth custom paging. (Since UICollectionView only handles paging based on collection view size and not cell size). guard let separatorWidth = (collectionView.collectionViewLayout as? UICollectionViewFlowLayout)?.minimumLineSpacing else { - return + return } // We switch cards if we pass the velocity threshold or position threshold (currently 50%). @@ -381,11 +329,6 @@ extension Carousel: UIScrollViewDelegate { currentIndex = min(max(cellToSwipeTo, 0), lastCellIndex) collectionView.scrollToItem(at: IndexPath(row: currentIndex, section: 0), at: itemAlignment, animated: true) - - // Notify that card changed - /*if (self.cardChanged) { - self.cardChanged(self.currentIndex, [self.module string:[MFBaseHomeViewController getFeedContainerNameKey]]); - }*/ } // To give the illusion of endless scrolling. Since we are always calling scrollToItem we can assume finished paging in here. @@ -394,27 +337,7 @@ extension Carousel: UIScrollViewDelegate { handleUserOnBufferCell() pagingView?.setPage(pageIndex) - /* - // Update to the new page in the control if needed. - if (self.currentIndex - 1 != self.pageControl.currentPage) { - [self.pageControl setCurrentPage:self.currentIndex - 1]; - } - // Show overlay and arrow in next Cell - FeedBaseCollectionViewCell *nextCell = (FeedBaseCollectionViewCell *)[self.collectionView cellForItemAtIndexPath:[NSIndexPath indexPathForItem:self.currentIndex + 1 inSection:0]]; - [nextCell setPeaking:YES animated:YES]; - FeedBaseCollectionViewCell *currentCell = (FeedBaseCollectionViewCell *)[self.collectionView cellForItemAtIndexPath:[NSIndexPath indexPathForItem:self.currentIndex inSection:0]]; - if (currentCell) { - self.accessibilityElements = @[currentCell.containerView, self.pageControl]; - currentCell.containerView.isAccessibilityElement = YES; - currentCell.accessibilityElementsHidden = NO; - UIAccessibilityPostNotification(UIAccessibilityLayoutChangedNotification,currentCell.containerView); - } - - // Set the page control again if pageControl is tapped or voice over is using. - [self setPageControlColorsBasedOnScrollView:scrollView]; - - // send adobe tracker action - [self sendAdobeTrackerAction];*/ + showPeaking(true) } } diff --git a/MVMCoreUI/Molecules/MVMCoreUIPagingProtocol.h b/MVMCoreUI/Molecules/MVMCoreUIPagingProtocol.h index ac8aee3c..89dd279b 100644 --- a/MVMCoreUI/Molecules/MVMCoreUIPagingProtocol.h +++ b/MVMCoreUI/Molecules/MVMCoreUIPagingProtocol.h @@ -18,5 +18,8 @@ typedef void (^PagingTouchBlock)(NSObject* _Nonnull sen - (void)setPage:(NSInteger)page; - (void)setPagingTouchBlock:(nullable PagingTouchBlock)pagingTouchBlock; + +@optional +- (void)scrollViewDidScroll:(nonnull UICollectionView *)collectionView; @end diff --git a/MVMCoreUI/Molecules/MoleculeCollectionViewCell.swift b/MVMCoreUI/Molecules/MoleculeCollectionViewCell.swift index 2eb61e68..23850e70 100644 --- a/MVMCoreUI/Molecules/MoleculeCollectionViewCell.swift +++ b/MVMCoreUI/Molecules/MoleculeCollectionViewCell.swift @@ -11,6 +11,11 @@ import UIKit open class MoleculeCollectionViewCell: UICollectionViewCell, MVMCoreUIMoleculeViewProtocol, MoleculeListCellProtocol { open var molecule: (UIView & MVMCoreUIMoleculeViewProtocol)? + open var allowsPeaking = false + var peakingLeftArrow = UIImageView(image: MVMCoreUIUtility.imageNamed("peakingRightArrow")?.withRenderingMode(.alwaysTemplate)) + var peakingRightArrow = UIImageView(image: MVMCoreUIUtility.imageNamed("peakingRightArrow")?.withRenderingMode(.alwaysTemplate)) + var peakingCover = MVMCoreUICommonViewsUtility.commonView() + public override init(frame: CGRect) { super.init(frame: .zero) setupView() @@ -22,15 +27,49 @@ open class MoleculeCollectionViewCell: UICollectionViewCell, MVMCoreUIMoleculeVi } public func setupView() { + guard peakingCover.superview == nil else { + return + } + // Covers the card when peaking. + peakingCover.backgroundColor = .white + peakingCover.alpha = 0 + contentView.addSubview(peakingCover) + NSLayoutConstraint.constraintPinSubview(toSuperview: peakingCover) + + // A small arrow on the next card for when peaking. + let ratio: CGFloat = 0.015 + peakingLeftArrow.translatesAutoresizingMaskIntoConstraints = false + peakingLeftArrow.alpha = 0 + peakingLeftArrow.tintColor = .black + contentView.addSubview(peakingLeftArrow) + peakingLeftArrow.centerYAnchor.constraint(equalTo: contentView.centerYAnchor).isActive = true + NSLayoutConstraint.scalingPinViewLeft(toSuper: peakingLeftArrow, ratio: ratio, anchor: contentView.widthAnchor) + + peakingRightArrow.translatesAutoresizingMaskIntoConstraints = false + peakingRightArrow.transform = CGAffineTransform(scaleX: -1, y: 1) // Flip + peakingRightArrow.alpha = 0 + peakingRightArrow.tintColor = .black + contentView.addSubview(peakingRightArrow) + peakingRightArrow.centerYAnchor.constraint(equalTo: contentView.centerYAnchor).isActive = true + NSLayoutConstraint.scalingPinViewRight(toSuper: peakingRightArrow, ratio: ratio, anchor: contentView.widthAnchor) } public func setWithJSON(_ json: [AnyHashable : Any]?, delegateObject: MVMCoreUIDelegateObject?, additionalData: [AnyHashable : Any]?) { - guard let json = json, let moleculeJSON = json.optionalDictionaryForKey(KeyMolecule) else { + + // Handles peaking. + allowsPeaking = json?.optionalBoolForKey("peakingUI") ?? true + if let peakingArrowColor = json?.optionalStringForKey("peakingArrowColor") { + let color = UIColor.mfGet(forHex: peakingArrowColor) + peakingLeftArrow.tintColor = color + peakingRightArrow.tintColor = color + } + + guard let moleculeJSON = json?.optionalDictionaryForKey(KeyMolecule) else { return } if molecule == nil { if let moleculeView = MVMCoreUIMoleculeMappingObject.shared()?.createMolecule(forJSON: moleculeJSON, delegateObject: delegateObject, constrainIfNeeded: true) { - contentView.addSubview(moleculeView) + contentView.insertSubview(moleculeView, at: 0) let standardConstraints = (moleculeView as? MVMCoreUIViewConstrainingProtocol)?.useStandardConstraints?() ?? true NSLayoutConstraint.activate(Array(NSLayoutConstraint.pinView(toSuperview: moleculeView, useMargins: standardConstraints).values)) if standardConstraints { @@ -61,4 +100,21 @@ open class MoleculeCollectionViewCell: UICollectionViewCell, MVMCoreUIMoleculeVi public func updateView(_ size: CGFloat) { molecule?.updateView(size) } + + public func setPeaking(_ peaking: Bool, animated: Bool) { + guard allowsPeaking else { + return + } + let animation = {() in + self.peakingRightArrow.alpha = peaking ? 1 : 0 + self.peakingLeftArrow.alpha = peaking ? 1 : 0 + self.peakingCover.alpha = peaking ? 0.5 : 0 + print("\(self.peakingCover.alpha)") + } + if animated { + UIView.animate(withDuration: 0.4, animations: animation) + } else { + animation() + } + } } diff --git a/MVMCoreUI/SupportingFiles/Media.xcassets/Contents.json b/MVMCoreUI/SupportingFiles/Media.xcassets/Contents.json new file mode 100644 index 00000000..da4a164c --- /dev/null +++ b/MVMCoreUI/SupportingFiles/Media.xcassets/Contents.json @@ -0,0 +1,6 @@ +{ + "info" : { + "version" : 1, + "author" : "xcode" + } +} \ No newline at end of file diff --git a/MVMCoreUI/SupportingFiles/Media.xcassets/peakingRightArrow.imageset/Contents.json b/MVMCoreUI/SupportingFiles/Media.xcassets/peakingRightArrow.imageset/Contents.json new file mode 100644 index 00000000..0851ce22 --- /dev/null +++ b/MVMCoreUI/SupportingFiles/Media.xcassets/peakingRightArrow.imageset/Contents.json @@ -0,0 +1,23 @@ +{ + "images" : [ + { + "idiom" : "universal", + "filename" : "E_UBI_003_G.png", + "scale" : "1x" + }, + { + "idiom" : "universal", + "filename" : "E_UBI_003_G@2x.png", + "scale" : "2x" + }, + { + "idiom" : "universal", + "filename" : "E_UBI_003_G@3x.png", + "scale" : "3x" + } + ], + "info" : { + "version" : 1, + "author" : "xcode" + } +} \ No newline at end of file diff --git a/MVMCoreUI/SupportingFiles/Media.xcassets/peakingRightArrow.imageset/E_UBI_003_G.png b/MVMCoreUI/SupportingFiles/Media.xcassets/peakingRightArrow.imageset/E_UBI_003_G.png new file mode 100644 index 0000000000000000000000000000000000000000..8c789309b9b6158736aa92340a311bfe13a7e644 GIT binary patch literal 168 zcmeAS@N?(olHy`uVBq!ia0vp^JRr=$1|-8uW1a&k#^NA%Cx&(BWL^R}NuDl_AsV8| z2?zKNH6A*8W9f!&BgWR}jD?zInQs;;_!c+pVA^d`7U;I%Lyp3_LwdcjB1gTe~DWM4fpzt|a literal 0 HcmV?d00001 diff --git a/MVMCoreUI/SupportingFiles/Media.xcassets/peakingRightArrow.imageset/E_UBI_003_G@2x.png b/MVMCoreUI/SupportingFiles/Media.xcassets/peakingRightArrow.imageset/E_UBI_003_G@2x.png new file mode 100644 index 0000000000000000000000000000000000000000..b6453e48a2bbeceeb317ec1000da984b4aa7b85c GIT binary patch literal 275 zcmV+u0qp*XP)Px#%}GQ-R7efgmfZ>gQ5Z!Tf8!ZEpd?9}lH7R;4?!Z4+`0BjSX;Srv%i|}!l^aQ z#oF!pJLgQR;g2Tj1_to(W4>9U-rxx%KNd6l=vPq5I2QG7-N^-BF!5tCQzd6m$ut)A z?H=k0R5J5pF|&()1eMHVQQua{0aQ}?v6$IG--AjPv8ZpWWCto)`mva)k}arYrDz-O zI;nA}L}Lv_@j3mY!_OnC^V(BivgShCXPP?EQkRO<#V&QZPTg=)w@h7m>ZbqwZ5c*p Z=Nk_lFH7J3S+M{B002ovPDHLkV1fd9cWnRw literal 0 HcmV?d00001 diff --git a/MVMCoreUI/SupportingFiles/Media.xcassets/peakingRightArrow.imageset/E_UBI_003_G@3x.png b/MVMCoreUI/SupportingFiles/Media.xcassets/peakingRightArrow.imageset/E_UBI_003_G@3x.png new file mode 100644 index 0000000000000000000000000000000000000000..7fe147c7942353596fc01b9c9427daea9b2012e7 GIT binary patch literal 379 zcmV->0fhdEP)Px$HAzH4R9Fekm`REPK@dgN+Bvt{M{wbpM4S*25fNz+L3-2B_h=VhLs1l^6^HXU z{D4Xb3S0$L{eVwco1c$LD>5>?m_0mL{6R_RX1B9D{KDc1-JzP@&hGFDi!0=y>UK-J zLkSia1=X}$+8v6pIQvi!OgF#}W@5NieX#R9cbP!k5I6d;xg zYU-fk_)&HbA!q5I7Er}scZU2UKvExA;yb}Y;yCEG%z=fS-~Oq?29foo7SVk6RE3f1 z=#Uei=5VEIKd2fssuq^2$)~yoQC$>+SLv3N<)|V!Y-mIUBJ0wPW9SA}GSZtvRe4?3 ZcmYEIX$}#dZKD7H002ovPDHLkV1lz)oE888 literal 0 HcmV?d00001