Crousel not working properly and showing Blank screen - ios

In image we cleraly see the crousel showing blank image but I want crousel that shows images that bot happening the array of the image are on next slide/page I have added crousel with UICollectionview give the UIcollectionview image size 300/200
it doesn't scroll manually and if we scroll it forcefully it went to first screen and show Blank imageview.
NOT showing the crousel Which contain advertisement
not Working crousel and UICollectionView
import UIKit
class AdCollectionView: UICollectionViewCell {
#IBOutlet weak var adImage: UIImageView!
}
import UIKit
class Marketplace: UIViewController {
#IBOutlet weak var adCollectionView: UICollectionView!
var Images=["scan","stethscope","pulse","Reorder","specialist","trolley"]
var timer:Timer?
var currentIndex = 0
override func viewDidLoad() {
super.viewDidLoad()
timer = Timer.scheduledTimer(timeInterval:2.0, target: self, selector: #selector(slideToNext), userInfo: nil, repeats: true)
}
#objc func slideToNext(){
if currentIndex < Images.count - 1
{
currentIndex+=currentIndex
adCollectionView.scrollToItem(at: IndexPath(item: currentIndex, section: 0), at: .right, animated: true)
}
else{
currentIndex = 0
}
}
}
extension Marketplace:UICollectionViewDelegate,UICollectionViewDataSource,UICollectionViewDelegateFlowLayout
{
func collectionView(_ collectionView: UICollectionView, numberOfItemsInSection section: Int) -> Int {
return Images.count
}
func collectionView(_ collectionView: UICollectionView, cellForItemAt indexPath: IndexPath) -> UICollectionViewCell {
let cell=adCollectionView.dequeueReusableCell(withReuseIdentifier:"AdCell", for: indexPath) as! AdCollectionView
cell.adImage.image=UIImage(named: Images[indexPath.row])
return cell
}
func collectionView(_ collectionView: UICollectionView, layout collectionViewLayout: UICollectionViewLayout, sizeForItemAt indexPath: IndexPath) -> CGSize {
return CGSize(width: adCollectionView.frame.width, height: adCollectionView.frame.height)
}
}

Related

Start playling Lottie once collection view is changed

I have problem with lottie animations, I have some kind of onboarding on my app and what I would like to achive is to everytime view in collectionview is changed, to start my animation, I have 4 pages and 4 different lottie animations. Currently if I call animation.play() function, once app is started, all of my animations are played at the same time, so once I get to my last page, animation is over. And I want my lottie to be played only once, when view is shown.
This is my cell
class IntroductionCollectionViewCell: UICollectionViewCell {
#IBOutlet var title: UILabel!
#IBOutlet var subtitleDescription: UILabel!
#IBOutlet var animationView: AnimationView!
override func awakeFromNib() {
super.awakeFromNib()
}
public func configure(with data: IntroInformations) {
let animation = Animation.named(data.animationName)
title.text = data.title
subtitleDescription.text = data.description
animationView.animation = animation
}
static func nib() -> UINib {
return UINib(nibName: "IntroductionCollectionViewCell", bundle: nil)
}
}
This is how my collection view is set up
extension IntroductionViewController {
func collectionView(_ collectionView: UICollectionView, layout collectionViewLayout: UICollectionViewLayout, minimumLineSpacingForSectionAt section: Int) -> CGFloat {
return 0
}
func collectionView(_ collectionView: UICollectionView, numberOfItemsInSection section: Int) -> Int {
pages.count
}
func collectionView(_ collectionView: UICollectionView, cellForItemAt indexPath: IndexPath) -> UICollectionViewCell {
let cell = collectionView.dequeueReusableCell(withReuseIdentifier: "IntroductionCollectionViewCell", for: indexPath) as! IntroductionCollectionViewCell
cell.configure(with: pages[indexPath.row])
cell.animationView.loopMode = .loop
cell.animationView.play()
return cell
}
func collectionView(_ collectionView: UICollectionView, layout collectionViewLayout: UICollectionViewLayout, sizeForItemAt indexPath: IndexPath) -> CGSize {
return CGSize(width: view.frame.width, height: view.frame.height)
}
func scrollViewDidScroll(_ scrollView: UIScrollView) {
let scrollPos = scrollView.contentOffset.x / view.frame.width
self.pageControl.currentPage = Int(floorf(Float(scrollPos)))
let n = pageControl.numberOfPages
if self.pageControl.currentPage == n - 1 {
continueButton.isHidden = false
} else {
continueButton.isHidden = true
}
}
}
Thanks in advance!!
You can use the collectionViewDelegate willDisplay and didEndDisplaying methods to start/stop the animations. And not when configuring the cell. - https://developer.apple.com/documentation/uikit/uicollectionviewdelegate
If you want the animation to run only once dont use the loop option.
if let cell = cell as? IntroductionCollectionViewCell {
cell.animationView.loopMode = .playOnce
cell.animationView.play()
}
this is the answer, I need to check is cell once is loaded my cell where lottie animation is

