Dynamic TableView Swift 3 With Beginning Graph - dynamic

I have a tableview that gets its information from a database and returns it as "results. The TableView Data Source is as follows:
func tableView(_ tableView: UITableView, numberOfRowsInSection section: Int) -> Int {
if isLoading {
print("isLoading")
return 1
}else if results.count == 0 {
return 1
} else {
print("results Count:", results.count)
return results.count
}
}
enum MyRows: Int {
case graph = 0
}
func tableView(_ tableView: UITableView,
cellForRowAt indexPath: IndexPath) -> UITableViewCell {
if indexPath.row == MyRows.graph.rawValue {
let graphcell = tableView.dequeueReusableCell(withIdentifier: TableViewCellIdentifiers.GraphCell,for: indexPath) as! PendingGraphCell
graphcell.configureForGraph(graphData: self.graphData)
return graphcell
}
print(indexPath)
if isLoading {
let cell = tableView.dequeueReusableCell(withIdentifier: TableViewCellIdentifiers.loadingCell, for:indexPath)
return cell
} else if results.count == 0 {
return tableView.dequeueReusableCell(withIdentifier: TableViewCellIdentifiers.nothingFoundCell,for: indexPath)
} else {
let cell = tableView.dequeueReusableCell(withIdentifier: TableViewCellIdentifiers.ResultCell,for: indexPath) as! ResultCell
let result = results[indexPath.row];
print(result)
cell.configureForResult(result: result)
return cell
}
}
The tableView works perfectly when I remove the "Graph" Cell:
if indexPath.row == MyRows.graph.rawValue {
let graphcell = tableView.dequeueReusableCell(withIdentifier: TableViewCellIdentifiers.GraphCell,for: indexPath) as! PendingGraphCell
graphcell.configureForGraph(graphData: self.graphData)
return graphcell
}
So I need to update the number of rows to include the 1st static row. Did that and then I receive an error.
Index out of range.
Table Views really confuse me, I've been working on this all night. Any help would be appreciated.
EDIT:
I edited the count to 4 and still got the same error. And results.count = 3
Here is the error:
Index out of range
Here is the Exception Breakpoint where it fails
let pendingResult = pendingResults[indexPath.row];
Also, my output cell for the graph is different than the one for the results cell. The results cell is 44 and so every other cell in my table is set to 44.. What gives?
Denis Angell

try this code.
func tableView(_ tableView: UITableView,
cellForRowAt indexPath: IndexPath) -> UITableViewCell {
if indexPath.row == MyRows.graph.rawValue {
let graphcell = tableView.dequeueReusableCell(withIdentifier: TableViewCellIdentifiers.GraphCell,for: indexPath) as! PendingGraphCell
graphcell.configureForGraph(graphData: self.graphData)
return graphcell
}
else{
var cell = tableView.dequeueReusableCell(withIdentifier: TableViewCellIdentifiers.ResultCell,for: indexPath) as! ResultCell
if isLoading {
cell = tableView.dequeueReusableCell(withIdentifier: TableViewCellIdentifiers.loadingCell, for:indexPath)
} else if results.count == 0 {
cell = tableView.dequeueReusableCell(withIdentifier: TableViewCellIdentifiers.nothingFoundCell,for: indexPath)
} else {
cell = tableView.dequeueReusableCell(withIdentifier: TableViewCellIdentifiers.ResultCell,for: indexPath) as! ResultCell
let result = pendingResults[indexPath.row];
print(result)
cell.configureForResult(result: result)
}
return cell
}
}

Related

how to implement single selection swapping of the cell in collection view swift

