Show/hide content in expandable collection view cell - ios

I have a collection view with two cells. I made cells expand/collapse by select(didSelectItemAtIndexPath). Cell contains additional views which should became visible in expanded mode and hidden in collapsed. My code work well if I play with expanded cell, but if I have expanded cell and tap on collapsed the expanded cell change their size but additional view stay visible. Maybe it will be easy to understand looking on the gif.
Good scenario:
click first cell = expand it
click first cell again = collapse it and hide image view
Bag scenario:
click first cell = expand it
click second cell = expand second cell & collapse first cell but additional image view on first cell still visible
click second cell again = collapse second cell and hide their content. additional image view on first cell still visible
Here is cell code:
class ExerciseSetCell: BaseCell {
// timer
let timerButton: UIButton = {
let button = UIButton()
button.setImage(UIImage(named: "timer"), forState: .Normal)
button.frame = CGRectMake(0, 0, 25, 25)
button.alpha = 0
return button
}()
override func setupViews() {
super.setupViews()
backgroundColor = UIColor.whiteColor()
addSubview(timerButton)
timerButton.snp_makeConstraints { (make) in
make.width.equalTo(25)
make.height.equalTo(25)
make.bottomMargin.equalTo(-7)
make.centerX.equalTo(self)
}
}
}
Here is my collectionViewController code:
class ExerciseDetailVC: UICollectionViewController, UICollectionViewDelegateFlowLayout {
var exercise: Exercise?
let exerciseSetCell = ExerciseSetCell()
private let setCell = "ExerciseSetCell"
private var expandedCellIndex = -1
override func viewDidLoad() {
super.viewDidLoad()
collectionView?.registerClass(ExerciseSetCell.self, forCellWithReuseIdentifier: setCell)
}
override func collectionView(collectionView: UICollectionView, numberOfItemsInSection section: Int) -> Int {
return 2
}
override func collectionView(collectionView: UICollectionView, cellForItemAtIndexPath indexPath: NSIndexPath) -> UICollectionViewCell {
let cell = collectionView.dequeueReusableCellWithReuseIdentifier(setCell, forIndexPath: indexPath) as! ExerciseSetCell
return cell
}
override func collectionView(collectionView: UICollectionView, didSelectItemAtIndexPath indexPath: NSIndexPath) {
let cell = collectionView.cellForItemAtIndexPath(indexPath) as! ExerciseSetCell
if expandedCellIndex == indexPath.item {
UIView.animateWithDuration(0.1, animations: {
cell.weightView.alpha = 0
cell.timerButton.alpha = 0
})
expandedCellIndex = -1
} else {
UIView.animateWithDuration(0.25, animations: {
cell.weightView.alpha = 1
cell.timerButton.alpha = 1
})
expandedCellIndex = indexPath.item
}
collectionView.reloadData()
}
func collectionView(collectionView: UICollectionView, layout collectionViewLayout: UICollectionViewLayout, sizeForItemAtIndexPath indexPath: NSIndexPath) -> CGSize {
if expandedCellIndex == indexPath.item {
return CGSizeMake(view.frame.width, 200)
}
return CGSizeMake(view.frame.width, 60)
}
func collectionView(collectionView: UICollectionView, layout collectionViewLayout: UICollectionViewLayout, minimumLineSpacingForSectionAtIndex section: Int) -> CGFloat {
return 2
}

Related

How to show only selected cell of collectionView after 2-3 second of loading CollectionView

I have UICollectionView with 60 item. while selecting item in collection i am navigating to next screen and there also i am showing horizontal UICollectionView and selected cell is highlighted there. now i want to implement after 2-3 second of view appear only selected item(which is highlighted) should show, rest should be invisible(or should not show)
First override delegate method and didSelectItemAt method
Than already you have a list of array of 60 items.
func collectionView(_ collectionView: UICollectionView, numberOfItemsInSection section: Int) -> Int
{
return list.count
}
override func collectionView(_ collectionView: UICollectionView, didSelectItemAt indexPath: IndexPath)
{
addToList.append(objectsArray[indexPath.row])
let cell = collectionView.cellForItem(at: indexPath)
cell?.layer.borderWidth = 2.0
cell?.layer.borderColor = UIColor.gray.cgColor
}
#objc func hideChannel() {
if let channel = TVManager.shared.currentChannel {
for item in 0...self.viewModel.channelCount {
if let cell = collectionView.cellForItem(at: IndexPath(item: item, section: 0)) as? PlayerCell {
if cell.channelId != channel.id {
UIView.animate(withDuration: 0.4) {
cell.alpha = 0.0
}
}
}
}
}
}

