Center Horizontal Uicollectionview Based on Content

How to center horizontally UICollectionView Cells?

Its not a good idea to use a library, if your purpose is only this i.e to centre align.

Better you can do this simple calculation in your collectionViewLayout function.

func collectionView(collectionView: UICollectionView, layout collectionViewLayout: UICollectionViewLayout, insetForSectionAtIndex section: Int) -> UIEdgeInsets {

let totalCellWidth = CellWidth * CellCount
let totalSpacingWidth = CellSpacing * (CellCount - 1)

let leftInset = (collectionViewWidth - CGFloat(totalCellWidth + totalSpacingWidth)) / 2
let rightInset = leftInset

return UIEdgeInsets(top: 0, left: leftInset, bottom: 0, right: rightInset)
}

Center horizontal UICollectionView based on content

Assuming your current code is working when you the cells will fit - that is, it centers the "row of cells" when desired - change this line:

let leftInset = (collectionViewWidth - CGFloat(totalCellWidth + totalSpacingWidth)) / 2

to:

let leftInset = max(0, (collectionViewWidth - CGFloat(totalCellWidth + totalSpacingWidth)) / 2.0)

That way your insets will never be less than Zero

How to center align the cells of a UICollectionView?

I think you can achieve the single line look by implementing something like this:

- (UIEdgeInsets)collectionView:(UICollectionView *)collectionView layout:(UICollectionViewLayout*)collectionViewLayout insetForSectionAtIndex:(NSInteger)section {
return UIEdgeInsetsMake(0, 100, 0, 0);
}

You will have to play around with that number to figure out how to force the content into a single line. The first 0, is the top edge argument, you could adjust that one too, if you want to center the content vertically in the screen.

Detect which UICollectionViewCell of a uicollectionView that is inside another uicollectionview is in the center

Your best bet would be delegates via protocols

Create protocol for your collection view cells

protocol yourDelegate: class {

func didSelectCell(WithIndecPath indexPath: IndexPath, InCollectionView collectionView: UICollectionView) -> Void

}

In your cells, create a function called setup which you can call at cellForRow.
In your cells, create a touch recogniser for self.
Disable cell selection for your collection views since these delegates will be called when the user touches given cell.

