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()
}
}
Related
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)")
}
}
I have an ImageView inside of a ScrollView.
Each time the user clicks on a point on the image a pin is set and the coordinates are printed out.
However, I'm trying to store multiple coordinates inside of an array.
The first 3 times the user clicks on the image, I need the coordinates to store inside refs1. The next 14-20 times inside spots1.
// MARK: - Outlets
#IBOutlet weak var scrollView: UIScrollView!
#IBOutlet weak var sharkImage: UIImageView!
// MARK: - Properties
var refs1 :[Double] = []
var spots1 :[Double] = []
// MARK: - View Did Load
override func viewDidLoad() {
super.viewDidLoad()
scrollView.minimumZoomScale = 1.0
scrollView.maximumZoomScale = 6.0
scrollView.delegate = self
let tapGestureRecognizer = UITapGestureRecognizer(target: self, action: #selector(tapAction))
self.sharkImage.isUserInteractionEnabled = true
self.sharkImage.addGestureRecognizer(tapGestureRecognizer)
}
// MARK: - Scroll View
func viewForZooming(in scrollView: UIScrollView) -> UIView? {
return sharkImage
}
// MARK: - Functions
func tapAction(sender: UITapGestureRecognizer) {
// Get points for the UIImageView
let touchPoint = sender.location(in: self.sharkImage)
print(touchPoint)
// Add pin to tap
let pin = UIImageView(frame: CGRect(x: touchPoint.x - 5, y: touchPoint.y - 5, width:10, height:10))
pin.image = UIImage(named: "photo-pin-red")
sharkImage.addSubview(pin)
}
Well first of all you could store the coordinates in a 2D array if you want to:
var refs1 :[[Double]] = []
var spots1 :[[Double]] = []
Then store a global variable called counter to keep track of the click count:
var counter = 0
And then in your tapAction do the following (see comments for descriptions):
func tapAction(sender: UITapGestureRecognizer) {
// increase counter with +1 for each click
counter += 1
if counter <= 3 { // first 3
refs1.append([Double(touchPoint.x), Double(touchPoint.y)])
} else if counter <= 23 { // next 14 - 20 clicks
counter = 0 // reset counter to start over again
spots1.append([Double(touchPoint.x), Double(touchPoint.y)])
}
}
Use a counter variable:
var count = 0
func tapAction(sender: UITapGestureRecognizer) {
count = conut + 1
// Check for count
if (count >= 14) {
// Do stuff
}
// Get points for the UIImageView
let touchPoint = sender.location(in: self.sharkImage)
print(touchPoint)
// Add pin to tap
let pin = UIImageView(frame: CGRect(x: touchPoint.x - 5, y: touchPoint.y - 5, width:10, height:10))
pin.image = UIImage(named: "photo-pin-red")
sharkImage.addSubview(pin)
}
Why my current page in Page Control does not show correct output?
Page 1 and Page 2 display in one dot? Images here:
http://i.stack.imgur.com/498ap.png, http://i.stack.imgur.com/41kdg.png
Last page is page 6 display in dot 5th, doesn't last dot? Image: http://i.stack.imgur.com/NP9u1.png
My code here:
#IBOutlet weak var scrollView: UIScrollView!
#IBOutlet weak var pageControl: UIPageControl!
let totalPages = 6
let sampleBGColors: Array<UIColor> = [UIColor.redColor(), UIColor.yellowColor(), UIColor.greenColor(), UIColor.magentaColor(), UIColor.orangeColor(), UIColor.lightGrayColor()] #IBOutlet weak var scrollView: UIScrollView!
override func viewDidAppear(animated: Bool) {
super.viewDidAppear(animated)
configureScrollView()
configurePageControl()
}
func configureScrollView() {
// Enable paging.
scrollView.pagingEnabled = true
// Set the following flag values.
scrollView.showsHorizontalScrollIndicator = false
scrollView.showsVerticalScrollIndicator = false
scrollView.scrollsToTop = false
// Set the scrollview content size.
scrollView.contentSize = CGSizeMake(scrollView.frame.size.width * CGFloat(totalPages), scrollView.frame.size.height)
// Set self as the delegate of the scrollview.
scrollView.delegate = self
// Load the TestView view from the TestView.xib file and configure it properly.
for i in 0 ..< totalPages {
// Load the TestView view.
let testView = NSBundle.mainBundle().loadNibNamed("TestView", owner: self, options: nil)[0] as! UIView
// Set its frame and the background color.
testView.frame = CGRectMake(CGFloat(i) * scrollView.frame.size.width, scrollView.frame.origin.y, scrollView.frame.size.width, scrollView.frame.size.height)
testView.backgroundColor = sampleBGColors[i]
// Set the proper message to the test view's label.
let label = testView.viewWithTag(1) as! UILabel
label.text = "Page #\(i + 1)"
// Add the test view as a subview to the scrollview.
scrollView.addSubview(testView)
}
}
func configurePageControl() {
// Set the total pages to the page control.
pageControl.numberOfPages = totalPages
// Set the initial page.
pageControl.currentPage = 0
}
// MARK: UIScrollViewDelegate method implementation
func scrollViewDidScroll(scrollView: UIScrollView) {
// Calculate the new page index depending on the content offset.
let currentPage = floor(scrollView.contentOffset.x / UIScreen.mainScreen().bounds.size.width);
// Set the new page index to the page control.
pageControl.currentPage = Int(currentPage)
}
// MARK: IBAction method implementation
#IBAction func changePage(sender: AnyObject) {
// Calculate the frame that should scroll to based on the page control current page.
var newFrame = scrollView.frame
newFrame.origin.x = newFrame.size.width * CGFloat(pageControl.currentPage)
scrollView.scrollRectToVisible(newFrame, animated: true)
}
Please help me! Thank you.
Sorry for my English is bad.
Change the pageControl.currentPage in UIScrollViewDelegate's implemention scrollViewDidEndScrollingAnimation and scrollViewDidEndDecelerating, and I improved the calculation with scrollView's width, not screen's width:
// MARK: UIScrollViewDelegate method implementation
func scrollViewDidEndScrollingAnimation(scrollView: UIScrollView) {
// Calculate the new page index depending on the content offset.
let currentPage = floor(scrollView.contentOffset.x / scrollView.bounds.size.width)
// Set the new page index to the page control.
pageControl.currentPage = Int(currentPage)
}
func scrollViewDidEndDecelerating(scrollView: UIScrollView){
scrollViewDidEndScrollingAnimation(scrollView)
}
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