I'm trying to create an app where the user scrolls to the bottom of the tableview more results are displayed. At present only 20 items are displayed as per the API. The API has a parameter for page which I'm trying to increment by 1 each time the user scrolls to the bottom via this in the ViewController.
When I open the app it loads me page 1, when I go to the bottom of the tableView it quickly loads me in sequence page 2, 3, 4, 5 and stops at page 5. All the other pages are not displayed anymore, only page 5 is seen.
How can I see all the pages together after scrolling down?
ViewController.swift
override func viewDidLoad() {
super.viewDidLoad()
tableView.delegate = self
tableView.dataSource = self
swiftManager.delegate = self
swiftManager.fetchUrl()
}
func scrollViewDidScroll(_ scrollView: UIScrollView) {
let offsetY = scrollView.contentOffset.y
let contentHeight = scrollView.contentSize.height
if (offsetY > contentHeight - scrollView.frame.height){
swiftManager.fetchUrlLoadMore()
}
}
SwiftManager.swift
struct SwiftManager {
let baseURL = "https://api.themoviedb.org/3/movie/popular"
let apiKey = "xxxxxxxxxxxxx"
let filterURL1 = "language=en-US"
let filterURL2 = "sort_by=popularity.desc"
let filterURL3 = "page="
var filterPage = 1
func fetchUrl() {
let urlString = "\(baseURL)?api_key=\(apiKey)&\(filterURL1)&\(filterURL2)&\(filterURL3)\(filterPage)"
performRequest(with: urlString)
print("Number page = \(filterPage)")
}
mutating func fetchUrlLoadMore() {
while (filterPage<5) {
let urlString = "\(baseURL)?api_key=\(apiKey)&\(filterURL1)&\(filterURL2)&\(filterURL3)\(filterPage)"
performRequest(with: urlString)
filterPage += 1
print("Number page = \(filterPage)")
}
}
Related
I'm getting record from server using php
As i'm getting 11 record currently so i want in starting i will show just 6 records and remaining next 5 record will show when user reached at last cell while scrolling. So this process is in working form, but the problem is while running, it working so fast that before reaching last row all records are already showing while scrolling and the activity indicator is just animating at the bottom of tableView.
I don't know what is the problem.
Also i want when user reached at last cell, activity indicator start animating while loading data .
Here is my code
import UIKit
import AlamofireImage
struct property{
let property_Id : String
let propertyTitle : String
let imageURL : String
let user_Id : String
let area : String
let bed : String
let unit : String
let bath : String
let price : String
}
class searchRecordsViewController: UIViewController, UITableViewDelegate, UITableViewDataSource,favouriteButtonTableViewCellDelegate {
var y = 6
var m = 12
#IBOutlet weak var tableView : UITableView!
var RESULT : [NSDictionary] = []
var myProperty = [property]()
var myPropertyCopy = [property]()
override func viewDidLoad() {
super.viewDidLoad()
tableView.delegate = self
tableView.dataSource = self
}
override func didReceiveMemoryWarning() {
super.didReceiveMemoryWarning()
}
//MARK: Getting dictionary data from previous controller
override func viewWillAppear(_ animated: Bool) {
super.viewWillAppear(animated)
self.navigationItem.title = "Results"
self.navigationController?.navigationBar.tintColor = UIColor.black
//MARK: Getting dictionary data from previous controller
for item in RESULT {
let propertyInfo = property(property_Id: String(item["propertyId"]! as! Int), propertyTitle: item["propertyTitle"]! as! String, imageURL: item["imagePath"]! as! String, user_Id: String(item["userId"]! as! Int), area: item["area"]! as! String, bed: item["bed"]! as! String, unit: item["unit"]! as! String, bath: item["bath"]! as! String, price: item["price"]! as! String )
myProperty.append(propertyInfo)
}
//MARK: Inserting first 6 records in Array
for i in 0 ..< 6 {
if !(myProperty.indices.contains(i)) {
break
}
myPropertyCopy.append(myProperty[i])
}
}
func downloadImage(imagePath : String, theIMAGEVIEW : UIImageView) {
let myUrl = URL(string: URL_IP+imagePath);
//MARK: AlamofireImage to download the image
theIMAGEVIEW.af_setImage(withURL: myUrl!, placeholderImage: #imageLiteral(resourceName: "addProperty"), filter: nil, progress: nil, runImageTransitionIfCached: true, completion: nil)
}
func tableView(_ tableView:UITableView, numberOfRowsInSection section:Int) -> Int
{
return myPropertyCopy.count
}
func tableView(_ tableView: UITableView, cellForRowAt indexPath: IndexPath) -> UITableViewCell
{
let cell = tableView.dequeueReusableCell(withIdentifier: "RecordCell") as! searchrecordsTableViewCell
let property = myPropertyCopy[indexPath.row]
cell.area.text = property.area+" "+property.unit
if property.bath == ""{
cell.bath.text = property.bath
}
else{
cell.bath.text = property.bath+" Baths"
}
if property.bed == ""{
cell.bed.text = property.bed
}
else{
cell.bed.text = property.bed+" Baths"
}
cell.propertyTitle.text = property.propertyTitle
cell.price.text = convertAMOUNT(price : property.price)
downloadImage(imagePath: property.imageURL, theIMAGEVIEW: cell.myImageView)
//----
cell.delegate = self
return cell
}
func tableView(_ tableView: UITableView, willDisplay cell: UITableViewCell, forRowAt indexPath: IndexPath) {
if myPropertyCopy.count != myProperty.count{
let lastRow = myPropertyCopy.count - 1
if indexPath.row == lastRow {
let spinner = UIActivityIndicatorView(activityIndicatorStyle: .gray)
spinner.startAnimating()
spinner.frame = CGRect(x: CGFloat(0), y: CGFloat(0), width: tableView.bounds.width, height: CGFloat(44))
self.tableView.tableFooterView = spinner
self.tableView.tableFooterView?.isHidden = false
moreData()
}
}
}
func moreData(){
for i in y ..< m {
if !(myProperty.indices.contains(i)) {
break
}
myPropertyCopy.append(myProperty[i])
}
y = y + 10
m = m + 10
self.tableView.reloadData()
}
}
currently my TableView looks like
See output here
Thanks in Advance.
After a long practice i have done my problem, i have just added UIScrollView delegate function for checking if the user reached at last cell then start activityIndicator for 3 seconds and then load data and that's it.
As i have just very small amount of data that's why i'm start ing UIactivityIndicator for 3 seconds before getting data.
func scrollViewDidEndDragging(_ scrollView: UIScrollView, willDecelerate decelerate: Bool) {
// UITableView only moves in one direction, y axis
let currentOffset = scrollView.contentOffset.y
let maximumOffset = scrollView.contentSize.height - scrollView.frame.size.height
if maximumOffset - currentOffset <= 10.0 {
let spinner = UIActivityIndicatorView(activityIndicatorStyle: .gray)
if myPropertyCopy.count != myProperty.count {
//print("this is the last cell")
spinner.startAnimating()
spinner.frame = CGRect(x: CGFloat(0), y: CGFloat(0), width: tableView.bounds.width, height: CGFloat(44))
spinner.hidesWhenStopped = true
self.tableView.tableFooterView = spinner
self.tableView.tableFooterView?.isHidden = false
DispatchQueue.main.asyncAfter(deadline: .now() + 3) {
//MARK: Loading more data
self.moreData()
}
}
else{
self.tableView.tableFooterView?.isHidden = true
spinner.stopAnimating()
}
}
}
I've ImageView placed inside UICollectionViewCell and a PageControl below it. Both are connected via programmatically.
However, I want auto swipe (say every 5 seconds) the images should auto swipe. If user swipe manually then too it should happen. Also, when page control reaches to last it should begin with first.
Below is code that I've used :
var offersImages: [UIImage] = [ //Array of Banners
UIImage(named: "default-banner.png")!,
UIImage(named: "default-banner.png")!,
UIImage(named: "default-banner.png")!,
UIImage(named: "default-banner.png")!,
]
override func viewDidLoad() {
super.viewDidLoad()
self.objPageControl.currentPage = 0
self.objPageControl.numberOfPages = self.offersImages.count
}
func scrollViewDidScroll(scrollView: UIScrollView) {
let pageWidth : CGFloat = self.objBannerCollectionView.frame.size.width
self.objPageControl.currentPage = Int(self.objBannerCollectionView.contentOffset.x/pageWidth)
}
How can this be done in Swift?
Refer following link , it will help to resolve your problem.
Horizontal Paging
Below code solved my problem :
//MARK:- viewDidLoad
override func viewDidLoad() {
super.viewDidLoad()
. . .
_ = NSTimer.scheduledTimerWithTimeInterval(2, target: self, selector: #selector(moveToNextPage), userInfo: nil, repeats: true)
}
func moveToNextPage (){
let pageWidth:CGFloat = self.objBannerCollectionView.frame.width
let maxWidth:CGFloat = pageWidth * 4
let contentOffset:CGFloat = self.objBannerCollectionView.contentOffset.x
var slideToX = contentOffset + pageWidth
if contentOffset + pageWidth == maxWidth {
slideToX = 0
}
self.objBannerCollectionView.scrollRectToVisible(CGRect(x:slideToX, y:0, width:pageWidth, height:self.objBannerCollectionView.frame.height), animated: true)
}
I followed this tutorial, specifically under "Paging with UIScrollView" section to create horizontal scrolling. Currently, I have it set up so that the images cover the entire frame/screen.
I am trying to add a simple UIBarButtonItem on the navigation bar (using Storyboard) in an attempt to build a slide-out menu. However, the button does not show up. Also, the navigation bar does not show up either even when I tried self.navigationController?.navigationBarHidden = false.
My current view controller is written like so.
class HomeViewController: UIViewController, UIScrollViewDelegate {
#IBOutlet weak var pagedScrollView: UIScrollView!
#IBOutlet weak var pageControl: UIPageControl!
#IBOutlet weak var hamburger: UIBarButtonItem! // the button
var pageImages: [UIImage] = []
var pageViews: [UIImageView?] = []
override func viewDidLoad() {
super.viewDidLoad()
self.navigationController?.toolbarHidden = false
hamburger.target = self.revealViewController()
hamburger.action = Selector("revealToggle:")
}
override func prefersStatusBarHidden() -> Bool {
return true
}
override func viewDidAppear(animated: Bool) {
let weatherData = WeatherDataLibrary().library
pageImages = [
UIImage(named: weatherData[0]["image"] as! String!)!,
UIImage(named: weatherData[1]["image"] as! String!)!,
UIImage(named: weatherData[2]["image"] as! String!)!,
UIImage(named: weatherData[3]["image"] as! String!)!,
UIImage(named: weatherData[4]["image"] as! String!)!,
UIImage(named: weatherData[5]["image"] as! String!)!,
]
let pageCount = weatherData.count
pageControl.currentPage = 0
pageControl.numberOfPages = pageCount
for _ in 0..<pageCount {
pageViews.append(nil)
}
let pagesScrollViewSize = pagedScrollView.frame.size
pagedScrollView.contentSize = CGSize(width: pagesScrollViewSize.width * CGFloat(pageImages.count),
height: pagesScrollViewSize.height)
loadVisiblePages()
}
func loadPage(page: Int) {
if page < 0 || page >= pageImages.count {
// If it's outside the range of what you have to display, then do nothing
return
}
// 1
if let pageView = pageViews[page] {
// Do nothing. The view is already loaded.
} else {
// 2
var frame = pagedScrollView.bounds
frame.origin.x = frame.size.width * CGFloat(page)
frame.origin.y = 0.0
// 3
let newPageView = UIImageView(image: pageImages[page])
newPageView.contentMode = .ScaleToFill
newPageView.frame = frame
pagedScrollView.addSubview(newPageView)
// 4
pageViews[page] = newPageView
}
}
func purgePage(page: Int) {
if page < 0 || page >= pageImages.count {
// If it's outside the range of what you have to display, then do nothing
return
}
// Remove a page from the scroll view and reset the container array
if let pageView = pageViews[page] {
pageView.removeFromSuperview()
pageViews[page] = nil
}
}
func loadVisiblePages() {
// First, determine which page is currently visible
let pageWidth = pagedScrollView.frame.size.width
let numberOfImages = pageImages.count
let page = Int(floor((pagedScrollView.contentOffset.x * CGFloat(numberOfImages) + pageWidth) / (pageWidth * CGFloat(numberOfImages))))
// Update the page control
pageControl.currentPage = page
// Work out which pages you want to load
let firstPage = 0
let lastPage = numberOfImages
// Purge anything before the first page
for var index = 0; index < firstPage; ++index {
purgePage(index)
}
// Load pages in our range
for index in firstPage...lastPage {
loadPage(index)
}
// Purge anything after the last page
for var index = lastPage+1; index < pageImages.count; ++index {
purgePage(index)
}
}
func scrollViewDidScroll(pagedScrollView: UIScrollView!) {
// Load the pages that are now on screen
loadVisiblePages()
}
The code looks fine. Your problem is likely in your storyboard. Maybe the navigation controller isn't properly linked to your View Controller.
Did you attached the nav controller to the VC using Editor > Embed In > Navigation Controller? From the top menu.
I'm trying to display multiple images using a UIScrollView and a page control, think screenshots of apps on the App Store. Yet for some reason, my UIScrollView is not scrolling. I checked, and UISCrollView's contentSize's width is larger than the UIScrollView's width. It might also be worth noting that I put the page control in the UIScrollView, so that it displays on top of the pictures. My code is as follows:
import UIKit
class ItemDetailViewController: UIViewController, UIScrollViewDelegate {
#IBOutlet weak var scrollView: UIScrollView!
#IBOutlet weak var pageControl: UIPageControl!
var itemSelected: Item!
var pageViews: [UIImageView?] = []
var pageCount: Int!
override func viewDidLoad() {
super.viewDidLoad()
// Do any additional setup after loading the view.
pageCount = itemSelected.images.count
pageControl.currentPage = 0
pageControl.numberOfPages = pageCount
for _ in 0..<pageCount {
pageViews.append(nil)
}
scrollView.frame.size = CGSizeMake(view.frame.width, view.frame.height/2.0)
let pageSize = scrollView.frame.size
scrollView.contentSize = CGSizeMake(pageSize.width * CGFloat(pageCount), pageSize.height)
loadVisiblePages()
scrollView.delegate = self
}
override func didReceiveMemoryWarning() {
super.didReceiveMemoryWarning()
// Dispose of any resources that can be recreated.
}
override func viewWillAppear(animated: Bool) {
super.viewWillAppear(animated)
tabBarController?.tabBar.hidden = true
}
override func viewWillDisappear(animated: Bool) {
super.viewDidDisappear(animated)
tabBarController?.tabBar.hidden = false
}
// MARK: - Helper Functions
func loadPage(page: Int){
if page < 0 || page >= pageCount {
// page outside of range, do nothing
return
}
if let pageView = pageViews[page] {
// page already loaded, do nothing
return
} else {
var frame = scrollView.bounds
frame.origin.x = frame.size.width * CGFloat(page)
frame.origin.y = 0.0
let newPageView = UIImageView(image: itemSelected.images[page])
newPageView.contentMode = .ScaleToFill
newPageView.frame = frame
scrollView.addSubview(newPageView)
pageViews[page] = newPageView
}
}
func purgePage(page: Int){
if page < 0 || page >= pageCount {
// page outside of range, do nothing
return
}
if let pageView = pageViews[page]{
pageView.removeFromSuperview()
pageViews[page] = nil
}
}
func loadVisiblePages(){
let pageWidth = scrollView.frame.size.width
let page = Int(floor(scrollView.contentOffset.x * 2.0 + pageWidth)/(2.0 * pageWidth))
pageControl.currentPage = page
let firstPage = page - 1
let lastPage = page + 1
for var index = 0; index < firstPage; index++ {
purgePage(index)
}
for index in firstPage ... lastPage {
loadPage(index)
}
for var index = lastPage + 1; index < itemSelected.images.count; index++ {
purgePage(index)
}
}
// MARK: - Scroll View Delegate Methods
func scrollViewDidScroll(scrollView: UIScrollView) {
loadVisiblePages()
}
}
What could be causing the issue?
Better use UIPageViewController is u want only show images.
u can see tutorial how do it there there
So I am pretty new to Swift still and I was wondering if anyone could help me recreate the image slideshow at the top of the iOS Appstore.
Is it a scrollview with UIImageViews or CollectionView cells?
I tried following and modifying this Ray Wenderlich tutorial but the result I got laisse à désirer as can be seen in the image below.
Instead of three images showing I only got two and none completely filled the scrollView which leads me to think it might be a problem with auto layout.
Would really appreciate all the help I can get.
Anyway here is my code:
var pageImages = [UIImage]()
var pageViews: [UIImageView?] = []
#IBOutlet weak var carousel: UIScrollView!
override func viewDidLoad() {
super.viewDidLoad()
//Setting up the image carousel
pageImages = [UIImage(named: "featured_1")!, UIImage(named: "featured_2")!, UIImage(named: "featured_3")!]
for _ in 0..<pageImages.count {
pageViews.append(nil)
}
let pagesScrollViewSize = carousel.frame.size
carousel.contentSize = CGSize(width: pagesScrollViewSize.width * CGFloat(pageImages.count),
height: pagesScrollViewSize.height)
}
func loadPage(page: Int) {
if page < 0 || page >= pageImages.count {
// If it's outside the range of what you have to display, then do nothing
return
}
// 1
if let pageView = pageViews[page] {
// Do nothing. The view is already loaded.
} else {
// 2
var frame = carousel.bounds
frame.origin.x = frame.size.width * CGFloat(page)
frame.origin.y = 0.0
// 3
let imageView = UIImageView(image: pageImages[page])
imageView.contentMode = .ScaleAspectFit
imageView.frame = frame
carousel.addSubview(imageView)
// 4
pageViews[page] = imageView
}
}
func purgePage(page: Int) {
if page < 0 || page >= pageImages.count {
// If it's outside the range of what you have to display, then do nothing
return
}
// Remove a page from the scroll view and reset the container array
if let pageView = pageViews[page] {
pageView.removeFromSuperview()
pageViews[page] = nil
}
}
func loadVisiblePages() {
// First, determine which page is currently visible
let pageWidth = carousel.frame.size.width
let page = Int(floor((carousel.contentOffset.x * 2.0 + pageWidth) / (pageWidth * 2.0)))
// Work out which pages you want to load
let firstPage = page - 1
let lastPage = page + 1
// Purge anything before the first page
for var index = 0; index < firstPage; ++index {
purgePage(index)
}
// Load pages in our range
for index in firstPage...lastPage {
loadPage(index)
}
// Purge anything after the last page
for var index = lastPage+1; index < pageImages.count; ++index {
purgePage(index)
}
}
override func scrollViewDidScroll(scrollView: UIScrollView) {
loadVisiblePages()
}
}