am trying to get this in my UITableViewCell
an imageView which can hold an array of Images and can be scrollable
so i tried this :
class MostWantedImageView: UIImageView , UIScrollViewDelegate{
var pageImages:[UIImage] = [UIImage]()
var pageViews:[UIImageView?] = [UIImageView]()
var scrollView:UIScrollView = UIScrollView()
var pageControl:UIPageControl = UIPageControl()
var viewingPage = -1
func loadVisiblePages() {
// First, determine which page is currently visible
let pageWidth:CGFloat = self.frame.size.width;
let page = Int(floor((self.scrollView.contentOffset.x * 2.0 + pageWidth) / (pageWidth * 2.0)));
/*
Check that page have changed,
in case that user drag left in first page, or drag right in last page
a 'scrollViewDidEndDecelerating' is fired
*/
if viewingPage != page {
// Update the page control
self.pageControl.currentPage = page;
// Work out which pages we want to load
let firstPage = page - 1;
let lastPage = page + 1;
// Purge anything before the first page
for (var i=0; i<firstPage; i += 1) {
self.purgePage(i)
}
for (var i=firstPage; i<=lastPage; i += 1) {
self.loadPage(i)
}
for (var i = lastPage+1 ; i < self.pageImages.count ; i += 1) {
self.purgePage(i)
}
viewingPage = page
}
}
func loadPage(page:Int) {
if page < 0 || page >= self.pageImages.count {
// If it's outside the range of what we have to display, then do nothing
return;
}
// Load an individual page, first seeing if we've already loaded it
let pageView:UIImageView? = self.pageViews[page];
if pageView == nil {
var frame:CGRect = self.bounds;
//frame.origin.x = frame.size.width * CGFloat(page)
frame.origin.x = 320.0 * CGFloat(page)
frame.origin.y = 0.0
var newPageView:UIImageView = UIImageView(image: self.pageImages[page])
newPageView.contentMode = UIViewContentMode.ScaleAspectFit;
newPageView.frame = frame;
self.scrollView.addSubview(newPageView)
self.pageViews[page] = newPageView
}
}
func purgePage(page:Int) {
if page < 0 || page >= self.pageImages.count {
// If it's outside the range of what we have to display, then do nothing
return;
}
// Remove a page from the scroll view and reset the container array
let pageView:UIView? = self.pageViews[page];
if pageView != nil {
pageView?.removeFromSuperview()
self.pageViews[page] = nil
}
}
override init(frame: CGRect ) {
super.init(frame: frame )
self.backgroundColor = UIColor.blueColor()
// Set up the image we want to scroll & zoom and add it to the scroll view
self.pageImages.append(UIImage(named: "event1")!)
self.pageImages.append(UIImage(named: "event2")!)
self.pageImages.append(UIImage(named: "event3")!)
let pageCount = self.pageImages.count
self.scrollView.pagingEnabled = true
self.scrollView.delegate = self
self.scrollView.showsHorizontalScrollIndicator = false
self.scrollView.showsVerticalScrollIndicator = false
// Set up the page control
self.pageControl.currentPage = 0;
self.pageControl.numberOfPages = pageCount;
self.pageControl.frame = self.frame
self.scrollView.frame = self.frame
self.pageControl.translatesAutoresizingMaskIntoConstraints = false
self.scrollView.translatesAutoresizingMaskIntoConstraints = false
self.addSubview(self.pageControl)
self.addSubview(self.scrollView)
self.userInteractionEnabled = true
//Set layout
var viewsDict = Dictionary <String, UIView>()
viewsDict["control"] = self.pageControl;
viewsDict["scrollView"] = self.scrollView;
self.addConstraints(NSLayoutConstraint.constraintsWithVisualFormat("H:|-0-[scrollView]-0-|", options: NSLayoutFormatOptions(rawValue: 0), metrics: nil, views: viewsDict))
self.addConstraints(NSLayoutConstraint.constraintsWithVisualFormat("H:|-0-[control]-0-|", options: NSLayoutFormatOptions(rawValue: 0), metrics: nil, views: viewsDict))
self.addConstraints(NSLayoutConstraint.constraintsWithVisualFormat("V:|-0-[scrollView(400)]-[control]-0-|", options: NSLayoutFormatOptions(rawValue: 0), metrics: nil, views: viewsDict))
// Set up the array to hold the views for each page
for (var i = 0; i < pageCount; ++i) {
self.pageViews.append(nil)
}
// Set up the content size of the scroll view
let pagesScrollViewSize:CGSize = self.scrollView.frame.size;
self.scrollView.contentSize = CGSizeMake(pagesScrollViewSize.width * CGFloat(self.pageImages.count), pagesScrollViewSize.height);
// Load the initial set of pages that are on screen
self.loadVisiblePages()
}
required init?(coder aDecoder: NSCoder) {
fatalError("init(coder:) has not been implemented")
}
init() {
super.init(frame: CGRect(x: 0, y: 0, width: 100, height: 100))
}
func scrollViewDidEndDecelerating(scrollView: UIScrollView!) {
self.loadVisiblePages()
}
func ResizeImage(image: UIImage, targetSize: CGSize) -> UIImage {
let size = image.size
let widthRatio = targetSize.width / image.size.width
let heightRatio = targetSize.height / image.size.height
// Figure out what our orientation is, and use that to form the rectangle
var newSize: CGSize
if(widthRatio > heightRatio) {
newSize = CGSizeMake(size.width * heightRatio, size.height * heightRatio)
} else {
newSize = CGSizeMake(size.width * widthRatio, size.height * widthRatio)
}
// This is the rect that we've calculated out and this is what is actually used below
let rect = CGRectMake(0, 0, newSize.width, newSize.height)
// Actually do the resizing to the rect using the ImageContext stuff
//UIGraphicsBeginImageContextWithOptions(newSize, false, 1.0)
UIGraphicsBeginImageContextWithOptions(newSize, false, 0.0)
image.drawInRect(rect)
let newImage = UIGraphicsGetImageFromCurrentImageContext()
UIGraphicsEndImageContext()
return newImage
}
}
its a ImageView where i putted scrollView and UIPageControll i can use this in my ViewController but have no idea how to use this in my TableViewCell , if somebody can give me some guidance in this then it'll be helpful for me
Please use a CollectionView instead. As the number of images will grow, your app will have performance issues.
You need to take a look at this-
putting-a-uicollectionview-in-a-uitableviewcell-in-swift
This will help you understand how to use collectionView inside a table cell.
Related
I am using webRTC for video calling. Everything is running smooth but
I am struggling with aspect ratio of Remote video on iPhoneX, XSMax. I am seeing lot of zoom in video. Can you please help me out how I can manage remote video on devices that have notch. Below is the code where I am handling remote size.
func videoView(_ videoView: RTCEAGLVideoView, didChangeVideoSize size: CGSize) {
print(size)
let defaultAspectRatio: CGSize = CGSize(width: 4, height: 3)
let aspectRatio: CGSize = size.equalTo(CGSize.zero) ? defaultAspectRatio : size
let videoRect: CGRect = self.view.bounds
let maxFloat = CGFloat.maximum(self.view.frame.width, self.view.frame.height)
let newAspectRatio = aspectRatio.width / aspectRatio.height
var frame = CGRect(x: 0, y: 0, width: self.view.frame.width, height: self.view.frame.height)
if (aspectRatio.width < aspectRatio.height) {
frame.size.width = maxFloat;
frame.size.height = frame.size.width / newAspectRatio;
} else {
frame.size.height = maxFloat;
frame.size.width = frame.size.height * newAspectRatio;
}
frame.origin.x = (self.view.frame.width - frame.size.width) / 2
frame.origin.y = (self.view.frame.height - frame.size.height) / 2
self.remoteView.frame = frame
}
According to #Eysner's answer, what is work for me, the final code (written using swift 5):
import UIKit
import WebRTC
final class WebRTCView: UIView, RTCVideoViewDelegate {
let videoView = RTCEAGLVideoView(frame: .zero)
var videoSize = CGSize.zero
override init(frame: CGRect) {
super.init(frame: frame)
videoView.delegate = self
addSubview(videoView)
}
required init?(coder: NSCoder) {
super.init(coder: coder)
videoView.delegate = self
addSubview(videoView)
}
func videoView(_ videoView: RTCVideoRenderer, didChangeVideoSize size: CGSize) {
self.videoSize = size
setNeedsLayout()
}
override func layoutSubviews() {
super.layoutSubviews()
guard videoSize.width > 0 && videoSize.height > 0 else {
videoView.frame = bounds
return
}
var videoFrame = AVMakeRect(aspectRatio: videoSize, insideRect: bounds)
let scale = videoFrame.size.aspectFitScale(in: bounds.size)
videoFrame.size.width = videoFrame.size.width * CGFloat(scale)
videoFrame.size.height = videoFrame.size.height * CGFloat(scale)
videoView.frame = videoFrame
videoView.center = CGPoint(x: bounds.midX, y: bounds.midY)
}
}
extension CGSize {
func aspectFitScale(in container: CGSize) -> CGFloat {
if height <= container.height && width > container.width {
return container.width / width
}
if height > container.height && width > container.width {
return min(container.width / width, container.height / height)
}
if height > container.height && width <= container.width {
return container.height / height
}
if height <= container.height && width <= container.width {
return min(container.width / width, container.height / height)
}
return 1.0
}
}
There is aspectFitScale function, it is simply to describe logic, you can refactor it if you want to.
I'm using this approach in the demo:
https://github.com/Maxatma/Walkie-Talkie/
You can make some class with show video -
class SomeVideoView: UIView, RTCVideoViewDelegate {
let videoView = RTCEAGLVideoView(frame: .zero)
var videoSize = CGSize.zero
With init method
override init(frame: CGRect) {
super.init(frame: frame)
videoView.delegate = self
self.addSubview(videoView)
...
Handle delegate method videoView:didChangeVideoSize like this (we don't need change frame in UI, only mark needsLayout)
func videoView(_ videoView: RTCEAGLVideoView, didChangeVideoSize size: CGSize) {
if (self.videoView == videoView) {
self.videoSize = size
}
self.setNeedsLayout()
}
And overwrite layoutSubviews method
override func layoutSubviews() {
if (self.videoSize.width > 0 && self.videoSize.height > 0) {
var videoFrame = AVMakeRect(aspectRatio: self.videoSize, insideRect: bounds)
var scale = 1.0
if (videoFrame.size.width > videoFrame.size.height) {
scale = bounds.size.height / videoFrame.size.height
} else {
scale = bounds.size.width / videoFrame.size.width
}
videoFrame.size.width = videoFrame.size.width * scale
videoFrame.size.height = videoFrame.size.height * scale
self.videoView.frame = videoFrame
self.videoView.center = CGPointMake(bounds.midX, bounds.midY)
} else {
self.videoView.frame = bounds
}
...
}
And set up SomeVideoView is full screen (this link can be help with it)
Safe Area of Xcode 9
just simple using AVMakeRect
//TODO: Default mobile
if size.width < size.height{
newSize = aspectFill(aspectRatio: size, minimumSize: UIScreen.main.bounds.size)
}else{
//Default computer
newSize = AVMakeRect(aspectRatio: size, insideRect: UIScreen.main.bounds).size
}
for sometimes user may have call from website, so i didnt make fill from it
func aspectFill(aspectRatio : CGSize, minimumSize: CGSize) -> CGSize {
let mW = minimumSize.width / aspectRatio.width;
let mH = minimumSize.height / aspectRatio.height;
var temp = minimumSize
if( mH > mW ) {
temp.width = minimumSize.height / aspectRatio.height * aspectRatio.width;
}
else if( mW > mH ) {
temp.height = minimumSize.width / aspectRatio.width * aspectRatio.height;
}
return temp;
}
Im trying to implement an infinitely paging UIScrollView based on the Advanced ScrollView Techniques from WWDC 2011. The problem that Im facing is that as I scroll the screen keeps on Jumping backwards instead of advancing forward in the array. Is there any way to create this effect. Below is the code I have implemented thus far.
import Foundation
import UIKit
class CustomScrollView:UIScrollView{
var label1:CustomLabel!
var label2:CustomLabel!
var label3:CustomLabel!
var labels:[UILabel]!
var visibleLabels:[UILabel]!
var recycledPages:Set<CustomLabel>!
var visiblePages:Set<CustomLabel>!
override init(frame: CGRect) {
super.init(frame: frame)
indicatorStyle = .white
recycledPages = Set<CustomLabel>()
visiblePages = Set<CustomLabel>()
var firstScreenPostion:CGRect = CGRect(origin: CGPoint(x: 0 * bounds.width, y: 0), size: bounds.size)
var secondeScreenPosition:CGRect = CGRect(origin: CGPoint(x: 1 * bounds.width, y: 0), size: bounds.size)
var thirdScreenPosition:CGRect = CGRect(origin: CGPoint(x: 2 * bounds.width, y: 0), size: bounds.size)
label1 = CustomLabel(frame: firstScreenPostion)
label1.backgroundColor = .red
label1.text = "1"
label2 = CustomLabel(frame: secondeScreenPosition)
label2.backgroundColor = .green
label2.text = "2"
label3 = CustomLabel(frame: thirdScreenPosition)
label3.backgroundColor = .blue
label3.text = "3"
visibleLabels = [label1,label2,label3]
labels = [label1,label2,label3]
}
required init?(coder aDecoder: NSCoder) {
fatalError("init(coder:) has not been implemented")
}
func recenterIfNecessary(){
let currentOffset = contentOffset
let contentWidth = contentSize.width
let centerOffset = (contentWidth - bounds.width)/2
let distanceFromCenter = abs(currentOffset.x - centerOffset)
if distanceFromCenter > contentWidth/4{
self.contentOffset = CGPoint(x: centerOffset, y: 0)
for label in visibleLabels{
var center = label.center
center.x += centerOffset - currentOffset.x
label.center = center
}
}
}
override func layoutSubviews() {
recenterIfNecessary()
let visibleBounds = bounds
let minimumVisibleX = bounds.minX
let maximumVisbleX = bounds.maxX
tilePages(minimumVisibleX: minimumVisibleX, toMaxX: maximumVisbleX)
// tileLabelsFromMinX(minimumVisibleX: minimumVisibleX, toMaxX: maximumVisbleX)
}
func insertLabel()->UILabel{
let recycledLabels = visibleLabels.filter { (label) -> Bool in
return label.superview == nil
}
let label = recycledLabels.last ?? UILabel(frame: bounds)
self.addSubview(label)
return label
}
func placeNewLabelOnRight(rightEdge: CGFloat)->CGFloat{
let label = self.insertLabel()
visibleLabels.append(label) // add rightmost label at the end of the array
label.frame.origin.x = rightEdge;
label.frame.origin.y = 0
label.text = labels.last?.text
return label.frame.maxX
}
func placeNewLabelOnLeft(leftEdge:CGFloat)->CGFloat{
let label = self.insertLabel()
self.visibleLabels.insert(label, at: 0) // add leftmost label at the beginning of the array
label.frame.origin.x = leftEdge - frame.size.width;
label.frame.origin.y = bounds.size.height - frame.size.height;
label.text = labels[0].text
return label.frame.minX
}
//function used in video
// func tileLabelsFromMinX(minimumVisibleX:CGFloat, toMaxX maximumVisibleX:CGFloat){
// // the upcoming tiling logic depends on there already being at least one label in the visibleLabels array, so
// // to kick off the tiling we need to make sure there's at least one label
// if (self.visibleLabels.count == 0)
// {
// self.placeNewLabelOnRight(rightEdge: minimumVisibleX);
// }
// print("visible labels.count: \(visibleLabels.count)")
//
// // add labels that are missing on right side
// // UILabel *lastLabel = [self.visibleLabels lastObject];
// var lastLabel = visibleLabels.last!
// var rightEdge = lastLabel.frame.maxX
// while (rightEdge < maximumVisibleX){
// rightEdge = self.placeNewLabelOnRight(rightEdge: rightEdge)
// }
//
// // add labels that are missing on left side
// var firstLabel = self.visibleLabels[0]
// var leftEdge = firstLabel.frame.minX
// while (leftEdge > minimumVisibleX){
// leftEdge = self.placeNewLabelOnLeft(leftEdge:leftEdge)
// }
//
// // remove labels that have fallen off right edge
// // lastLabel = [self.visibleLabels lastObject];
//
// while (lastLabel.frame.origin.x > maximumVisibleX){
// lastLabel.removeFromSuperview()
// self.visibleLabels.removeLast()
// lastLabel = self.visibleLabels.last!
// }
//
// // remove labels that have fallen off left edge
// firstLabel = self.visibleLabels[0];
// while (firstLabel.frame.maxX < minimumVisibleX){
// firstLabel.removeFromSuperview()
// self.visibleLabels.removeFirst()
// firstLabel = self.visibleLabels[0];
// }
// }
func tilePages(minimumVisibleX:CGFloat, toMaxX maximumVisibleX:CGFloat){
let visibleBounds = bounds
var firstNeededPageIndex:Int = Int(floorf(Float(minimumVisibleX/visibleBounds.width)))
var lastNeededPageIndex:Int = Int(floorf(Float((maximumVisibleX - 1)/visibleBounds.width)))
firstNeededPageIndex = max(firstNeededPageIndex, 0)
lastNeededPageIndex = min(lastNeededPageIndex, labels.count - 1)
//Recycle no-longer needed pages
for page in visiblePages{
if page.index < Int(firstNeededPageIndex) || page.index > Int(lastNeededPageIndex){
recycledPages.insert(page)
page.removeFromSuperview()
}
}
visiblePages.subtract(recycledPages)
//add missing pages
for i in firstNeededPageIndex...lastNeededPageIndex{
if !isDisplaying(pageForIndex: i){
let page:CustomLabel = dequeueRecycledPage() ?? CustomLabel()
print("index i: \(i)")
self.configurePage(page: page, forIndex: i)
self.addSubview(page)
visiblePages.insert(page)
}
}
}
func isDisplaying(pageForIndex index:Int)->Bool{
for page in visiblePages{
if page.index == index{
return true
}
}
return false
}
func configurePage(page:CustomLabel,forIndex index:Int){
page.index = index
page.text = "current index: \(index)"
let width = bounds.width
let newX:CGFloat = CGFloat(index) * width
page.backgroundColor = labels[index].backgroundColor
page.frame = CGRect(origin: CGPoint(x: newX, y: 0), size: bounds.size)
}
func dequeueRecycledPage()->CustomLabel?{
let page = recycledPages.first
if let page = page{
recycledPages.remove(page)
return page
}
return nil
}
}
I am setting titleView using this method
func addConstrainstToSearchField(with size: CGSize? = nil) {
var width : CGFloat = 0.0
if let searchField = self.searchfield {
var frame = searchField.frame
if size != nil, let frameWidth = size?.width {
width = frameWidth
} else if let frameWidth = self.navigationController?.navigationBar.frame.size.width {
width = frameWidth
}
frame.size.width = (width - 145.0) * 0.90 // 136 is width of (left and right BarButtonItems) button
searchField.frame = frame
self.navigationItem.titleView = searchField
// DispatchQueue.main.async(execute: {
// self.navigationItem.titleViewWithConstraint = searchField
// })
}
}
and I am calling this method from viewdidload and viewWillTransiion
but it's not showing properly
screenshot In landscape
image 2
thanks in advance
I'm facing a challenge of creating an introduction view, something like the "Cleanio" app (https://itunes.apple.com/fr/app/cleanio-pressing-la-demande/id885856031?mt=8).
Here is how it looks like:
So, the background and the overlay are moving independently and not in the same speed.
Does anyone have a start point how to realize that?
Yep.
What you need is two UIScrollViews. These should both be subviews of the main view (not contained in each other.
The bottom one has your image in it and the top one has the content.
Call them imageScrollView and contentScrollView.
Become the delegate of contentScrollView.
The contents will look something like this...
contents: [---page 1---][---page 2---][---page 3---][---page 4---]
image: [------------the image------------]
screen: [---screen---]
Key is that image is smaller than all the pages and bigger than the screen.
The frames of the scrollviews are the same width as the screen. This diagram is just to show the content widths not the frame widths.
So, the screen stays where it is and the two scroll views move over it.
Now the parallax part...
- (CGFloat)maxOffsetForScrollView:(UIScrollView *)scrollView
{
CGFloat contentWidth = scrollView.contentSize.width;
CGFloat frameWidth = CGRectGetWidth(scrollView.frame);
return contentWidth - frameWidth;
}
- (void)scrollViewDidScroll:(UIScrollView *)scrollView
{
// this is the delegate method for the content scroll view.
// I'm only doing horizontal stuff here, you can do vertical too if you want
CGFloat maximumContentOffset = [self maximumOffsetForScrollView:self.contentScrollView];
CGFloat currentOffset = self.contentScrollView.contentOffset.x;
CGFloat percentageOffset = currentOffset/maximumContentOffset;
CGFloat maximumImageOffset = [self maximumContentOffsetForScrollView:self.imageScrollView];
CGFloat actualImageOffset = maximumImageOffset * percentageOffset;
[self.imageScrollView setContentOffset:CGPointMake(actualImageOffset, 0)];
}
This takes the percentage offset from the content view and offsets the image view by the same percentage offset.
The result is a parallax effect. You can make it faster or slower by changing the relative sizes of the image and the content. More pages (or smaller image) = slower parallax.
I had been struggling with this parallax effect for a little while. I wouldn't have done it without #Fogmeister instructions, though I still had to figure out a couple of things by myself.
Anyway, here is a Swift 2.0 version, (hopefully a bit more complete):
import UIKit
class ViewController: UIViewController, UIScrollViewDelegate {
var backgroundScrollView: UIScrollView!
var contentScrollView: UIScrollView!
var imageView: UIImageView!
var contentView: UIView!
var maxContentOffset: CGFloat!
var maxBackgroundOffset: CGFloat!
var cvbw: CGFloat!
var page: Int = 1
override func viewDidLoad() {
super.viewDidLoad()
self.createBackground()
self.createContent()
}
func createBackground() {
self.imageView = UIImageView(image: UIImage(named: "ParalaxMaterial.jpg")) //ParalaxMaterial.jpg is of size: 2500 x 2668px
self.imageView.frame = CGRectMake(0, 0, ((self.view.bounds.height/2668) * 2500), self.view.bounds.height)
self.backgroundScrollView = UIScrollView(frame: view.bounds)
self.backgroundScrollView.backgroundColor = UIColor.redColor()
self.backgroundScrollView.contentSize = imageView.bounds.size
self.backgroundScrollView.addSubview(self.imageView)
self.view.addSubview(self.backgroundScrollView)
self.maxBackgroundOffset = self.maxOffsetForScrollView(self.backgroundScrollView)
}
func createContent() {
self.contentView = UIView(frame: CGRectMake(0, 0, (self.view.bounds.width * 3), self.view.bounds.height))
self.contentScrollView = UIScrollView(frame: view.bounds)
self.contentScrollView.backgroundColor = UIColor.clearColor()
self.contentScrollView.contentSize = self.contentView.bounds.size
self.contentScrollView.delegate = self
let firstButton = UIButton()
firstButton.frame = CGRectMake(((self.contentView.bounds.width / 6) - 150), 300, 300, 100)
firstButton.setTitle("START", forState: UIControlState.Normal)
firstButton.titleLabel?.font = UIFont(name: "Arial", size: 18)
firstButton.addTarget(self, action: "firstAction:", forControlEvents: UIControlEvents.TouchUpInside)
self.contentView.addSubview(firstButton)
let firstLabel = UILabel()
firstLabel.frame = CGRectMake(((self.contentView.bounds.width / 6) - 100), 0, 200, 200)
firstLabel.text = "#BrusselsLockDown"
firstLabel.textAlignment = NSTextAlignment.Center
self.contentView.addSubview(firstLabel)
let secondLabel = UILabel()
secondLabel.frame = CGRectMake(((self.contentView.bounds.width / 2) - 100), 0, 200, 200)
secondLabel.text = "#LolCats"
secondLabel.textAlignment = NSTextAlignment.Center
self.contentView.addSubview(secondLabel)
let thirdLabel = UILabel()
thirdLabel.frame = CGRectMake((((self.contentView.bounds.width / 6) * 5) - 100), 0, 200, 200)
thirdLabel.text = "#Final"
thirdLabel.textAlignment = NSTextAlignment.Center
self.contentView.addSubview(thirdLabel)
self.contentScrollView.addSubview(self.contentView)
self.view.addSubview(self.contentScrollView)
self.maxContentOffset = self.maxOffsetForScrollView(self.contentScrollView)
self.cvbw = self.contentView.bounds.width
}
func scrollViewWillBeginDecelerating(scrollView: UIScrollView) {
if self.page == 1 {
if scrollView.contentOffset.x > 0 {
scrollView.setContentOffset(CGPointMake((self.cvbw / 3), 0), animated: true)
}
} else if self.page == 2 {
if scrollView.contentOffset.x < (self.cvbw * 4/12) {
scrollView.setContentOffset(CGPointMake(0, 0), animated: true)
} else if scrollView.contentOffset.x > (self.cvbw * 4/12) {
scrollView.setContentOffset(CGPointMake(((self.cvbw / 3) * 2), 0), animated: true)
}
} else if self.page == 3 {
if scrollView.contentOffset.x < (self.cvbw * 8/12) {
scrollView.setContentOffset(CGPointMake((self.cvbw / 3), 0), animated: true)
}
} else {
print("self.page messed up")
}
}
func scrollViewDidScroll(scrollView: UIScrollView) {
if scrollView == self.contentScrollView {
let percentageOffset: CGFloat = self.contentScrollView.contentOffset.x / self.maxContentOffset
let currentBackgroundOffsetPoint: CGPoint = CGPointMake(((self.maxBackgroundOffset * percentageOffset) + 50), 0) self.backgroundScrollView.setContentOffset(currentBackgroundOffsetPoint, animated: false)
}
if self.contentScrollView.contentOffset.x == 0 {
print("page 1")
self.page = 1
} else if self.contentScrollView.contentOffset.x == 320 {
print("page 2")
self.page = 2
} else if self.contentScrollView.contentOffset.x == 640 {
print("page 3")
self.page = 3
}
}
func maxOffsetForScrollView(scrollView: UIScrollView) -> CGFloat {
let contentWidth: CGFloat = scrollView.contentSize.width - 100
let frameWidth: CGFloat = CGRectGetWidth(scrollView.frame)
return contentWidth - frameWidth
}
func firstAction (sender: UIButton) {
print("firstAction")
self.contentScrollView.setContentOffset(CGPointMake((self.cvbw / 3), 0), animated: true)
}
}
i am trying to make an imageViewer using this toturial
this toturial
i want to use the "PagedScrollViewController" example and make it using swift,
i am able to display images on screen, but i have issues with the scroll.
the scroll is not stoping between pages/photos, it scrolling freely, so that way loadVisiblePages is always called each pixel that i scroll.
probably i am missing something, can you help me with this please?
here is what i am doing :
thank you
import UIKit
class PagedScrollViewController:UIViewController,UIScrollViewDelegate {
var pageImages:[UIImage] = [UIImage]()
var pageViews:[UIView?] = [UIView]()
var scrollView:UIScrollView = UIScrollView()
var pageControl:UIPageControl = UIPageControl()
func loadVisiblePages() {
// First, determine which page is currently visible
var pageWidth:CGFloat = self.scrollView.frame.size.width;
var page = Int(floor((self.scrollView.contentOffset.x * 2.0 + pageWidth) / (pageWidth * 2.0)));
// Update the page control
self.pageControl.currentPage = page;
// Work out which pages we want to load
var firstPage = page - 1;
var lastPage = page + 1;
// Purge anything before the first page
for (var i=0; i<firstPage; i++) {
println("1) purge index \(i)")
self.purgePage(i)
}
for (var i=firstPage; i<=lastPage; i++) {
println("2) load index \(i)")
self.loadPage(i)
}
for (var i = lastPage+1 ; i < self.pageImages.count ; i++) {
println("3) purge index \(i)")
self.purgePage(i)
}
}
//
func loadPage(page:Int) {
if page < 0 || page >= self.pageImages.count {
// If it's outside the range of what we have to display, then do nothing
return;
}
// Load an individual page, first seeing if we've already loaded it
var pageView:UIView? = self.pageViews[page];
if pageView == nil {
var frame:CGRect = self.scrollView.bounds;
//frame.origin.x = frame.size.width * CGFloat(page)
frame.origin.x = 320.0 * CGFloat(page)
frame.origin.y = 0.0
var newPageView:UIImageView = UIImageView(image: self.pageImages[page])
newPageView.contentMode = UIViewContentMode.ScaleAspectFit;
newPageView.frame = frame;
self.scrollView.addSubview(newPageView)
self.pageViews[page] = newPageView
}
}
func purgePage(page:Int) {
if page < 0 || page >= self.pageImages.count {
// If it's outside the range of what we have to display, then do nothing
return;
}
// Remove a page from the scroll view and reset the container array
var pageView:UIView? = self.pageViews[page];
if pageView != nil {
pageView?.removeFromSuperview()
self.pageViews[page] = UIView()//nil
}
}
override func viewDidLoad() {
super.viewDidLoad()
self.title = "Paged";
self.view.backgroundColor = UIColor.blueColor()
// Set up the image we want to scroll & zoom and add it to the scroll view
self.pageImages.append(UIImage(named: "first.png"))
self.pageImages.append(UIImage(named: "second.png"))
self.pageImages.append(UIImage(named: "first.png"))
self.pageImages.append(UIImage(named: "second.png"))
self.pageImages.append(UIImage(named: "first.png"))
var pageCount = self.pageImages.count
self.scrollView.delegate = self
//self.tableView.showsHorizontalScrollIndicator = false
//self.tableView.showsVerticalScrollIndicator = false
// Set up the page control
self.pageControl.currentPage = 0;
self.pageControl.numberOfPages = pageCount;
self.pageControl.setTranslatesAutoresizingMaskIntoConstraints(false)
self.scrollView.setTranslatesAutoresizingMaskIntoConstraints(false)
self.view.addSubview(self.pageControl)
self.view.addSubview(self.scrollView)
//Set layout
var viewsDict = Dictionary <String, UIView>()
viewsDict["control"] = self.pageControl;
viewsDict["scrollView"] = self.scrollView;
self.view.addConstraints(NSLayoutConstraint.constraintsWithVisualFormat("H:|-0-[scrollView]-0-|", options: NSLayoutFormatOptions(0), metrics: nil, views: viewsDict))
self.view.addConstraints(NSLayoutConstraint.constraintsWithVisualFormat("H:|-0-[control]-0-|", options: NSLayoutFormatOptions(0), metrics: nil, views: viewsDict))
self.view.addConstraints(NSLayoutConstraint.constraintsWithVisualFormat("V:|-0-[scrollView(400)]-[control]-0-|", options: NSLayoutFormatOptions(0), metrics: nil, views: viewsDict))
// Set up the array to hold the views for each page
for (var i = 0; i < pageCount; ++i) {
self.pageViews.append(nil)
}
}
override func viewDidAppear(animated:Bool) {
super.viewDidAppear(animated)
// Set up the content size of the scroll view
var pagesScrollViewSize:CGSize = self.scrollView.frame.size;
self.scrollView.contentSize = CGSizeMake(pagesScrollViewSize.width * CGFloat(self.pageImages.count), pagesScrollViewSize.height);
// Load the initial set of pages that are on screen
self.loadVisiblePages()
}
override func didReceiveMemoryWarning() {
super.didReceiveMemoryWarning()
// self.scrollView = nil
// self.pageControl = nil
// self.pageImages = nil
// self.pageViews = nil
}
func scrollViewDidScroll(scrollView:UIScrollView ) {
// Load the pages which are now on screen
self.loadVisiblePages()
println("scrollViewDidScroll")
}
}
the problem was i didn't set the 'self.scrollView.pagingEnabled' to true. still i am now to UIKit.
any way i made some performance improvement, and the layout is call only when needed now,
hope someone will find this usfull :)
thanks to http://www.raywenderlich.com
import UIKit
class PagedScrollViewController:UIViewController,UIScrollViewDelegate {
var pageImages:[UIImage] = [UIImage]()
var pageViews:[UIView?] = [UIView]()
var scrollView:UIScrollView = UIScrollView()
var pageControl:UIPageControl = UIPageControl()
var viewingPage = -1
func loadVisiblePages() {
// First, determine which page is currently visible
var pageWidth:CGFloat = self.scrollView.frame.size.width;
var page = Int(floor((self.scrollView.contentOffset.x * 2.0 + pageWidth) / (pageWidth * 2.0)));
/*
Check that page have changed,
in case that user drag left in first page, or drag right in last page
a 'scrollViewDidEndDecelerating' is fired
*/
if viewingPage != page {
// Update the page control
self.pageControl.currentPage = page;
// Work out which pages we want to load
var firstPage = page - 1;
var lastPage = page + 1;
// Purge anything before the first page
for (var i=0; i<firstPage; i++) {
self.purgePage(i)
}
for (var i=firstPage; i<=lastPage; i++) {
self.loadPage(i)
}
for (var i = lastPage+1 ; i < self.pageImages.count ; i++) {
self.purgePage(i)
}
viewingPage = page
}
}
func loadPage(page:Int) {
if page < 0 || page >= self.pageImages.count {
// If it's outside the range of what we have to display, then do nothing
return;
}
// Load an individual page, first seeing if we've already loaded it
var pageView:UIView? = self.pageViews[page];
if pageView == nil {
var frame:CGRect = self.scrollView.bounds;
//frame.origin.x = frame.size.width * CGFloat(page)
frame.origin.x = 320.0 * CGFloat(page)
frame.origin.y = 0.0
var newPageView:UIImageView = UIImageView(image: self.pageImages[page])
newPageView.contentMode = UIViewContentMode.ScaleAspectFit;
newPageView.frame = frame;
self.scrollView.addSubview(newPageView)
self.pageViews[page] = newPageView
}
}
func purgePage(page:Int) {
if page < 0 || page >= self.pageImages.count {
// If it's outside the range of what we have to display, then do nothing
return;
}
// Remove a page from the scroll view and reset the container array
var pageView:UIView? = self.pageViews[page];
if pageView != nil {
pageView?.removeFromSuperview()
self.pageViews[page] = nil
}
}
override func viewDidLoad() {
super.viewDidLoad()
self.title = "Image viewer";
self.view.backgroundColor = UIColor.blueColor()
// Set up the image we want to scroll & zoom and add it to the scroll view
self.pageImages.append(UIImage(named: "message_full.png"))
self.pageImages.append(UIImage(named: "heart_full"))
self.pageImages.append(UIImage(named: "star_full.png"))
self.pageImages.append(UIImage(named: "second.png"))
self.pageImages.append(UIImage(named: "first.png"))
var pageCount = self.pageImages.count
self.scrollView.pagingEnabled = true
self.scrollView.delegate = self
self.scrollView.showsHorizontalScrollIndicator = false
self.scrollView.showsVerticalScrollIndicator = false
// Set up the page control
self.pageControl.currentPage = 0;
self.pageControl.numberOfPages = pageCount;
self.pageControl.setTranslatesAutoresizingMaskIntoConstraints(false)
self.scrollView.setTranslatesAutoresizingMaskIntoConstraints(false)
self.view.addSubview(self.pageControl)
self.view.addSubview(self.scrollView)
//Set layout
var viewsDict = Dictionary <String, UIView>()
viewsDict["control"] = self.pageControl;
viewsDict["scrollView"] = self.scrollView;
self.view.addConstraints(NSLayoutConstraint.constraintsWithVisualFormat("H:|-0-[scrollView]-0-|", options: NSLayoutFormatOptions(0), metrics: nil, views: viewsDict))
self.view.addConstraints(NSLayoutConstraint.constraintsWithVisualFormat("H:|-0-[control]-0-|", options: NSLayoutFormatOptions(0), metrics: nil, views: viewsDict))
self.view.addConstraints(NSLayoutConstraint.constraintsWithVisualFormat("V:|-0-[scrollView(400)]-[control]-0-|", options: NSLayoutFormatOptions(0), metrics: nil, views: viewsDict))
// Set up the array to hold the views for each page
for (var i = 0; i < pageCount; ++i) {
self.pageViews.append(nil)
}
}
override func viewDidAppear(animated:Bool) {
super.viewDidAppear(animated)
// Set up the content size of the scroll view
var pagesScrollViewSize:CGSize = self.scrollView.frame.size;
self.scrollView.contentSize = CGSizeMake(pagesScrollViewSize.width * CGFloat(self.pageImages.count), pagesScrollViewSize.height);
// Load the initial set of pages that are on screen
self.loadVisiblePages()
}
override func didReceiveMemoryWarning() {
super.didReceiveMemoryWarning()
//TODO make cleaning
// self.scrollView = nil
// self.pageControl = nil
// self.pageImages = nil
// self.pageViews = nil
}
func scrollViewDidEndDecelerating(scrollView: UIScrollView!) {
self.loadVisiblePages()
}
}