UICollectionView reuse in UITableViewCell

I know this question is already ask many times but non of the solution will work.
I have collection view in uitableview cell and i prepare a cell of table view and collection view in story board and my problem is that suppose i scroll cell 1 collection view then cell 4 collection is auto scroll to that position also. How i can handle this situation..
Please note right now i make a static design of the screen
My code
// MARK:
// MARK: table view delegate method
func numberOfSectionsInTableView(tableView: UITableView) -> Int {
return 1
}
func tableView(tableView: UITableView, heightForRowAtIndexPath indexPath: NSIndexPath) -> CGFloat {
if Appconstant.isIpad()
{
return 215.0
}
return 185.0
}
func tableView(tableView: UITableView, numberOfRowsInSection section: Int) -> Int {
return 6
}
func tableView(tableView: UITableView, cellForRowAtIndexPath indexPath: NSIndexPath) -> UITableViewCell {
let strCell = "WorkoutCell" //+ "\(indexPath.row)"
let cell = tableView.dequeueReusableCellWithIdentifier(strCell) as? WorkoutCell
// if cell == nil
// {
// cell = work
// }
return cell!
}
func tableView(tableView: UITableView, willDisplayCell cell: UITableViewCell, forRowAtIndexPath indexPath: NSIndexPath) {
let cell2 = cell as! WorkoutCell
cell2.collecionWorkout.reloadData()
}
// MARK:
// MARK: collectionview delegate and data source
//1
func shouldInvalidateLayoutForBoundsChange(newBounds: CGRect) -> Bool {
return true
}
func numberOfSectionsInCollectionView(collectionView: UICollectionView) -> Int {
return 1
}
//2
func collectionView(collectionView: UICollectionView, numberOfItemsInSection section: Int) -> Int {
return 10
}
func collectionView(collectionView: UICollectionView, layout collectionViewLayout: UICollectionViewLayout, insetForSectionAt section: Int) -> UIEdgeInsets {
return UIEdgeInsetsMake(0.0, 10.0, 0.0, 10.0)
}
func collectionView(collectionView: UICollectionView, layout collectionViewLayout: UICollectionViewLayout, sizeForItemAt indexPath: NSIndexPath) -> CGSize {
// Adjust cell size for orientation
if Appconstant.isIpad() {
return CGSize(width: 160, height: 150)
}
return CGSize(width: 140.0, height: 130.0)
}
//3
func collectionView(collectionView: UICollectionView, cellForItemAtIndexPath indexPath: NSIndexPath) -> UICollectionViewCell {
let cell = collectionView.dequeueReusableCellWithReuseIdentifier("WorkoutCollectionCell", forIndexPath: indexPath)
// Configure the cell
return cell
}
uitableview cell code
class WorkoutCell: UITableViewCell {
#IBOutlet weak var collecionWorkout: UICollectionView!
var flowLayout : UICollectionViewFlowLayout!
override func awakeFromNib() {
super.awakeFromNib()
self.flowLayout = UICollectionViewFlowLayout()
if Appconstant.isIpad()
{
self.flowLayout.itemSize = CGSize(width: 160, height: 150)
}
else
{
self.flowLayout.itemSize = CGSize(width: 140, height: 130)
}
self.flowLayout.scrollDirection = .Horizontal
self.flowLayout.minimumInteritemSpacing = 10.0
flowLayout.sectionInset = UIEdgeInsetsMake(0.0, 10.0, 0.0, 10.0);
collecionWorkout.collectionViewLayout = flowLayout
// Initialization code
}
override func setSelected(selected: Bool, animated: Bool) {
super.setSelected(selected, animated: animated)
// Configure the view for the selected state
}
}
Cell 1st which i scroll
cell 4th which auto scroll
There are two scenarios.
1 - Reset The UICollectionView offset position :
To Reset the collectionview position just call cell.collectionView.contentOffset = .zero in cellForRowAtIndexPath
2 - Maintain the previous scroll position :
To Maintain the previous scroll position, You'll need to have a list of offsets for each cell stored alongside your data models in the containing view controller. Then you might save the offset for a given cell in didEndDisplayingCell and setting it in cellForRowAtIndexPath instead of .zero .
UITableView works on the concept of reusability. Whenever the tableView is scrolled, the cells in the tableView will definitely be reused.
Now 2 scenarios arise with this,
Get a new cell - When the tableViewCell is reused, the collectionView inside it also will be reused and so this is the reason the contentOffset of the previous cell is retained.
Scroll to previous cell - if we've manually scrolled to a particular cell in the collectionView, we might want to retain its position when we scroll back to it.
To get this kind of functionality in tableView, we need to - manually reset the contentOffset for 1st case and need to retain the contentOffset in the 2nd one.
Another approach you can follow is using a combination of UIScrollview and UIStackView.
This is how it goes.
In storyboard, create a UIScrollView. Add a vertical UIStackView to it.
Add 4 UICollectionViews in the stackView. This number is configurable as per your requirement.
Add your controller as the dataSource and delegate of all the collectionViews.
i.e.
class ViewController: UIViewController, UICollectionViewDataSource {
override func viewDidLoad() {
super.viewDidLoad()
}
func collectionView(_ collectionView: UICollectionView, numberOfItemsInSection section: Int) -> Int {
return 10
}
func collectionView(_ collectionView: UICollectionView, cellForItemAt indexPath: IndexPath) -> UICollectionViewCell {
let cell = collectionView.dequeueReusableCell(withReuseIdentifier: "cell", for: indexPath) as! CustomCell
cell.label.text = "\(indexPath.row)"
return cell
}
}
class CustomCell: UICollectionViewCell {
#IBOutlet weak var label: UILabel!
}
Now, since we're using a stackView, none of the collectionViews will be reused. So, the contentOffsets of the all the collectionViews will remain intact.