I am having a collection view when i select a cell it should change the colour of the cell to yellow and when i select the next cell it should change its colour yellow but it should change the previous cell colour back to clear and i only want at a time 1 selected cell all the other remaining cells should remain clear color and only the selected should be in the yellow colour
Can anyone help me with this
var selectedFirstIndexPath = [IndexPath]()
var selectedSecondIndexPath : IndexPath?
var selection = false
func collectionView(_ collectionView: UICollectionView, cellForItemAt indexPath: IndexPath) -> UICollectionViewCell {
guard let cell = detailedCollectionView.dequeueReusableCell(withReuseIdentifier: "cellZain", for: indexPath) as? BillingDetailVCollectionCell else {
return UICollectionViewCell()
}
cell.titleLabel.text = colltnTitleName?[indexPath.row].name
if self.selectedFirstIndexPath != [] && [indexPath] == self.selectedFirstIndexPath {
cell.viewBG.backgroundColor = UIColor.yellow
cell.titleLabel.textColor = UIColor.black
selection = true
}else {
cell.viewBG.backgroundColor = UIColor.clear
cell.titleLabel.textColor = UIColor.white
selection = false
}
return cell
}
func collectionView(_ collectionView: UICollectionView, didSelectItemAt indexPath: IndexPath) {
let cell = detailedCollectionView.cellForItem(at: indexPath) as? BillingDetailVCollectionCell
self.selectedSecondIndexPath = indexPath
detailedCollectionView.allowsMultipleSelection = false
cell?.viewBG.backgroundColor = UIColor.yellow
cell?.titleLabel.textColor = UIColor.black
self.selection = true
if self.selectedFirstIndexPath != [] {
detailedCollectionView.delegate?.collectionView?(detailedCollectionView, didDeselectItemAt: indexPath)
self.selectedFirstIndexPath = []
self.selection = false
cell?.viewBG.backgroundColor = UIColor.clear
cell?.titleLabel.textColor = UIColor.white
DispatchQueue.main.async {
self.detailedCollectionView.reloadItems(at:self.selectedFirstIndexPath)
}
}
}

Images are not setting properly to the collectionview cell

I am using a collection view and it contains an imageview. Images are in url format so I have written a function to convert the url into Image but images are not looking properly.
I have tried all the modes like aspect fit, aspect fill, scale to fill.
I have searched a lot on the internet but not come up with answer.
This is my code :
extension HomeDemoViewController : UICollectionViewDelegate,UICollectionViewDataSource{
func collectionView(_ collectionView: UICollectionView, numberOfItemsInSection section: Int) -> Int {
return bannerArray.count
}
func collectionView(_ collectionView: UICollectionView, cellForItemAt indexPath: IndexPath) -> UICollectionViewCell {
let cell = collectionView.dequeueReusableCell(withReuseIdentifier: "HomeAddCollectionViewCell", for: indexPath)
as! HomeAddCollectionViewCell
cell.imageview.setImageFromURl(stringImageUrl: imageArray[indexPath.row])
return cell
}
func collectionView(_ collectionView: UICollectionView, didSelectItemAt indexPath: IndexPath) {
let vc = self.storyboard!.instantiateViewController(withIdentifier: "MenuViewController") as! MenuViewController
self.navigationController!.pushViewController(vc, animated: true)
}
}
func setImageFromURl(stringImageUrl url: String){
if let url = NSURL(string: url) {
DispatchQueue.global(qos: .default).async{
if let data = NSData(contentsOf: url as URL) {
DispatchQueue.main.async {
self.image = UIImage(data: data as Data)
}
}
}
}
}
Describe your problem please, attach screenshot what’s wrong.
Seems like the problem is in the image, try setting the different content mode and if needed — clipsToBounds = true

CABasicAnimation stops when UICollectionView is reloaded

