قالب وردپرس درنا توس
Home / IOS Development / ios – How do you change the UICollectionViewCell setup position?

ios – How do you change the UICollectionViewCell setup position?



Wallpaper

So I work with a custom framework and I have implemented a custom UICollectionViewFlowLayout for UICollectionView .
The implementation allows you to scroll through the deck while also turning cards (cells) to the left / right (Tinder + Shazam Discover combo).

I change UICollectionViewLayoutAttributes to create a scroll screen stack effect.

Problem

At the end of the stack, when I turn off a card (cell), the new cards do not appear behind the stack, but from the top instead. This only happens at the end of the stack, and I have no idea why.

What I think ̵
1; What I have tried

My guess is that I have to change some things in initialLayoutAttributesForAppearingItem and I've tried it, but it doesn't seem to do anything.

I currently call the function updateCellAttributes inside it to update attributes, but I've also tried manually changing attributes in it. I really do not see the problem here unless there is another way to change how a card is placed for this case.

Could it be that because the cells are not technically in the "right" yet (see layoutAttributesForElements (in rect: CGRect) ), are they not updated?

Is there anything I lack?

Examples and Code

Here is a poison of that in action: [commonplace example]

Is there anyone more familiar with how I can modify the flow performance to achieve my desired behavior? ]

Here's a point of the error I'm trying to fix:

 bug example

As you can see, when you sweep away the last card , the new card will appear at the top while it should appear behind the previous card instead.

Below you find the custom UICollectionViewFlowLayout code .
The most important feature is updateCellAttributes one,
which is well documented with inline comments.
This function is called from:
initialLayoutAttributesForAppearingItem
finalLayoutAttributesForDisappearingItem
layoutAttributesForTem
layoutAttributesForElements

To change the layout information and create the stack effect.

  import UIKit

/// Custom `UICollectionViewFlowLayout` providing flow layout information such as paging and` CardCell` gestures.
internal class VerticalCardSwiperFlowLayout: UICollectionViewFlowLayout {

/// This property specifies the amount of scaling for the first item.
internally was firstItemTransform: CGFloat?
/// This feature enables paging per card. The default is true.
internal was isPagingEnabled: Bool = true
/// Saves the height of a CardCell.
internally was cellHeight: CGFloat!
/// Allows you to make the previous card visible or not visible (stuck effect). The default is `true`.
internal was is PreviousCardVisible: Bool = true

internal override func preparation () {
super.prepar ()

assert (collectionView? .numberOfSections == 1, "Number of sections should always be 1.")
assert (collectionView? .isPagingEnabled == false, "Collection paging itself should never be enabled. To enable cell paging, use the isPagingEnabled property of VerticalCardSwiperFlowLayout instead.")
}

intern override func layoutAttributesForElements (in rect: CGRect) -> [UICollectionViewLayoutAttributes]? {

leave items = NSArray (array: super.layoutAttributesForElements (i: rect)!, copyItems: true)

for items in items {
if let attributes = object like? UICollectionViewLayoutAttributes {
self.updateCellAttributes (attributes)
}
}
return items like? [UICollectionViewLayoutAttributes]
}

internal override function layoutAttributesForItem (at indexPath: IndexPath) -> UICollectionViewLayoutAttributes? {

if self.collectionView? .numberOfems (inSection: 0) == 0 {return nil}

if let attr = super.layoutAttributesForItem (by: indexPath)?. copy () like? UICollectionViewLayoutAttributes {
self.updateCellAttributes (attr)
return attr
}
return zero
}

internal override func finalLayoutAttributesForDisappearingItem (by itemIndexPath: IndexPath) -> UICollectionViewLayoutAttributes? {
// attributes for swiping cards away
return self.layoutAttributesForItem (by: itemIndexPath)
}

internal override func initialLayoutAttributesForAppearingItem (by itemIndexPath: IndexPath) -> UICollectionViewLayoutAttributes? {
// attributes to add cards
return self.layoutAttributesForItem (by: itemIndexPath)
}

// We invalidate the setup when a "boundary change" occurs, for example, when we scale the top cell. This forces a layout update on the flow statement.
internal override function shouldInvalidateLayout (forBoundsChange newBounds: CGRect) -> Bool {
return true
}

// Cell paging
internal override targetContentOffset (forProposedContentOffset proposedContentOffset: CGPoint, with Scrolling Velocity speed: CGPoint) -> CGPoint {

// If the property `isPagingEnabled` is set to false, we do not enable paging and thus return the current content statement.
guard la collectionView = self.collectionView, isPagingEnabled else {
la latestOffset = super.targetContentOffset (forProposedContentOffset: proposedContentOffset, with Scrolling Velocity: speed)
return lastOffset
}

// Side height used to estimate and calculate paging.
la sideHeight = cellHeight + self.minimumLineSpacing

// Make an overview of the current page position.
la approximatePage = collectionView.contentOffset.y / pageHeight

// Determine the current page based on speed.
let currentPage = (speed.y <0.0)? floor (approximate side): roof (approximate side)

// Create custom flickVelocity.
let flickVelocity = speed.y * 0.4

// Check how many pages the user tabbed if <= 1 so flickedPages should return 0.
la flickedPages = (abs (round (flickVelocity)) <= 1) ? 0 : round(flickVelocity)

        // Calculate newVerticalOffset.
        let newVerticalOffset = ((currentPage + flickedPages) * pageHeight) - collectionView.contentInset.top

        return CGPoint(x: proposedContentOffset.x, y: newVerticalOffset)
    }