rearrange collectionViewCell once the scrolling to next item ends

I have a collectionView and my collectionViewCell contains an imageView, so when I'm loading my view for the first time it seems fine, but when I scroll through it, it gets misplaced , see the images
i have 3 images in my collectionView cell the first image is at place but not the second and third images
before scrolling (image1)
after scrolling (image2) (when am horizontally switching to next image)
my collectinView supports Horizontal Scroll and (pink background) is my cell , (yellow background) is CollectionView as you can see once I scroll to next image my cell gets a little out of screens, any idea how to fix this ???
my codes :
in tableView:
extension TableViewController: UICollectionViewDelegate, UICollectionViewDataSource {
func collectionView(collectionView: UICollectionView,
numberOfItemsInSection section: Int) -> Int {
return contentImages[collectionView.tag].count
}
func shouldInvalidateLayoutForBoundsChange(newBounds: CGRect) -> Bool {
return true
}
func collectionView(collectionView: UICollectionView,
cellForItemAtIndexPath indexPath: NSIndexPath) -> UICollectionViewCell {
let cell = collectionView.dequeueReusableCellWithReuseIdentifier("Cell",
forIndexPath: indexPath) as! CollectionViewCell
//cell.imgView.frame = CGRectMake(0, 0, collectionView.frame.width, collectionView.frame.height)
cell.imgViewOfCell.contentMode = .ScaleAspectFit
cell.imgViewOfCell.image = ResizeImage(UIImage(named: contentImages[collectionView.tag][indexPath.item])!, targetSize: CGSizeMake( cell.imgViewOfCell.frame.width , cell.imgViewOfCell.frame.height))
//imageView.image = UIImage(named: imageModel[collectionView.tag][indexPath.item])
return cell
}
}
collectionViewCell :
class CollectionViewCell: UICollectionViewCell {
#IBOutlet var imgViewOfCell: UIImageView!
override func awakeFromNib() {
imgViewOfCell.frame = self.bounds
self.contentView.setNeedsLayout()
}
}
in tableViewCell:
func setCollectionViewDataSourceDelegate
<D: protocol<UICollectionViewDataSource, UICollectionViewDelegate>>
(dataSourceDelegate: D, forRow row: Int) {
collectionView.delegate = dataSourceDelegate
collectionView.dataSource = dataSourceDelegate
collectionView.tag = row
collectionView.reloadData()
}
var collectionViewOffset: CGFloat {
get {
return collectionView.contentOffset.x
}
set {
collectionView.contentOffset.x = newValue
}
}
Any idea of how to fix this? Please let me know what am doing wrong or what I'm missing.
ended up with this ,after debugging i got to know that my Cell's x origin was not accurate , so am calculating this manually on my cellForItemAtIndexPath like this :
func collectionView(collectionView: UICollectionView,
cellForItemAtIndexPath indexPath: NSIndexPath) -> UICollectionViewCell {
let cell = collectionView.dequeueReusableCellWithReuseIdentifier("Cell",
forIndexPath: indexPath) as! CollectionViewCell
cell.imgViewOfCell.contentMode = .ScaleAspectFit
if indexPath.row == 0 {
cell.frame.origin.x = 0
}else if indexPath.row == 1 {
cell.frame.origin.x = self.view.bounds.width
}else if indexPath.row == 2 {
cell.frame.origin.x = (self.view.bounds.width*2)
}else if indexPath.row == 3 {
cell.frame.origin.x = (self.view.bounds.width*3)
}
....... }

