iOS Tinder/Twitter like slider paging navigation and menu - ios

I'm looking for examples/tutorials/framework explaining how to do a navigation bar/controller which slide to left and right like Tinder.app and Twitter.app
I'm not talking about the faces swiping thing of Tinder, I'm talking about the top menu and the views we can slide entirely to left or right to go smoothly to other screens of the app like profile, moments, etc
I'm looking around but not find anything really interesting until then, I hope you can point me out something.

I'm afraid that the complete solution to this is quite a bit beyond the scope of a single question.
However in the interest of trying to help you I think it's worth looking into this - That's a link to Cocoa Controls, a website which people build ready to go controls you can just drop into your app. (it's quite a cool site really).
That particular link is to MSSlidingPanelController. Which I think is exactly what you are looking for. The source code is clearly visible so you can see exactly what's required to get the effect you are looking for.
Here are a few other examples. Hope this helps.

MSSlidingPanelController is not what you are looking for. These are "drawer views", which only allows user to swipe to a certain drawer.
TwitterPagingViewer and SwiftPagingNav is exactly like the one on Twitter, only more complicated.
Tinder seems to be using a UIPageViewController with hidden dots, which is done by deleting these methods:
presentationCountForPageViewController
presentationIndexForPageViewController
Here is a good tutorial:
https://www.youtube.com/watch?v=8bltsDG2ENQ
Here is a great repo:
https://github.com/goktugyil/EZSwipeController

If you need it in Swift, I've created this one
(it also works on any screen resolution vs just iPhone 4/5/5s like the other example)
https://github.com/aubrey/SwiftPagingNav
class PageViewController: UIViewController, UIScrollViewDelegate {
var scrollView:UIScrollView!
var pageControl:UIPageControl!
var navbarView:UIView!
var navTitleLabel1:UILabel!
var navTitleLabel2:UILabel!
var navTitleLabel3:UILabel!
var view1:UIView!
var view2:UIView!
var view3:UIView!
override func viewDidLoad() {
super.viewDidLoad()
self.view.backgroundColor = UIColor.lightGrayColor()
//Creating some shorthand for these values
var wBounds = self.view.bounds.width
var hBounds = self.view.bounds.height
// This houses all of the UIViews / content
scrollView = UIScrollView()
scrollView.backgroundColor = UIColor.clearColor()
scrollView.frame = self.view.frame
scrollView.pagingEnabled = true
scrollView.showsHorizontalScrollIndicator = false
scrollView.delegate = self
scrollView.bounces = false
self.view.addSubview(scrollView)
self.scrollView.contentSize = CGSize(width: self.view.bounds.size.width * 3, height: hBounds/2)
//Putting a subview in the navigationbar to hold the titles and page dots
navbarView = UIView()
self.navigationController?.navigationBar.addSubview(navbarView)
//Paging control is added to a subview in the uinavigationcontroller
pageControl = UIPageControl()
pageControl.frame = CGRect(x: 0, y: 35, width: 0, height: 0)
pageControl.backgroundColor = UIColor.whiteColor()
pageControl.numberOfPages = 3
pageControl.currentPage = 0
pageControl.currentPageIndicatorTintColor = UIColor(red:0.325, green:0.667, blue:0.922, alpha: 1)
pageControl.pageIndicatorTintColor = UIColor.whiteColor()
self.navbarView.addSubview(pageControl)
//Titles for the nav controller (also added to a subview in the uinavigationcontroller)
//Setting size for the titles. FYI changing width will break the paging fades/movement
var titleSize = CGRect(x: 0, y: 8, width: wBounds, height: 20)
navTitleLabel1 = UILabel()
navTitleLabel1.frame = titleSize
navTitleLabel1.text = "Home"
navTitleLabel1.textAlignment = NSTextAlignment.Center
self.navbarView.addSubview(navTitleLabel1)
navTitleLabel2 = UILabel()
navTitleLabel2.frame = titleSize
navTitleLabel2.text = "Discover"
navTitleLabel2.textAlignment = NSTextAlignment.Center
self.navbarView.addSubview(navTitleLabel2)
navTitleLabel3 = UILabel()
navTitleLabel3.frame = titleSize
navTitleLabel3.text = "Activity"
navTitleLabel3.textAlignment = NSTextAlignment.Center
self.navbarView.addSubview(navTitleLabel3)
//Views for the scrolling view
//This is where the content of your views goes (or you can subclass these and add them to ScrollView)
view1 = UIView()
view1.backgroundColor = UIColor(red:0.325, green:0.667, blue:0.922, alpha: 1)
view1.frame = CGRectMake(0, 0, wBounds, hBounds)
self.scrollView.addSubview(view1)
self.scrollView.bringSubviewToFront(view1)
//Notice the x position increases per number of views
view2 = UIView()
view2.backgroundColor = UIColor(red:0.231, green:0.529, blue:0.757, alpha: 1)
view2.frame = CGRectMake(wBounds, 0, wBounds, hBounds)
self.scrollView.addSubview(view2)
self.scrollView.bringSubviewToFront(view2)
//Notice the x position increases yet again (wBounds * 2)
view3 = UIView()
view3.backgroundColor = UIColor(red:0.529, green:0.600, blue:0.647, alpha: 1)
view3.frame = CGRectMake(wBounds * 2, 0, wBounds, hBounds)
self.scrollView.addSubview(view3)
self.scrollView.bringSubviewToFront(view3)
}
override func viewDidLayoutSubviews() {
super.viewDidLayoutSubviews()
navbarView.frame = CGRect(x: 0, y: 0, width: self.view.bounds.width, height: 44)
}
func scrollViewDidScroll(scrollView: UIScrollView) {
var xOffset: CGFloat = scrollView.contentOffset.x
//Setup some math to position the elements where we need them when the view is scrolled
var wBounds = self.view.bounds.width
var hBounds = self.view.bounds.height
var widthOffset = wBounds / 100
var offsetPosition = 0 - xOffset/widthOffset
//Apply the positioning values created above to the frame's position based on user's scroll
navTitleLabel1.frame = CGRectMake(offsetPosition, 8, wBounds, 20)
navTitleLabel2.frame = CGRectMake(offsetPosition + 100, 8, wBounds, 20)
navTitleLabel3.frame = CGRectMake(offsetPosition + 200, 8, wBounds, 20)
//Change the alpha values of the titles as they are scrolled
navTitleLabel1.alpha = 1 - xOffset / wBounds
if (xOffset <= wBounds) {
navTitleLabel2.alpha = xOffset / wBounds
} else {
navTitleLabel2.alpha = 1 - (xOffset - wBounds) / wBounds
}
navTitleLabel3.alpha = (xOffset - wBounds) / wBounds
}
func scrollViewDidEndDecelerating(scrollView: UIScrollView) {
var xOffset: CGFloat = scrollView.contentOffset.x
//Change the pageControl dots depending on the page / offset values
if (xOffset < 1.0) {
pageControl.currentPage = 0
} else if (xOffset < self.view.bounds.width + 1) {
pageControl.currentPage = 1
} else {
pageControl.currentPage = 2
}
}
}

Related

Programmatically display UIScrollView in Swift

I have view controller with views: top level View Contains Container View which contains two views: bottomView, topView, as shown.
Scene
I want to display from: to: date range in the topView. In the bottomView I want to display a UIScrollView that contains two columns which I can scroll. I did that but the topView and BottomView overlap when I introduce scrollView. When I scroll I can see the views getting separated and as soon as i Let go the scrollbar they overlap again.
can someone tell me how to fix it? I just don't seem to understand how the scrollView and bottomView are to be associated.
Code below:
override func viewDidLayoutSubviews() {
super.viewDidLayoutSubviews()
scrollView.frame = view.bounds
//scrollView.frame = innerView.bounds
innerView.frame = CGRect(x:0, y:0, width:scrollView.contentSize.width, height:scrollView.contentSize.height)
}
func buildBottomView () {
let screenSize = UIScreen.main.bounds
let screenWidth = screenSize.width
let ht:Int = 21
let incrX:Int = 5
let incrY:Int = 5
let gapCol1:Int = 5
let col1Width:Int = 65
let col2Width:Int = 65
let startY:Int = 5
let col1StartX:Int = 10
let col2StartX:Int = col1StartX + col1Width + gapCol1
var loadRowStartY: Int = 0
// column headers
categoryColumnLabel.text = "Interval"
categoryColumnLabel.font = UIFont.preferredFont(forTextStyle:UIFontTextStyle.subheadline)
//categoryColumnLabel.font = UIFont.systemFont(ofSize: 14)
categoryColumnLabel.frame = CGRect(x: col1StartX, y:startY, width: col1Width, height: ht)
categoryColumnLabel.textAlignment = NSTextAlignment.left
categoryColumnLabel.tag = 1
innerView.addSubview(categoryColumnLabel)
valueColumnLabel.text = "Values"
valueColumnLabel.font = UIFont.preferredFont(forTextStyle:UIFontTextStyle.subheadline)
//valueColumnLabel.font = UIFont.systemFont(ofSize: 14)
valueColumnLabel.frame = CGRect(x: col2StartX, y:startY, width: col2Width, height: ht)
valueColumnLabel.textAlignment = NSTextAlignment.center
valueColumnLabel.tag = 3
innerView.addSubview(valueColumnLabel)
let sepLine:UIView = UIView()
sepLine.frame = CGRect(x: col1StartX, y:startY+ht+incrY, width: Int(screenWidth-20), height: 2)
sepLine.backgroundColor = UIColor.darkGray
sepLine.tag = 60
loadRowStartY = startY+ht+incrX+ht
innerView.addSubview(sepLine)
for i in 0 ..< 24 {
let timeIntervalLabel = UILabel()
let value2Label = UILabel()
print("display load profile")
let loadStruct = loadDict[String(i)] as! CommercialProfile
print (loadStruct.timeInterval)
timeIntervalLabel.text = loadStruct.timeInterval
timeIntervalLabel.font = UIFont.preferredFont(forTextStyle:UIFontTextStyle.caption1)
//valueColumnLabel.font = UIFont.systemFont(ofSize: 14)
timeIntervalLabel.frame = CGRect(x: col1StartX, y:loadRowStartY, width: col1Width, height: Int(timeIntervalLabel.font.lineHeight))
timeIntervalLabel.textAlignment = NSTextAlignment.center
innerView.addSubview(timeIntervalLabel)
print(loadStruct.value)
value2Label.text = loadStruct.value
value2Label.font = UIFont.preferredFont(forTextStyle:UIFontTextStyle.caption1)
//value2Label = UIFont.systemFont(ofSize: 14)
value2Label.frame = CGRect(x: col2StartX, y:loadRowStartY, width: col2Width, height: Int(value2Label.font.lineHeight))
value2Label.textAlignment = NSTextAlignment.center
innerView.addSubview(value2Label)
loadRowStartY = loadRowStartY + incrY + Int(value2Label.font.lineHeight)
}
you are setting the bounds of the scrollView to the size of the whole view with this code: scrollView.frame = view.bounds.
The scrollView only needs to scroll the content in the bottom view. Scroll Views have their own content, that is normally larger than the viewable area of the screen/view. The scroll view just allows you to pan the viewport of that view.
So add the bottom view and setup your constraints on that. add the scrollView to the bottom view and then add your content into the scrollView.
Make sure that your bottom view has clipToBounds set to true and then you should be able to keep the headers in place and just scroll the content.
I'll try and put an example together for you shortly.
EDIT:
I've just created this simple example which shows the scroll behaviour you need. This works in a playground or just as a simple view controller. I've intentionally not used auto layout or setup constraints due to time, but you will see what you need to solve your issue
class ViewController: UIViewController {
var topView: UIView!
var bottomView: UIView!
var scrollView: UIScrollView!
var contentView: UIView!
override func viewDidLoad() {
super.viewDidLoad()
let screenSize = UIScreen.main.bounds
self.topView = UIView(frame: CGRect(x: 0, y: 0, width: screenSize.width, height: 100))
self.bottomView = UIView(frame: CGRect(x: 0, y: 100, width: screenSize.width, height: screenSize.height - 100))
self.scrollView = UIScrollView(frame: CGRect(x: 0, y: 100, width: screenSize.width, height: screenSize.height - 100))
self.contentView = UIView(frame: CGRect(x: 0, y: 0, width: screenSize.width, height: screenSize.height * 3))
self.view.backgroundColor = .white
self.view.addSubview(self.topView)
self.view.addSubview(self.bottomView)
self.bottomView.addSubview(self.scrollView)
self.scrollView.addSubview(self.contentView)
self.bottomView.clipsToBounds = true
self.scrollView.contentSize = CGSize(width: screenSize.width, height: screenSize.height * 3)
self.contentView.backgroundColor = .gray
}
}

my initial problems with UIScrollView now appear to be related to autolayout

For my first challenge using UIScrollView I modified this example to make UIScrollView display not just another background colour but another UIView and UILabel on each page. But I could have just as easily chosen to display objects like UITableView, UIButton or UIImage.
Potentially, UIScrollView could be much more than a giant content view where users scroll from one part to the next, e.g., some pages might have a UIButton that takes a user to a specific page, the same way we use books.
Code Improvements
My question has evolved since I first posted it. Initially the labels piled up on page 1 (as shown below) but this has now been corrected. I also included this extension to make the font larger.
Further improvement ?
As the code evolved I became more aware of other issues e.g. iPhone 5 images (below) appear differently on iPhone 7 where the UILabel is centred but not the UIView. So my next challenge is possibly to learn how to combine UIScrollView with Autolayout. I invite anyone to spot other things that might be wrong.
ViewController.swift (corrected)
import UIKit
class ViewController: UIViewController,UIScrollViewDelegate {
let scrollView = UIScrollView(frame: CGRect(x: 0, y: 0, width: 320, height: 480))
var views = [UIView]()
var lables = [UILabel]()
var colors:[UIColor] = [UIColor.red, UIColor.magenta, UIColor.blue, UIColor.cyan, UIColor.green, UIColor.yellow]
var frame: CGRect = CGRect.zero
var pageControl: UIPageControl = UIPageControl(frame: CGRect(x: 50, y: 500, width: 200, height: 50))
override func viewDidLoad() {
super.viewDidLoad()
initialiseViewsAndLables()
configurePageControl()
scrollView.delegate = self
self.view.addSubview(scrollView)
for index in 0..<colors.count {
frame.origin.x = self.scrollView.frame.size.width * CGFloat(index)
frame.size = self.scrollView.frame.size
self.scrollView.isPagingEnabled = true
views[index].frame = frame
views[index].backgroundColor = colors[Int(index)]
views[index].layer.cornerRadius = 20
views[index].layer.masksToBounds = true
lables[index].frame = frame
lables[index].center = CGPoint(x: (view.frame.midX + frame.origin.x), y: view.frame.midY)
lables[index].text = String(index + 1)
lables[index].defaultFont = UIFont(name: "HelveticaNeue", size: CGFloat(200))
lables[index].textAlignment = .center
lables[index].textColor = .black
let subView1 = views[index]
let subView2 = lables[index]
self.scrollView .addSubview(subView1)
self.scrollView .addSubview(subView2)
}
print(views, lables)
self.scrollView.contentSize = CGSize(width: self.scrollView.frame.size.width * CGFloat(colors.count), height: self.scrollView.frame.size.height)
pageControl.addTarget(self, action: Selector(("changePage:")), for: UIControlEvents.valueChanged)
}
func initialiseViewsAndLables() {
// Size of views[] and lables[] is linked to available colors
for index in 0..<colors.count {
views.insert(UIView(), at:index)
lables.insert(UILabel(), at: index)
}
}
func configurePageControl() {
// Total number of available pages is based on available colors
self.pageControl.numberOfPages = colors.count
self.pageControl.currentPage = 0
self.pageControl.backgroundColor = getColour()
self.pageControl.pageIndicatorTintColor = UIColor.black
self.pageControl.currentPageIndicatorTintColor = UIColor.green
self.view.addSubview(pageControl)
}
func getColour() -> UIColor {
let index = colors[pageControl.currentPage]
return (index)
}
func changePage(sender: AnyObject) -> () {
scrollView.setContentOffset(CGPoint(x: CGFloat(pageControl.currentPage) * scrollView.frame.size.width, y: 0), animated: true)
}
func scrollViewDidEndDecelerating(_ scrollView: UIScrollView) {
let pageNumber = round(scrollView.contentOffset.x / scrollView.frame.size.width)
pageControl.currentPage = Int(pageNumber)
pageControl.backgroundColor = getColour()
}
}
Extension
extension UILabel{
var defaultFont: UIFont? {
get { return self.font }
set { self.font = newValue }
}
}
The centre point of the lable on each frame must be offset by the origin of the content view (as Baglan pointed out). I've modified the following line of code accordingly.
lables[Int(index)].center = CGPoint(x: (view.frame.midX + frame.origin.x), y: view.frame.midY)

Create an "add-player" view - Swift

I'm creating a game where the player has the possibility to add several players on a view controller :
Actually, I can add a new player and remove it :
The problem appears when I remove a player :
I want player 2 and player 3 goes below the textField "Name when I remove a player. How can I do this ?
ViewDidLoad :
// MARK: ADD BUTTON
let addButtonSize = CGSize(width: topPartSize.height, height: topPartSize.height)
let addButton = UIButton(frame: CGRect(x: enterPlayerPartSize.width - addButtonSize.width, y: 0, width: addButtonSize.width, height: addButtonSize.height))
addButton.titleLabel!.font = UIFont.fontAwesomeOfSize(addButtonSize.height / 2)
addButton.setTitle(String.fontAwesomeIconWithName(.Plus), forState: .Normal)
addButton.setTitleColor(UIColor.whiteColor(), forState: .Normal)
addButton.setTitleColor(UIColor(red: 1, green: 1, blue: 1, alpha: 0.5), forState: .Highlighted)
addButton.titleLabel?.textAlignment = .Center
addButton.layer.zPosition = 3
addButton.addTarget(self, action: #selector(PlayersViewController.addPlayer(_:)), forControlEvents: .TouchUpInside)
enterPlayerPart.addSubview(addButton)
// MARK: TEXT FIELD
let textFieldSize = CGSize(width: enterPlayerPartSize.width - playerIconSize.width - addButtonSize.width, height: enterPlayerPartSize.height)
textField = UITextField(frame: CGRect(x: playerIconSize.width, y: 0, width: textFieldSize.width, height: textFieldSize.height))
textField.font = UIFont(name: "Avenir-Light", size: textFieldSize.height / 2)
textField.attributedPlaceholder = NSAttributedString(string:"Name", attributes:[NSForegroundColorAttributeName: UIColor(red: 1, green: 1, blue: 1, alpha: 0.5)])
textField.textColor = UIColor.whiteColor()
textField.textAlignment = NSTextAlignment.Left
textField.returnKeyType = UIReturnKeyType.Done
textField.delegate = self
enterPlayerPart.addSubview(textField)
Functions :
// MARK: ADD PLAYER - FUNCTION
func addPlayer(sender: UIButton) {
if textField.text == nil || textField.text == "" {
print("Enter player name")
} else {
createNewPlayer(textField.text!)
}
}
// MARK: CREATE NEW PLAYER - FUNCTION
func createNewPlayer(playerName: String) {
let playerPartSize = CGSize(width: screenWidth, height: screenHeight * 0.1)
let playerPart = UIView(frame: CGRect(x: 0, y: playerPartSize.height * CGFloat(playersCount), width: playerPartSize.width, height: playerPartSize.height))
scrollView.addSubview(playerPart)
// PLAYER ICON
let playerIconSize = CGSize(width: playerPartSize.height, height: playerPartSize.height)
let playerIcon = UILabel(frame: CGRect(x: 0, y: 0, width: playerIconSize.width, height: playerIconSize.height))
playerIcon.font = UIFont.fontAwesomeOfSize(topPartSize.height / 2)
playerIcon.text = String.fontAwesomeIconWithName(.User)
playerIcon.textAlignment = .Center
playerIcon.textColor = UIColor.whiteColor()
playerPart.addSubview(playerIcon)
// REMOVE BUTTON
let removeButtonSize = playerIconSize
let removeButton = UIButton(frame: CGRect(x: playerPartSize.width - removeButtonSize.width, y: 0, width: playerIconSize.width, height: playerIconSize.height))
removeButton.titleLabel!.font = UIFont.fontAwesomeOfSize(removeButtonSize.height / 2)
removeButton.setTitle(String.fontAwesomeIconWithName(.Trash), forState: .Normal)
removeButton.setTitleColor(UIColor.whiteColor(), forState: .Normal)
removeButton.setTitleColor(UIColor(red: 1, green: 1, blue: 1, alpha: 0.5), forState: .Highlighted)
removeButton.titleLabel?.textAlignment = .Center
removeButton.addTarget(self, action: #selector(PlayersViewController.removePlayer(_:)), forControlEvents: .TouchUpInside)
playerPart.addSubview(removeButton)
// PLAYER NAME
let playerNameSize = CGSize(width: playerPartSize.width - playerIconSize.width - removeButtonSize.width, height: playerPartSize.height)
let playerNameLabel = UILabel(frame: CGRect(x: playerIconSize.width, y: 0, width: playerNameSize.width, height: playerNameSize.height))
playerNameLabel.font = UIFont(name: "Avenir-Light", size: playerNameSize.height / 2)
playerNameLabel.text = playerName
playerNameLabel.textAlignment = .Left
playerNameLabel.textColor = UIColor.whiteColor()
playerPart.addSubview(playerNameLabel)
// BOTTOM LINE
let bottomLineHeight = playerPartSize.height / 50
let bottomLine = UIView(frame: CGRect(x: 0, y: playerPartSize.height - bottomLineHeight, width: playerPartSize.width, height: bottomLineHeight))
bottomLine.backgroundColor = UIColor(hexColor: 0x1B1B1B)
playerPart.addSubview(bottomLine)
// PLAYERS COUNT ++
playersCount += 1
}
Thanks for your help !
You have two ways to perform it :
You seem using reusable components, so you should have a look on UITableView / UICollectionView. It will manage memory usage, and components layout
If you dont want to migrate to theses components, it recommend you to store all your player views in an array, and relayout them after an add/remove operation
something like :
var players : [UIView] = []
func createNewPlayer(playerName: String) {
//Do your stuff here
players.append(newCreatedPalyerView)
layout()
}
func layout() {
var yPosition = 0
for view in players {
view.frame.origin.y = yPosition
yPosition += view.frame.size.height
}
}
func removePlayer(player : UIView) {
self.players.remove(player)
self.layout()
}
You need to manage your scenario something like below :
First take all the UI of one player in one UIView. So you should have all your one player's stuff(playername label, remove button etc) in one view. (i think you have it in playerPart - that`s cool)
Now you are adding that playerPart directly in scrollview i think, If it is like that then you should not do like this. You should have one UIView of same size of scrollview in scrollview(same as content size of scrollview) and you should add playerPart to that view.
Now you can get all subviews of that view in array something like :
NSArray *viewArr = [tempView subviews];
Assume tempView is vied over scrollview as i have mentioned above,
you can get subview of scrollview also by calling same method.
Now for example you have four player(four view) in view (temp view or scrollview if tempview is not added on it) and you click remove on player 3 then you can get index of that object from that view array. for example,
you have array of total view which you have get from
NSArray *viewArr = [tempView subviews];
then you can get index of player3 i.e view3 like,
int index = [viewArr indexOfObject:player3];
now make one method or function which is called after every removed call and pass that index as parameter in that method.
In that method take one for loop, which start from this index and run till last object (view) of this viewArr. Decrease y of every coming view in this for loop so your all view which was belowed removed view will goes up.
Here is one my method i was using in my one project to remove view and manage other accordingly :
#pragma mark UpdateFrameOfViews
-(void)updateFrameOfViewWithTag : (int) myTag increament : (CGFloat)increament fromIndex : (int)index{
CustomSubClassView *tempView = [self.view viewWithTag:myTag];
UIScrollView *tempScroll = (UIScrollView*)[tempView superview];
NSArray *subViews = [tempView subviews];
BOOL status = NO;
for (int i = index; i <= subViews.count; i++) {
if (i < subViews.count) {
UIView *tempView1 = [subViews objectAtIndex:i];
CGFloat newY = tempView1.frame.origin.y + increament;
CGRect newFrame = CGRectMake(tempView1.frame.origin.x, newY, tempView1.frame.size.width, tempView1.frame.size.height);
tempView1.frame = newFrame;
status = YES;
}
if (index == subViews.count && i == subViews.count) {
// UIView *tempView1 = [subViews lastObject];
//
// CGFloat newY = tempView1.frame.origin.y + increament;
//
// CGRect newFrame = CGRectMake(tempView1.frame.origin.x, newY, tempView1.frame.size.width, tempView1.frame.size.height);
//
// tempView1.frame = newFrame;
status = YES;
}
// tempView1.backgroundColor = [UIColor orangeColor];
}
if (status) {
CGRect containerFrame = CGRectMake(0, 0, self.view.frame.size.width, tempView.frame.size.height+increament);
tempView.frame = containerFrame;
tempScroll.contentSize = CGSizeMake(tempView.frame.size.width, tempView.frame.size.height);
}
}
This method is for reference just, because here scenario is little bit different.
My code is in objective and is for reference only convert in swift required!!
This was how you manage it!!
Suggestion : it is better to use UITableView in your case!!!
Hope this will help :)

When to use UITouch vs UIScroll

I would like to achieve the design you see in dating apps. Where you can vertically scroll images of a profile and also horizontally scroll to view the next or previous person in the list.
Currently I have my views laid out as such.
Previous-UIView - current UIView - next UIView
UIScrollView. UIScrollView. UIScrollView
Images. Images. Images
UIView. UIView. UIView
Profile info. Profile info. Profile info
UIPageControl. UIPageControl UIPageControl.
Only one of the Views occupies the main view with next and previous off screen. Ideally when the user moves the view left I would programmatically remove the previous view, make current the previous, the next current and add a new view for next. Visa versa for moving right.
What is the best way to scroll the views horizontally?
Should I wrap them all in a UIScrollView? And would that interfere with the UIScrollView sub Views?
Or should I program touch controls to move the views?
Or is there a better way?
I'm still a newbie at iOS development so any help would be greatly appreciated.
So I've tried some experimenting with a test app and I'm pleased to say you can have UIScrollviews inside UIScrollviews.
I was able to get it running perfectly. Here is my code below.
override func viewDidLoad() {
super.viewDidLoad()
self.superView.delegate = self
// Do any additional setup after loading the view, typically from a nib.
var subImages1 = ["IMG_0004.JPG","IMG_0005.JPG","IMG_0008.JPG"]
var subImages2 = ["IMG_0009.JPG","IMG_0010.JPG","IMG_0011.JPG"]
var subImages3 = ["IMG_0013.JPG","IMG_0017.JPG","IMG_0018.JPG"]
self.images.append(subImages1)
self.images.append(subImages2)
self.images.append(subImages3)
self.superView.frame = self.view.frame
self.superView.contentSize = CGSizeMake(self.view.frame.width*3, self.view.frame.height)
self.superView.contentOffset = CGPoint(x:self.view.frame.width,y:0)
self.superView.pagingEnabled = true
self.view.addSubview(self.superView)
//layout the UIVeiws into the master ScrollView
for i in 0...2{
var offset = self.view.frame.width * CGFloat(i)
var pView = UIView()
pView.frame = CGRectMake(offset, 0, self.view.frame.width, self.view.frame.height)
pView.backgroundColor = colours[i]
self.superView.addSubview(pView)
self.profileViews.append(pView)
}
// Add sub Scroll views and images to the Views.
for (index, view) in enumerate(self.profileViews){
var scrollView = UIScrollView()
scrollView.delegate = self
scrollView.frame = CGRectMake(10, 10, self.view.frame.width-20, self.view.frame.height-20)
scrollView.pagingEnabled = true
scrollView.contentSize = CGSizeMake(scrollView.frame.width, scrollView.frame.height * CGFloat(images[index].count))
for (index2, image) in enumerate(images[index]){
var subImage = UIImageView()
subImage.frame = CGRectMake(0, scrollView.frame.height * CGFloat(index2), scrollView.frame.width, scrollView.frame.height)
subImage.contentMode = UIViewContentMode.ScaleAspectFit
subImage.image = UIImage(named: image as! String)
scrollView.addSubview(subImage)
}
view.addSubview(scrollView)
self.scrollViews.append(scrollView)
}
}
//Use the did end decelerating as it executes the code once the scoll has finished moving.
func scrollViewDidEndDecelerating(scrollView: UIScrollView) {
if(scrollView == self.superView){
var contentOffset = scrollView.contentOffset
var pageWidth = self.superView.frame.width
var fractionalPage:Double = Double(self.superView.contentOffset.x / pageWidth)
var page = lround(fractionalPage)
// In this example I take the last UIView from the stack and move it to the first.
// I would do the same in the real app but update the contents of the view after
if(page == 0){
var tempView = self.profileViews[2]
self.profileViews[2].removeFromSuperview()
self.profileViews.removeAtIndex(2)
for view in self.profileViews{
view.frame = CGRectMake(view.frame.minX + self.view.frame.width, 0, view.frame.width, view.frame.height)
println(view.frame)
}
tempView.frame = CGRectMake(0, 0, tempView.frame.width, tempView.frame.height)
self.profileViews.insert(tempView, atIndex: 0)
self.superView.addSubview(tempView)
var newOffset = contentOffset.x + pageWidth
self.superView.contentOffset = CGPoint(x: newOffset, y: 0)
}
// Take the first view and move it to the last.
if(page == 2){
var tempView = self.profileViews[0]
self.profileViews[0].removeFromSuperview()
self.profileViews.removeAtIndex(0)
for view in self.profileViews{
view.frame = CGRectMake(view.frame.minX - self.view.frame.width, 0, view.frame.width, view.frame.height)
println(view.frame)
}
tempView.frame = CGRectMake(tempView.frame.width*2, 0, tempView.frame.width, tempView.frame.height)
self.profileViews.append(tempView)
self.superView.addSubview(tempView)
var newOffset = contentOffset.x - pageWidth
self.superView.contentOffset = CGPoint(x: newOffset, y: 0)
}
}
}

ios: Center view in its superview

I'm trying to center my subview with a button in itssuperview. So I want the center of the subview be the center of the superview. I'm trying that with following code:
override func viewDidLoad() {
self.view.backgroundColor = UIColor.redColor()
var menuView = UIView()
var newPlayButton = UIButton()
//var newPlayImage = UIImage(named: "new_game_button_5cs")
var newPlayImageView = UIImageView(image: UIImage(named: "new_game_button_5cs"))
newPlayButton.frame = CGRectMake(0, 0, newPlayImageView.frame.width, newPlayImageView.frame.height)
newPlayButton.setImage(newPlayImage, forState: .Normal)
newPlayButton.backgroundColor = UIColor.whiteColor()
menuView.center = self.view.center
menuView.center = CGPointMake(self.view.bounds.size.width / 2, self.view.bounds.size.height / 2)
menuView.backgroundColor = UIColor.whiteColor()*/
menuView.addSubview(newPlayButton)
}
Unfortunately it doesent seem to work as this is the result:
UIView *subview = your View To Be Centered In Its SuperView;
UIView *superView = subview.superview;
subview.center = [superView convertPoint:superView.center
fromView:superView.superview];
If view is nil(on fromView:), this method instead converts from window base coordinates. Otherwise, both view and the receiver must belong to the same UIWindow object.
NOTE: If you use the auto layout stuff, then you have to change the constraints . not the frame or center.
Good Luck :)
Try removing your view width from your superview width, e.g.:
var width: CGFloat = (self.view.bounds.size.width / 2)
// (here goes your view width that you want centralize)
menuView.center = CGPointMake(width, self.view.bounds.size.height / 2)
My working code
vRate = superview
rcRating = view ( that I want to centralize in vRate )
self.rcRating = AMRatingControl(location: CGPoint(x: 0, y: 0), andMaxRating: 5)
self.vRate.addSubview(self.rcRating)
var width: CGFloat = (self.vRate.bounds.size.width / 2) - self.rcRating.bounds.size.width
self.rcRating.center = CGPointMake(width, self.vRate.bounds.size.height / 2)

Resources