class yourCell: UICollectionViewCell  {

var indexPath: IndexPath? = nil
var collectionView: UICollectionView? = nil

weak var delegate: yourDelegate? = nil

override func awakeFromNib() {
super.awakeFromNib()

let selfTGR = UITapGestureRecognizer(target: self, action: #selector(self.didTouchSelf))
self.contentView.addGestureRecognizer(selfTGR)
}

@objc func didTouchSelf() {
guard let collectionView = self.collectionView, let indexPath = self.indexPath else {
return
}

delegate?.didSelectCell(WithIndecPath: indexPath, InCollectionView: collectionView)
}

func setupCell(WithIndexPath indexPath: IndexPath, CollectionView collectionView: UICollectionView, Delegate delegate: yourDelegate) {
self.indexPath = indexPath
self.collectionView = collectionView
self.delegate = delegate
}

}

In your viewController, create extension for this protocol and if you do everything right, when the user touches your cell, the cell will call you via this delegation.

extension YourViewController: yourDelegate {

func didSelectCell(WithIndecPath indexPath: IndexPath, InCollectionView collectionView: UICollectionView) {
//You have your index path and you can "if" your colllection view

if collectionView == self.yourFirstCollectionView {

} else if collectionView == self.yourSecondCollectionView {

}
//and so on..
}

}

since protocol is ": class", we can use weak for your delegate property so no memory leak will occur. I use this method for tableViews and collectionViews throughout my projects.

Align cell in center(horizontally) in UICollectionView

I'd control the focus and the collection content offset (scroll position) separately.

For the content offset you should set the section margins and the inter-item spacing so that you have one cell centred and the adjacent cells visible at the edges. You can get this setup and tested without showing any focus.

Presumably there is difficulty getting the item to move exactly to the centre when you scroll (the focus changes). To resolve this, implement - scrollViewWillEndDragging:withVelocity:targetContentOffset: to find the item at the targetContentOffset and get its centre point (from the layout attributes). With that you can modify the targetContentOffset such that the scroll ends exactly with the item centred.

Now, the focus should be managed by the cell itself, not the collection view. Below is a (slightly large) example of a cell focus change animation. It uses cartography to change image view constraints and applies a transform to a label. You can do something similar depending on how you want the image and label to interact with each other.

Note that the below code also applies a motion effect transform similar to the stock supplied by apple when a UIImageView has focus and has adjustsImageWhenAncestorFocused set. If you don't want that you can simplify and shorten the code quite a bit.

override func didUpdateFocusInContext(context: UIFocusUpdateContext, withAnimationCoordinator coordinator: UIFocusAnimationCoordinator) {
super.didUpdateFocusInContext(context, withAnimationCoordinator: coordinator)

if (context.nextFocusedView == self) {
UIView.animateWithDuration(0.1,
animations: { () -> Void in
self.imageConstraints = constrain(self.itemImageView, replace: self.imageConstraints!) {
$0.top == $0.superview!.top
$0.bottom == $0.superview!.bottom
$0.leading == $0.superview!.leading
$0.trailing == $0.superview!.trailing
}
self.itemLabel.transform = CGAffineTransformMakeTranslation(0, 60)
self.itemLabel.layer.backgroundColor = UIColor.darkGrayColor().colorWithAlphaComponent(0).CGColor

self.layer.shadowOpacity = 1

self.layoutIfNeeded()
}, completion: nil)

let minMaxAngle = 10.0
let m34 = CGFloat(1.0 / -1250)
let angle = CGFloat(minMaxAngle * M_PI / 180.0)

var baseTransform = CATransform3DIdentity
baseTransform.m34 = m34

let rotateXmin = CATransform3DRotate(baseTransform, -1 * angle, 1.0, 0.0, 0.0);
let rotateXmax = CATransform3DRotate(baseTransform, angle, 1.0, 0.0, 0.0);
let rotateYmin = CATransform3DRotate(baseTransform, angle, 0.0, 1.0, 0.0);
let rotateYmax = CATransform3DRotate(baseTransform, -1 * angle, 0.0, 1.0, 0.0);

let verticalMotionEffect = UIInterpolatingMotionEffect(keyPath: "layer.transform",
type: .TiltAlongVerticalAxis)
verticalMotionEffect.minimumRelativeValue = NSValue(CATransform3D: rotateXmin)
verticalMotionEffect.maximumRelativeValue = NSValue(CATransform3D: rotateXmax)

let horizontalMotionEffect = UIInterpolatingMotionEffect(keyPath: "layer.transform",
type: .TiltAlongHorizontalAxis)
horizontalMotionEffect.minimumRelativeValue = NSValue(CATransform3D: rotateYmin)
horizontalMotionEffect.maximumRelativeValue = NSValue(CATransform3D: rotateYmax)

let group = UIMotionEffectGroup()
group.motionEffects = [horizontalMotionEffect, verticalMotionEffect]

self.addMotionEffect(group)

}
else {
UIView.animateWithDuration(0.3,
animations: { () -> Void in
self.imageConstraints = constrain(self.itemImageView, replace: self.imageConstraints!) {
$0.top == $0.superview!.top + 20
$0.bottom == $0.superview!.bottom - 20
$0.leading == $0.superview!.leading + 20
$0.trailing == $0.superview!.trailing - 20
}
self.itemLabel.transform = CGAffineTransformIdentity
self.itemLabel.layer.backgroundColor = UIColor.darkGrayColor().colorWithAlphaComponent(0.75).CGColor

self.layer.shadowOpacity = 0

self.layoutIfNeeded()
}, completion: nil)

for effect in self.motionEffects {
self.removeMotionEffect(effect)
}
}
}


Related Topics



Leave a reply



Submit