How to switch to the staggered collection view and to a list view with one item per row in iOS using swift?

I am showing some images in the collection view cells . As of now I am using a simple collection view which shows the items and it is currently showing two items per row . The following code is given below:
import UIKit
import MBProgressHUD
class HotViewController: BaseViewController {
// MARK: - IBOutlets
#IBOutlet var collectionView: UICollectionView!
#IBOutlet weak var filterSwitch: UISwitch!
#IBOutlet weak var toolbarHeightConstraint: NSLayoutConstraint!
#IBOutlet weak var toolbarView: UIView!
#IBOutlet weak var messageLabel: UILabel!
// MARK: - Properties
let hotViewModel = HotViewModel()
var hotPhotos = [ImageMeta]()
var filteredPhotos = [ImageMeta]()
// MARK: - ViewLifeCycle
override func viewDidLoad() {
super.viewDidLoad()
setupViewModel()
}
// MARK: - Methods
func setupViewModel() {
MBProgressHUD.showAdded(to: self.view, animated: true)
hotViewModel.getHotPhotos()
hotViewModel.getPhotoListDidSucess = { [weak self] list in
guard let strongSelf = self else {return}
strongSelf.hotPhotos = list
strongSelf.filteredPhotos = list.filter{$0.in_most_viral == true}
DispatchQueue.main.async {
MBProgressHUD.hide(for: strongSelf.view, animated: true)
strongSelf.collectionView.reloadData()
}
}
hotViewModel.getPhotoListDidFailed = { [weak self] message in
print("message \(message)")
guard let strongSelf = self else {return}
DispatchQueue.main.async {
MBProgressHUD.hide(for: strongSelf.view, animated: true)
}
}
}
// MARK: - Actions
#IBAction func switchValueDidChanged(_ sender: Any) {
self.collectionView.reloadData()
}
#IBAction func aboutButtonClicked(_ sender: UIButton) {
showPopUp()
}
}
// MARK: - CollectionViewDataSource
extension HotViewController: UICollectionViewDataSource,UICollectionViewDelegate {
func numberOfSections(in collectionView: UICollectionView) -> Int {
return 1
}
func collectionView(_ collectionView: UICollectionView, numberOfItemsInSection section: Int) -> Int {
if filterSwitch.isOn && filteredPhotos.count == 0 {
messageLabel.isHidden = false
}
else{
messageLabel.isHidden = true
}
return (filterSwitch.isOn ? filteredPhotos.count : hotPhotos.count)
}
func collectionView(_ collectionView: UICollectionView, cellForItemAt indexPath: IndexPath) -> UICollectionViewCell {
let photo = filterSwitch.isOn ? filteredPhotos[indexPath.row] : hotPhotos[indexPath.row]
let cell : PhotoListCell = collectionView.dequeueReusableCell(for: indexPath)
cell.configureCell(with: photo)
return cell
}
func collectionView(_ collectionView: UICollectionView, didSelectItemAt indexPath: IndexPath) {
let photo = filterSwitch.isOn ? filteredPhotos[indexPath.row] : hotPhotos[indexPath.row]
showDetailedPage(metaData: photo)
}
}
// MARK: - UICollectionViewDelegateFlowLayout
extension HotViewController: UICollectionViewDelegateFlowLayout {
func collectionView(_ collectionView: UICollectionView,
layout collectionViewLayout: UICollectionViewLayout,
minimumInteritemSpacingForSectionAt section: Int) -> CGFloat {
return CGFloat(interitemSpacing)
}
func collectionView(_ collectionView: UICollectionView, layout
collectionViewLayout: UICollectionViewLayout,
minimumLineSpacingForSectionAt section: Int) -> CGFloat {
return CGFloat(lineSpacing)
}
func collectionView(_ collectionView: UICollectionView, layout collectionViewLayout: UICollectionViewLayout, sizeForItemAt indexPath: IndexPath) -> CGSize {
return getItemSize()
}
}
I am getting the following result as:
So in this image you can see 1 and 2 marked in red . What I want is
A) on pressing 1 the number of items per row should become 1
instead of 2
B) on pressing 2 the cells should become staggered
instead of perfect square .
Is it possible to achieve using the same collection view ?How can I achieve it using the same collection view ?
Here is an example of staggered collection view :
How can I switch to staggered view , list and regular view on button clicks?
is it possible to add flags and when you click you just reload the collectionView.
and do all the code in the delegates of the collection view ...