Animating a CollectionViewCell Size To Outside CollectionView Boundary - Swift

I have been working on animating the size of some collectionViewCells. It is working great in my collectionViewController, but in another UIViewController where I have a small collectionView alongside other objects, the cell will only grow to the size of the collectionView. I would like it to fill the whole screen. What is the best way about doing this?
Here is my current code:
var largePhotoIndexPath : NSIndexPath? {
didSet{
var indexPaths = [NSIndexPath]()
if largePhotoIndexPath != nil {
indexPaths.append(largePhotoIndexPath!)
}
if oldValue != nil {
indexPaths.append(oldValue!)
}
collectionView?.performBatchUpdates({ () -> Void in
self.collectionView?.reloadItemsAtIndexPaths(indexPaths)
return
}){
completed in
if self.largePhotoIndexPath != nil {
self.collectionView?.scrollToItemAtIndexPath(self.largePhotoIndexPath!, atScrollPosition: .CenteredVertically, animated: true)
}
}
}
}
func collectionView(collectionView: UICollectionView, shouldSelectItemAtIndexPath indexPath: NSIndexPath) -> Bool {
if largePhotoIndexPath == indexPath {
largePhotoIndexPath = nil
}
else {
largePhotoIndexPath = indexPath
}
return false
}
func collectionView(collectionView: UICollectionView, layout collectionViewLayout: UICollectionViewLayout, sizeForItemAtIndexPath indexPath: NSIndexPath) -> CGSize {
let dealImage: UIImage = UIImage(data: self.imageDataArray[indexPath.row])!
let dealPhoto: UIImageView = UIImageView(image: dealImage)
if indexPath == largePhotoIndexPath {
var size = UIScreen.mainScreen().bounds
dealPhoto.frame == size
return CGSize(width: 300, height: 525)
}
return CGSize(width: 100, height: 175)
}
func collectionView(collectionView: UICollectionView, numberOfItemsInSection section: Int) -> Int {
return self.imageDataArray.count
}
func collectionView(collectionView: UICollectionView, cellForItemAtIndexPath indexPath: NSIndexPath) -> UICollectionViewCell {
let cell = collectionView.dequeueReusableCellWithReuseIdentifier("Cell", forIndexPath: indexPath) as! TrailInfoCollectionViewCell
cell.imageView.image = UIImage(data: self.imageDataArray[indexPath.row])
return cell
}
And some images before and after I select the cell:
As you can see, the image has grown to the size I want it, but it is constrained by the collectionView. Is it possible for a collectionViewCell to exceed the boundaries of a collectionView, or will I have to do it some other way? I would just set up a hidden imageView but I like the animated transition.
Thanks for your help. Please let me know if you need any more details.
clipsToBounds properties is what prevents a subview from growing past it's parent. Set it to false and it should work.