I need help with an issue in Collection Views. In my collectionView I am using UILongPressGestureRecognizer to start CABasicAnimation in the items (images), but when I remove an item and reload the collectionView the CABasicAnimation is interrupeted.
How can I prevent the animation stop?
I need the animation continues until the user decide to stop.
Here is some information about my collectionView:
class SentMemesCollectionVC: UICollectionViewController {
//MARK: - PROPERTIES
var memes: [Meme]! {
return Meme.accessMemes().memes
}
//MARK: - LIFE CYCLE
override func viewDidLoad() {
super.viewDidLoad()
let longPressGesture = UILongPressGestureRecognizer(target: self, action: #selector(longTap(_:)))
self.collectionView.addGestureRecognizer(longPressGesture)
}
#objc func longTap(_ gesture: UILongPressGestureRecognizer) {
switch gesture.state {
case .began:
print("LongPress begin")
guard let selectedIndexPath = collectionView.indexPathForItem(at: gesture.location(in: collectionView)) else {return}
collectionView.beginInteractiveMovementForItem(at: selectedIndexPath)
setEditing(true, animated: true)
default:
collectionView.cancelInteractiveMovement()
}
}
// MARK: - COLLECTIONVIEW DATA SOURCE
//Defini o número de itens em cada seção
override func collectionView(_ collectionView: UICollectionView, numberOfItemsInSection section: Int) -> Int {
return memes.count
}
override func collectionView(_ collectionView: UICollectionView, cellForItemAt indexPath: IndexPath) -> UICollectionViewCell {
let cell = collectionView.dequeueReusableCell(withReuseIdentifier: "gridCell", for: indexPath) as! GridMemeCell
let meme = memes[indexPath.row]
cell.prepareGridCell(with: meme)
cell.delegate = self
return cell
}
// MARK: - COLLECTIONVIEW DELEGATE
/*
override func collectionView(_ collectionView: UICollectionView, didSelectItemAt indexPath: IndexPath) {
let memeDetail = storyboard?.instantiateViewController(withIdentifier: "DetailVC") as! MemeDetailVC
let meme = memes[indexPath.row]
memeDetail.memeSelected = meme
Feedback.share.hapticFeedback()
navigationController?.pushViewController(memeDetail, animated: true)
}
*/
// MARK: - DELETE ITEMS IN COLLECTVIEW
override func setEditing(_ editing: Bool, animated: Bool) {
super.setEditing(editing, animated: animated)
Feedback.share.hapticFeedback()
if let indexPaths = collectionView?.indexPathsForVisibleItems {
for indexPath in indexPaths {
if let cell = collectionView?.cellForItem(at: indexPath) as? GridMemeCell {
if editing {
cell.isEditing = editing
cell.startAnimate()
doneBarButtonItem()
} else {
cell.isEditing = editing
cell.stopAnimate()
addBarButtonItem()
}
}
}
}
}
}
Here is my CollectionViewCell
class GridMemeCell: UICollectionViewCell {
//MARK: - OUTLETS
#IBOutlet weak var ivImage: UIImageView!
#IBOutlet weak var deleteMeme: UIVisualEffectView!
//MARK: - PROPERTIES
weak var delegate: GridMemeCellDelegate?
var isAnimate: Bool! = true
//MARK: - METHODS AND COMPUTED PROPERTIES
func prepareGridCell(with meme: Meme) {
ivImage.image = meme.memeImage
deleteMeme.layer.cornerRadius = deleteMeme.bounds.width / 2.0
deleteMeme.layer.masksToBounds = true
deleteMeme.isHidden = !isEditing
deleteMeme.contentView.backgroundColor = Theme.current.subViewColor
}
func startAnimate() {
let shakeAnimation = CABasicAnimation(keyPath: "transform.rotation")
shakeAnimation.duration = 0.05
shakeAnimation.repeatCount = 4
shakeAnimation.autoreverses = true
shakeAnimation.duration = 0.2
shakeAnimation.repeatCount = 99999
let startAngle: Float = (-2) * 3.14159 / 180
let stopAngle = -startAngle
shakeAnimation.fromValue = NSNumber(value: startAngle)
shakeAnimation.toValue = NSNumber(value: 3 * stopAngle)
shakeAnimation.autoreverses = true
shakeAnimation.timeOffset = 290 * drand48()
let layer: CALayer = self.layer
layer.add(shakeAnimation, forKey: "animate")
self.deleteMeme.isHidden = false
isAnimate = true
}
func stopAnimate() {
let layer: CALayer = self.layer
layer.removeAnimation(forKey: "animate")
self.deleteMeme.isHidden = true
isAnimate = false
}
var isEditing: Bool = false {
didSet {
deleteMeme.isHidden = !isEditing
}
}
#IBAction func btDeleteMeme(_ sender: Any) {
Feedback.share.hapticFeedback()
delegate?.deleteCell(cell: self)
}
}
And here is my Protocol Delegate Cell:
protocol GridMemeCellDelegate: class {
func deleteCell(cell: GridMemeCell)
}
And here is my extension CollectionView - Delegate.
extension SentMemesCollectionVC: GridMemeCellDelegate {
func deleteCell(cell: GridMemeCell) {
if let indexPath = collectionView.indexPath(for: cell) {
//Apaga o Meme do Array
Meme.accessMemes().memes.remove(at: indexPath.item)
collectionView.reloadData()
}
}
}