Collection view auto resizing and setup repeating background

I am using collection view to load data from API. Here i want to extend size of collection view height instead of scrolling inside collection view. And also need to repeat the background image according to collection view height.
Here is the android layout and i want to develop similar to this.Tap here
import UIKit
import Nuke
import SVProgressHUD
import JSONJoy
class HomeViewController: UIViewController {
#IBOutlet weak var categoryCollection: UICollectionView!
#IBOutlet weak var tabbar: UITabBar!
var sectors:[Sector] = []
var timer = Timer()
var counter = 0
var selectedSector = ""
var selectedSectorName = ""
var webService = ApiService()
let plist = PlistHelper()
override func viewDidLoad() {
super.viewDidLoad()
self.categoryCollection.dataSource = self
self.categoryCollection.delegate = self
for item in tabbar.items ?? []{
item.image = item.image?.withRenderingMode(.alwaysOriginal)
}
UITabBarItem.appearance().setTitleTextAttributes([NSAttributedString.Key.foregroundColor: UIColor.white], for: .normal)
UITabBarItem.appearance().setTitleTextAttributes([NSAttributedString.Key.foregroundColor: UIColor.black], for: .selected)
listSectors()
self.categoryCollection.backgroundColor = UIColor(patternImage: UIImage(named: "bg")!)
}
override func viewWillAppear(_ animated: Bool) {
listbanners()
}
override func viewWillDisappear(_ animated: Bool) {
self.timer.invalidate()
}
override func prepare(for segue: UIStoryboardSegue, sender: Any?) {
if(segue.identifier == "sectors"){
let vc = segue.destination as! SectorsViewController
vc.sectorCode = selectedSector
vc.sectorName = selectedSectorName
}
}
func listSectors(){
webService.listSectors({ (sectors, message, status) in
if(status){
if let resData = sectors.arrayObject {
do{
for data in resData{
self.sectors.append(try Sector(JSONLoader(data)))
}
DispatchQueue.main.async {
self.categoryCollection.reloadData()
}
}
catch let error {
print("JSonJoyError:\(error)")
}
}
}
})
}
}
extension HomeViewController: UICollectionViewDelegate, UICollectionViewDataSource {
func collectionView(_ collectionView: UICollectionView, numberOfItemsInSection section: Int) -> Int {
if(collectionView == bannerCollection){
return banners.count
}
else {
return sectors.count
}
}
func collectionView(_ collectionView: UICollectionView, cellForItemAt indexPath: IndexPath) -> UICollectionViewCell {
let options = ImageLoadingOptions(placeholder: UIImage(named: "bannerPlaceholder"),transition: .fadeIn(duration: 0.33))
if(collectionView == bannerCollection){
let cell = collectionView.dequeueReusableCell(withReuseIdentifier: "cell", for: indexPath) as! DataCollectionViewCell
Nuke.loadImage(with: URL(string: banners[indexPath.row].ImageUrl ?? "")!, options: options, into:cell.img)
return cell
}
else{
let cell = categoryCollection.dequeueReusableCell(withReuseIdentifier: "catCell", for: indexPath) as! catogeryCollectionViewCell
Nuke.loadImage(with: URL(string: sectors[indexPath.row].ImageUrl ?? "")!, options: options, into:cell.photoImageView)
return cell
}
}
func collectionView(_ collectionView: UICollectionView, didSelectItemAt indexPath: IndexPath) {
if(collectionView == categoryCollection){
selectedSector = sectors[indexPath.row].Code ?? "FOOD"
selectedSectorName = sectors[indexPath.row].Name ?? "FOOD"
self.performSegue(withIdentifier: "sectors", sender: self)
}
}
}
extension HomeViewController: UICollectionViewDelegateFlowLayout {
func collectionView(_ collectionView: UICollectionView, layout collectionViewLayout: UICollectionViewLayout, insetForSectionAt section: Int) -> UIEdgeInsets {
return UIEdgeInsets(top: 0, left: 0, bottom: 0, right: 0)
}
func collectionView(_ collectionView: UICollectionView, layout collectionViewLayout: UICollectionViewLayout, sizeForItemAt indexPath: IndexPath) -> CGSize {
if(collectionView == bannerCollection){
let size = bannerCollection.frame.size
return CGSize(width: size.width, height: size.height - 10)
}
else{
let size = categoryCollection.frame.size
print("size\(size)")
return CGSize(width: (size.width / 2) - 8, height:120)
}
}
func collectionView(_ collectionView: UICollectionView, layout collectionViewLayout: UICollectionViewLayout, minimumLineSpacingForSectionAt section: Int) -> CGFloat {
return 30
}
func collectionView(_ collectionView: UICollectionView, layout collectionViewLayout: UICollectionViewLayout, minimumInteritemSpacingForSectionAt section: Int) -> CGFloat {
return 0.0
}
}
Following steps can help you to increase your collection View height according to data.
Create Heightconstraint outlet.
After loading data in collection view with delay of 0.2 sec in main thread,
Set Height Constraint constant = collection view content size height.