    /**
     Updates the attributes.
     Here manipulate the zIndex of the cells here, calculate the positions and do the animations.

     Below we'll briefly explain how the effect of scrolling a card to the background instead of the top is achieved.
     Keep in mind that (x,y) coords in views start from the top left (x: 0,y: 0) and increase as you go down/to the right,
     so as you go down, the y-value increases, and as you go right, the x value increases.

     The two most important variables we use to achieve this effect are cvMinY and cardMinY.
     * cvMinY (A): The top position of the collectionView + inset. On the drawings below it's marked as "A".
     This position never changes (the value of the variable does, but the position is always at the top where "A" is marked).
     * cardMinY (B): The top position of each card. On the drawings below it's marked as "B". As the user scrolls a card,
     this position changes with the card position (as it's the top of the card).
     When the card is moving down, this will go up, when the card is moving up, this will go down.

     We then take the max(cvMinY, cardMinY) to get the highest value of those two and set that as the origin.y of the card.
     By doing this, we ensure that the origin.y of a card never goes below cvMinY, thus preventing cards from scrolling upwards.


     +---------+   +---------+
     |         |   |         |
     | +-A=B-+ |   |  +-A-+  | ---> The top line here is the previous card
| | | | | + - B - + | It is visible when the user starts scrolling.
| | | | | | | |
| | | | | | | | | When the card moves down,
| | | | | | | | v cardMinY ("B") goes up.
| + ----- + | | | | |
| | | + ----- + |
| + - B - + | | + - B - + |
| | | | | | | |
+ - + ----- + - + + - + ----- + - +


- Parameter attributes: The attributes we update.
* /
private func updateCellAttributes (_ attributes: UICollectionViewLayoutAttributes) {

guard la collectionView = collectionView otherwise {return}

var cvMinY = collectionView.bounds.minY + collectionView.contentInset.top
la cardMinY = attributes.frame.minY
was origin = attributes.frame.origin
la cardHeight = attributes.frame.height

if cvMinY> cardMinY + cardHeight + minimumLineSpacing + collectionView.contentInset.top {
cvMinY = 0
}

la finalY = max (cvMinY, cardMinY)

la deltaY = (finalY - cardMinY) / cardHeight
transformAttributes (attributes: attributes, deltaY: deltaY)

// Set attributes frame position to the values ​​we have calculated
origin.x = collectionView.frame.width / 2 - attributes.frame.width / 2 - collectionView.contentInset.left
origin.y = finalY
attributes.frame = CGRect (origin: origin, size: attributes.frame.size)
attributes.zIndex = attributes.indexPath.row
}

// Creates and uses a CGAffineTransform for attributes to replicate the effect of the card that goes to the background.
private func transformAttributes (attributes: UICollectionViewLayoutAttributes, deltaY: CGFloat) {

if let itemTransform = firstItemTransform {

let scale = 1 - deltaY * itemTransform
la translationScale = CGFloat ((attributes.zdex + 1) * 10)
was t = CGAffineTransform.identity

t = t.scaledBy (x: scale, y: 1)
if are previously short-sighted {
t = t.translatedBy (x: 0, y: (deltaY * translationScale))
}
attributes.transform = t
}
}
}

Full project list (immediate download)

Github repo

Github problem

If you have more questions, I would like to answer them.
Thanks for your time and effort, your help will be greatly appreciated!


Source link