didSelectItemAtIndexPath modifying multiple cells in UICollectionView

I have collection view with 30 items, and want to perform something on press. I do it in this way:
func collectionView(collectionView: UICollectionView, didSelectItemAtIndexPath indexPath: NSIndexPath) {
let cell = collectionView.cellForItemAtIndexPath(indexPath) as! ItemCell
var translucentView = ILTranslucentView(frame: CGRectMake(0, 0, cell.contentView.frame.size.width, cell.contentView.frame.size.height))
translucentView.translucentAlpha = 0.9
translucentView.translucentStyle = UIBarStyle.BlackTranslucent
translucentView.translucentTintColor = UIColor.clearColor()
translucentView.backgroundColor = UIColor.clearColor()
translucentView.alpha = 0.0
cell.contentView.addSubview(translucentView)
UIView.animateWithDuration(0.4, animations: {
translucentView.alpha = 1.0
})
}
The function works as expected, however the view appears not only on the tapped cell, but also on the cell in the same position that is not visible on the screen.
So if there are 3 visible cells on the screen and I tap on number 1, then when I scroll the view has been added to cell 4, 7, etc...
UICollectionView re-use cells like to UITableView. When a cell is scrolled offscreen it is added to queue, and will be re-used for the next cell to be scrolled onscreen(e.g. cell 4, 7 ...).
Simply removing the translucentView will solve this issue:
UIView.animateWithDuration(0.4, animations: { () -> Void in
translucentView.alpha = 1.0
}) { (finish) -> Void in
translucentView.removeFromSuperview()
}
You can create the translucentView in the ItemCell and update its status in the cellForItemAtIndexPath method:
override func collectionView(collectionView: UICollectionView, cellForItemAtIndexPath indexPath: NSIndexPath) -> UICollectionViewCell {
let cell = collectionView.dequeueReusableCellWithReuseIdentifier(CellIdentifier, forIndexPath: indexPath) as! ItemCell
if find(collectionView.indexPathsForSelectedItems() as! [NSIndexPath], indexPath) != nil {
cell.translucentView.alpha = 1.0
} else {
cell.translucentView.alpha = 0.0
}
return cell
}
override func collectionView(collectionView: UICollectionView, didSelectItemAtIndexPath indexPath: NSIndexPath) {
let cell = collectionView.cellForItemAtIndexPath(indexPath) as! ItemCell
UIView.animateWithDuration(0.4, animations: {
cell.translucentView.alpha = 1.0
})
}
override func collectionView(collectionView: UICollectionView, didDeselectItemAtIndexPath indexPath: NSIndexPath) {
let cell = collectionView.cellForItemAtIndexPath(indexPath) as! ItemCell
UIView.animateWithDuration(0.4, animations: {
cell.translucentView.alpha = 0.0
})
}
did you set your numberOfSectionsInTableView correctly like that?
func numberOfSectionsInCollectionView(collectionView: UICollectionView) -> Int {
return 1
}

Resources