IOS Swift Thread Abort Error when Appending image to an image array

I get this error when I try to append an image to my image array in IOS swift: Thread 1:signal SIGABRT
It occurs when I call the loadImages() function:
import UIKit
class ProtectedGallery: UIViewController, UICollectionViewDataSource {
#IBOutlet weak var imageCollection: UICollectionView!
var images = [UIImage]()
override func viewDidLoad() {
super.viewDidLoad()
loadImages()
}
func loadImages()
{
images.append(UIImage(named: "image1")!)
self.imageCollection.reloadData()
}
func collectionView(_ imageCollection: UICollectionView, numberOfItemsInSection section: Int)-> Int{
return images.count
}
func collectionView(_ imageCollection: UICollectionView, cellForItemAt indexPath: IndexPath) -> UICollectionViewCell {
let cell = imageCollection.dequeueReusableCell(withReuseIdentifier: "Cell", for: indexPath) as! ImageCollectionViewCell
let image = images[indexPath.row]
cell.imageView.image = image;
return cell
}
}
Any ideas why this is the case? I have been stuck on this for a while.
I've just noticed a few things:
First, you never set the data source (or delegate) for your collection view. Do that:
class ProtectedGallery: UIViewController, UICollectionViewDataSource, UICollectionViewDelegate {
#IBOutlet weak var imageCollection: UICollectionView! {
didSet {
imageCollection.dataSource = self
imageCollection.delegate = self
}
}
}
Also, your data source method arguments are not named correctly. Change to this:
func collectionView(_ collectionView: UICollectionView, numberOfItemsInSection section: Int) -> Int {
// put your code here
}
func collectionView(_ collectionView: UICollectionView, cellForItemAt indexPath: IndexPath) -> UICollectionViewCell {
// put your code here
}

Scrolling issue with UITableViewController hosted in UICollectionViewCell