How to use AVPlayer and Image in UITableViewCell depending upon the response from my API

Functionality : I need to implement a tableview where the cells will have either an image or a video depending upon the category in my API.
Whats happening : The images and video are displayed well but when a cell with video is displayed it replaces all the cell with AVPlayer, the cells with the images too.
Code : -
(in cellForRowAtIndexPath - )
if (![dict[#"video_360x290"] isEqualToString:#""]) {
AVPlayerItem* playerItem = [AVPlayerItem playerItemWithURL:[NSURL URLWithString:dict[#"video_360x290"]]];
AVPlayer *playVideo = [[AVPlayer alloc] initWithPlayerItem:playerItem];
cell.playerViewController = [[AVPlayerViewController alloc] init];
cell.playerViewController.player = playVideo;
cell.playerViewController.player.volume = 10;
cell.playerViewController.view.frame = CGRectMake(0, 0, cell.vPost.frame.size.width, cell.vPost.frame.size.height);
[cell.vPost addSubview:cell.playerViewController.view];
[playVideo play];
}
else{
[cell.iPost sd_setImageWithURL:dict[#"image"] placeholderImage:[UIImage imageNamed:#"imageNotAvailable"] options:SDWebImageHighPriority];
}
What i Need : I need that cell with images displays images and cell with video displays video
Thanks in advance.
Let TableViewCell Class name is ImageVideoCell
Create THREE cells from Storyboard in TableView, 1 for Image and 2 for Video and change cell identifier. For Image Cell change Identifier to "ImageCell" and for Video Cell change Identifier to "VideoCell1" and "VideoCell2" add same tableViewCell Class on all cells like here ImageVideoCell.
And in Controller
class ViewController: UIViewController {
// MARK: - Outlets
#IBOutlet weak var tableView: UITableView!
// MARK: - Properties
var imgVideos = [ImgVideo?]()
var player : AVPlayer?
// MARK: - View Life Cycle
override func viewDidLoad() {
super.viewDidLoad()
// API call to get Images and videos in TableView
tableView.dataSource = self
}
override func viewWillDisappear(_ animated: Bool) {
super.viewWillDisappear(true)
if player?.isPlaying == true {
self.player?.pause()
self.player = nil
}
}
// MARK: - Action
#IBAction func play_pauseButtonPressed(_ sender: UIButton) {
guard let video = imgVideos[sender.tag] else { return } // get video URl here
guard let cell = tableView.cellForRow(at: IndexPath(row: sender.tag, section: 0)) as? ImageVideoCell else { return }
// if Video is already Playing And User want to Pause it then
if player?.isPlaying ?? false && video.isSelected {
player?.pause()
sender.setImage(#imageLiteral(resourceName: "play-button"), for: .normal)
}
// if the Video is pause and User want to Play it again
else if player?.isPlaying ?? true == false && video.isSelected {
player?.play()
sender.setImage(#imageLiteral(resourceName: "media-pause"), for: .normal)
}
// Play any other Video
else {
for (index, video) in audios.enumerated() {
if video?.isSelected ?? false {
video?.isSelected = false
tableView.beginUpdates()
tableView.reloadRows(at: [IndexPath(row: index, section: 0)], with: .none)
tableView.endUpdates()
}
}
video.isSelected = true
tableView.beginUpdates()
tableView.reloadRows(at: [IndexPath(row: sender.tag, section: 0)], with: .none)
tableView.endUpdates()
guard let cell = tableView.cellForRow(at: IndexPath(row: sender.tag, section: 0)) as? ImageVideoCell else { return }
cell.play_pauseButton.setImage(#imageLiteral(resourceName: "media-pause"), for: .normal)
play(videoUrl: vedio.url ?? "") // Play is a function for playing Videos
}
}
func tableView(_ tableView: UITableView, cellForRowAt indexPath: IndexPath) -> UITableViewCell {
let cell = ImageVideoCell()
if Image {
cell = tableView.dequeueReusableCell(withIdentifier: "ImageCell", for: indexPath) as! ImageVideoCell
// Display Img
}else {
if video?.isSelected ?? false {
cell = tableView.dequeueReusableCell(withIdentifier: "VideoCell1", for: indexPath) as! ImageVideoCell
}else {
cell = tableView.dequeueReusableCell(withIdentifier: "VideoCell2", for: indexPath) as! ImageVideoCell
}
}
cell.play_pauseButton.tag = indexPath.row
cell.play_pauseButton.setImage(audio?.isSelected ?? false ? #imageLiteral(resourceName: "media-pause") : #imageLiteral(resourceName: "play-button"), for: .normal)
return cell
}
}
// MARK: - AVPlayer
extension AVPlayer {
var isPlaying: Bool {
return ((rate != 0) && (error == nil))
}
}

Collection view cell not appear after resize the CollectionView height

I am facing the UICollectionView cell size issue. I am using two collection_view and one table_view 1:- Main CollectionView ,which is use for swipe and only display one cell at one time 2:- Inside Main Collection_View, i use table_view and now further inside table_view I am using Collection view which display 6 cell at one time.
Now the whole process is I am using a layout which is swipable and display 6 item at one page and so on.
The problem is when I set main cell height 200 then inside collectionview cell not appearing as expected.
Outer CollectionView Class
import UIKit
class ViewController: UIViewController {
#IBOutlet weak var collectionMain: UICollectionView!
#IBOutlet weak var tableView: UITableView!
let itemsPerRow: CGFloat = 1
let sectionInsets = UIEdgeInsets(top: 0.0, left: 0.0, bottom: 0.0, right: 0.0)
override func viewDidLoad() {
super.viewDidLoad()
}
}
extension ViewController:UICollectionViewDataSource,UICollectionViewDelegate {
//1
func numberOfSections(in collectionView: UICollectionView) -> Int {
return 1
}
//2
func collectionView(_ collectionView: UICollectionView,
numberOfItemsInSection section: Int) -> Int {
return 3
}
//3
func collectionView(_ collectionView: UICollectionView,
cellForItemAt indexPath: IndexPath) -> UICollectionViewCell {
let cell:cellCollectionCollectionViewCell! = collectionView.dequeueReusableCell(withReuseIdentifier: "cellSwipe",
for: indexPath) as! cellCollectionCollectionViewCell
switch indexPath.item {
case 0:
cell.backgroundColor = UIColor.black
cell.setupCollectionTableCell(indexPath)
break
case 1: cell.backgroundColor = UIColor.red
cell.setupCollectionTableCell(indexPath)
break
default:
cell.backgroundColor = UIColor.yellow
cell.setupCollectionTableCell(indexPath)
break
}
// Configure the cell
return cell
}
}
extension ViewController : UICollectionViewDelegateFlowLayout {
//1
func collectionView(_ collectionView: UICollectionView,
layout collectionViewLayout: UICollectionViewLayout,
sizeForItemAt indexPath: IndexPath) -> CGSize {
//2
let paddingSpace = sectionInsets.left * (itemsPerRow + 1)
let availableWidth = self.collectionMain.frame.width - paddingSpace
let widthPerItem = availableWidth / itemsPerRow
return CGSize(width: widthPerItem, height: widthPerItem)
}
//3
func collectionView(_ collectionView: UICollectionView,
layout collectionViewLayout: UICollectionViewLayout,
insetForSectionAt section: Int) -> UIEdgeInsets {
return sectionInsets
}
// 4
func collectionView(_ collectionView: UICollectionView,
layout collectionViewLayout: UICollectionViewLayout,
minimumLineSpacingForSectionAt section: Int) -> CGFloat {
return sectionInsets.left
}
}
Model Constant class
import UIKit
class Constant {
static let totalItem: CGFloat = 9
static let column: CGFloat = 3
static let minLineSpacing: CGFloat = 1.0
static let minItemSpacing: CGFloat = 1.0
static let offset: CGFloat = 1.0 // TODO: for each side, define its offset
static func getItemWidth(boundWidth: CGFloat) -> CGFloat {
let totalWidth = boundWidth - (offset + offset) - ((column - 1) * minItemSpacing)
return totalWidth / column
}
}
Table Cell Class
import UIKit
class CollectionCell: UITableViewCell {
#IBOutlet weak var collectionView: UICollectionView!
override func awakeFromNib() {
super.awakeFromNib()
if let layout = collectionView.collectionViewLayout as? UICollectionViewFlowLayout {
layout.sectionInset = UIEdgeInsetsMake(
Constant.offset, // top
Constant.offset, // left
Constant.offset, // bottom
Constant.offset // right
)
layout.minimumInteritemSpacing = Constant.minItemSpacing
layout.minimumLineSpacing = Constant.minLineSpacing
}
collectionView.isScrollEnabled = false
collectionView.dataSource = self
collectionView.delegate = self
}
}
extension CollectionCell: UICollectionViewDataSource {
func collectionView(_ collectionView: UICollectionView, numberOfItemsInSection section: Int) -> Int {
return Int(Constant.totalItem)
}
func collectionView(_ collectionView: UICollectionView, cellForItemAt indexPath: IndexPath) -> UICollectionViewCell {
let cell = collectionView.dequeueReusableCell(withReuseIdentifier: "BoxCell", for: indexPath)
return cell
}
}
extension CollectionCell: UICollectionViewDelegateFlowLayout {
func collectionView(_ collectionView: UICollectionView, layout collectionViewLayout: UICollectionViewLayout, sizeForItemAt indexPath: IndexPath) -> CGSize {
let itemWidth = Constant.getItemWidth(boundWidth: collectionView.bounds.size.width)
return CGSize(width: itemWidth, height: 50)
}
}
Main CollectionCell class
import UIKit
class cellCollectionCollectionViewCell: UICollectionViewCell {
#IBOutlet weak var tblView: UITableView!
var indexPath:IndexPath?
func setupCollectionTableCell(_ row:IndexPath){
self.indexPath = row
self.tblView.delegate = self
self.tblView.dataSource = self
// self.tblView.estimatedRowHeight = 300
self.tblView.reloadData()
}
}
extension cellCollectionCollectionViewCell:UITableViewDelegate,UITableViewDataSource{
func tableView(_ tableView: UITableView, heightForRowAt indexPath: IndexPath) -> CGFloat {
switch indexPath.row {
case 0:
return 50
case 1:
let itemHeight = Constant.getItemWidth(boundWidth: tableView.bounds.size.width)
let totalRow = ceil(Constant.totalItem / Constant.column)
let totalTopBottomOffset = Constant.offset + Constant.offset
let totalSpacing = CGFloat(totalRow - 1) * Constant.minLineSpacing
let totalHeight = ((itemHeight * CGFloat(totalRow)) + totalTopBottomOffset + totalSpacing)
print("total height \(totalHeight)")
return totalHeight
default:
return UITableViewAutomaticDimension
}
}
func tableView(_ tableView: UITableView, numberOfRowsInSection section: Int) -> Int {
return 2
}
func tableView(_ tableView: UITableView, cellForRowAt indexPath: IndexPath) -> UITableViewCell {
// switch indexPath.row {
// case 0:
// let cell = tableView.dequeueReusableCell(withIdentifier: "HeaderCell", for: indexPath)
// return cell
// default:
// let cell = tableView.dequeueReusableCell(withIdentifier: "CollectionCell", for: indexPath) as! CollectionCell
// return cell
// }
let cell = tableView.dequeueReusableCell(withIdentifier: "CollectionCell", for: indexPath) as! CollectionCell
return cell
}
When I set height of Main Collection view 200
Bellow are the link of images
When I set height 300, working fine