I have the following setup in my app:
UITabBarController
UINavigationController
UIViewController
The UIViewController has a UICollectionView with horizontal scrolling.
In the cells, I want to "host" a view from another ViewController. This works pretty well, but I have scrolling issues. The first UICollectionViewCell hosts a view that comes from a UITableViewController. I can scroll the UITableViewController but it does not really scroll to the end - it seems like the UITableViewController starts to bounce way too early.
When I used the UITableViewController as the Root View Controller, everything worked fine, so I don't think there is something wrong with this ViewController.
The height of the CollectionView is pretty small, I just wanted to show the "bouncing" behaviour.
Here is the code for the collectionView:
import Foundation
import UIKit
class FeedSplitViewController : UIViewController, Controllable
{
#IBOutlet weak var menuBar: MenuBar!
#IBOutlet weak var collectionView: UICollectionView!
private var currentIndex = 0
private var dragStart: CGFloat = 0.0
private var feedActivities: FeedViewController!
var controller: Controller!
override func viewDidLoad()
{
super.viewDidLoad()
self.initControls()
self.initMenuBar()
self.initCollectionView()
self.initActivitiesViewController()
}
fileprivate func initActivitiesViewController()
{
self.feedActivities = UIStoryboard.instantiate("Main", "feedActivities")
self.feedActivities.controller = self.controller
}
fileprivate func initControls()
{
self.navigationController?.navigationBar.setValue(false, forKey: "hidesShadow")
}
fileprivate func initMenuBar()
{
self.menuBar.showLine = true
self.menuBar.enlargeIndicator = true
self.menuBar.texts = [Resources.get("FEED_ACTIVITIES"), Resources.get("DASHBOARD")]
self.menuBar.selectionChanged =
{
index in
self.collectionView.scrollToItem(at: IndexPath(item: index, section: 0), at: UICollectionView.ScrollPosition.right, animated: true)
}
}
fileprivate func initCollectionView()
{
self.collectionView.register(UICollectionViewCell.self, forCellWithReuseIdentifier: "cell")
let menuBarFrame = self.menuBar.frame.origin
let collectionView = self.collectionView.frame.origin
Swift.print(menuBarFrame)
Swift.print(collectionView)
}
}
extension FeedSplitViewController : UICollectionViewDelegate, UICollectionViewDelegateFlowLayout, UICollectionViewDataSource
{
func collectionView(_ collectionView: UICollectionView, numberOfItemsInSection section: Int) -> Int
{
return 2
}
func collectionView(_ collectionView: UICollectionView, cellForItemAt indexPath: IndexPath) -> UICollectionViewCell
{
let cell = collectionView.dequeueReusableCell(withReuseIdentifier: "cell", for: indexPath)
if indexPath.item == 0, let feedActivities = self.feedActivities
{
cell.contentView.addSubview(feedActivities.view)
}
return cell
}
func collectionView(_ collectionView: UICollectionView, layout collectionViewLayout: UICollectionViewLayout, minimumLineSpacingForSectionAt section: Int) -> CGFloat
{
return 0
}
func collectionView(_ collectionView: UICollectionView, layout collectionViewLayout: UICollectionViewLayout, sizeForItemAt indexPath: IndexPath) -> CGSize
{
return CGSize(width: self.view.bounds.width, height: self.view.bounds.height)
}
func scrollViewWillBeginDragging(_ scrollView: UIScrollView)
{
self.dragStart = scrollView.contentOffset.x
}
func scrollViewDidScroll(_ scrollView: UIScrollView)
{
let oldIndex = self.currentIndex
let page = scrollView.contentOffset.x / scrollView.frame.size.width
let currentPage = Int(round(page))
if oldIndex != currentPage
{
if Settings.useHapticFeedback
{
Utilities.haptic(.medium)
}
self.menuBar.selectedIndex = currentPage
}
self.currentIndex = currentPage
}
}
I have attached a small video: https://imgur.com/a/pj7l3Hd
I solved it by doing the following:
I no longer host the view of an ViewController directly in the
Every UICollectionView cell hosts an UITableView.
The UITableViewCell contains the data model that was previously implemented in the ViewController. The logic is still outside of the UITableViewCell.

Resources