How to zoom ImageView inside PageViewController swift - ios

I am using a PageViewController which loads multiple images. I can slide through the images one by one. I now want to zoom that ImageView, how can I achieve it. Thanks in advance.
I have this in my viewDidLoad
var vWidth = self.view.frame.width
var vHeight = self.view.frame.height
var scrollImg: UIScrollView = UIScrollView()
scrollImg.delegate = self
scrollImg.frame = CGRectMake(0, 0, vWidth, vHeight)
scrollImg.backgroundColor = UIColor(red: 90, green: 90, blue: 90, alpha: 0.90)
scrollImg.alwaysBounceVertical = false
scrollImg.alwaysBounceHorizontal = false
scrollImg.showsVerticalScrollIndicator = true
scrollImg.flashScrollIndicators()
scrollImg.minimumZoomScale = 1.0
scrollImg.maximumZoomScale = 10.0
self.view.addSubview(scrollImg)
scrollImg.addSubview(contentImageView!)
And then the delegate of the scrollview
func viewForZoomingInScrollView(scrollView: UIScrollView) -> UIView? {
return self.contentImageView
}
Now the image gets kind of zoomed abnormally, focusing mostly on the top. And not able to pan it.

Related

Add UIView over UIViewImage. Users can zooming image

I tried to add UIView over my UIImage. But it doesn't work for me.
When I reduce and increase my image, UIView moved down and doesn't cover completely my image.
I use double click for zooming.
#objc func doubleTap(gestureRecognizer: UITapGestureRecognizer) {
if self.productScrollView.zoomScale == 1 {
self.productScrollView.zoom(to: self.zoomRectForScale(scale: self.productScrollView.maximumZoomScale, center: gestureRecognizer.location(in: gestureRecognizer.view)), animated: true)
} else {
self.productScrollView.setZoomScale(1, animated: true)
}
}
I tried to use these codes, but it doesn't work for me.
first:
let tintView = UIView()
tintView.backgroundColor = UIColor(white: 0, alpha: 0.5)
tintView.frame = CGRect(x: 0, y: 0, width: imageView.frame.width,
height: imageView.frame.height)
imageView.addSubview(tintView)
Second:
let tintView = UIView()
tintView.backgroundColor = UIColor(white: 0, alpha: 0.5)
tintView.translatesAutoresizingMaskIntoConstraints = false
imageView.addSubview(tintView)
NSLayoutConstraint.activate([
tintView.bottomAnchor.constraint(equalTo: imageView.bottomAnchor),
tintView.leadingAnchor.constraint(equalTo: imageView.leadingAnchor),
tintView.trailingAnchor.constraint(equalTo: imageView.trailingAnchor),
tintView.topAnchor.constraint(equalTo: imageView.topAnchor),
])
also, I tried to add on storyboard, but it also doesn't work for me.
Does anyone have ideas or suggestions?
Try to add your UIView to the main view of your viewController instead of UIImageView and set constraints to the imageView

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)

Make transition between two Menus with UIScrollView

I want to have 2 menus (the other one will be the same as the one shown in the screenshot, but it will contain other items).
Each menu is in its own UIStackView.
I've decided to rule out the UIPageViewController and instead use UIScrollView because it's the behaviour I want.
How can I put both menus inside of UIScrollView and make a nice animation?
Are you avoiding UIPageViewController because of the complexity? Because if you are there is a much easier way to accomplish the same gesture controlled transition using UIScrollView's pagingEnabled property
Based on what I see in the screenshots...
var size = CGSize()
size.height = self.view.frame.height
size.width = self.view.frame.width * 2
let scrollView = UIScrollView()
scrollView.frame = self.view.frame
scrollView.contentSize = size
scrollView.pagingEnabled = true
scrollView.showsHorizontalScrollIndicator = false
nav.center.y = scrollView.frame.height / 2
nav.center.x = scrollView.frame.width / 2
nav2.center.y = scrollView.frame.height / 2
nav2.center.x = nav.center.x + scrollView.frame.width
scrollView.addSubview(nav1)
scrollView.addSubview(nav2)
self.view.addSubview(scrollView)
#dsieczko did fantastic job answering my question. I'm not experienced with AutoLayout, so that was the problem. My final code looks something like this:
import UIKit
class MainMenuViewController: UIViewController, UIScrollViewDelegate {
#IBOutlet var scrollView: UIScrollView!
#IBOutlet var nav2: UIStackView!
#IBOutlet var nav: UIStackView!
#IBOutlet var pageControl: UIPageControl!
override func viewDidLoad() {
super.viewDidLoad()
/* MAIN MENUS */
var size = CGSize()
size.height = self.nav.frame.height
size.width = self.view.frame.width * 2
scrollView.frame = self.view.frame
scrollView.contentSize = size
scrollView.pagingEnabled = true
scrollView.showsHorizontalScrollIndicator = false
nav.center.y = scrollView.frame.height / 2
nav.center.x = self.view.frame.width * 1.5
nav2.center.y = scrollView.frame.height / 2
nav2.center.x = nav.center.x + scrollView.frame.width + 400
scrollView.addSubview(nav)
scrollView.addSubview(nav2)
self.view.addSubview(scrollView)
/* MAIN MENUS */
// Change the Navigation Bar Color to Red
navigationController!.navigationBar.barTintColor = UIColor(red: 0.79, green: 0.19, blue: 0.19, alpha: 1)
// Change the Navigation Bar Font to Lato
self.navigationController?.navigationBar.titleTextAttributes =
[NSForegroundColorAttributeName: UIColor.whiteColor(),
NSFontAttributeName: UIFont(name: "Lato-Semibold", size: 20)!]
}
}
And my layout something like this:
If anyone encounters a problem like this, I will gladly help with my exp with this.

Create Constraints to reposition the button on the view resized programmatically

I'm working on an app that resizes shapes. I'm using views for example.
I drew my view:
And programmatically created a button and added a UIPanGestureRecognizer:
import UIKit
class ViewController: UIViewController {
#IBOutlet var rect: UIView!
override func viewDidLoad() {
super.viewDidLoad()
let rectFrame = rect.frame
let selectorColor = UIColor(red: 0.000, green: 0.000, blue: 0.000, alpha: 0.700)
let resizeTopLeft = UIButton(frame: CGRect(x: rectFrame.size.width - 20, y: rectFrame.size.height - 20, width: 20, height: 20))
resizeTopLeft.backgroundColor = selectorColor
let panTopLeft = UIPanGestureRecognizer(target: self, action: "panTopLeft:")
resizeTopLeft.addGestureRecognizer(panTopLeft)
rect.addSubview(resizeTopLeft)
}
func panTopLeft(gesture: UIPanGestureRecognizer){
let location = gesture.locationInView(rect)
rect.frame.size = CGSize(width: location.x + 20, height: location.y + 20)
}
}
At run time, it is presented as follows:
When the move across the screen button, the view resizes as expected. But the button is still in the same place.
And this is the problem: I need you to resize the view when the button is positioned as a Constraints. I tried to make several Constraints, in nothing worked as expected.
My question: How do I create Constraints to reposition the button on the view resized programmatically?
Here you should use auto layout. Otherwise you should set position of button also in t pan gesture selector.
Here is my solution with auto layout.
Step 1 :
Add leading, top, width and height constraints for your view. Like
Step 2 :
Connect the width and height constrains via IBOutlet. like
#IBOutlet weak var rectHeightConstraint: NSLayoutConstraint!
#IBOutlet weak var rectWidthConstraint: NSLayoutConstraint!
Step 3 :
Add your button with auto layout constraints
//Create UIButton
let selectorColor = UIColor(red: 0.000, green: 0.000, blue: 0.000, alpha: 0.700)
let resizeTopLeft = UIButton()
resizeTopLeft.backgroundColor = selectorColor
resizeTopLeft.translatesAutoresizingMaskIntoConstraints = false
//Add gesture recognizer
let panTopLeft = UIPanGestureRecognizer(target: self, action: "panTopLeft:")
resizeTopLeft.addGestureRecognizer(panTopLeft)
rect.addSubview(resizeTopLeft)
//Add auto layout constraints for the button
let views = ["resizeTopLeft" : resizeTopLeft]
let horizontalConstraints = NSLayoutConstraint.constraintsWithVisualFormat("H:[resizeTopLeft(20)]|", options: NSLayoutFormatOptions(rawValue: 0), metrics: nil, views: views)
self.rect.addConstraints(horizontalConstraints)
let verticalConstraints = NSLayoutConstraint.constraintsWithVisualFormat("V:[resizeTopLeft(20)]|", options: NSLayoutFormatOptions(rawValue: 0), metrics: nil, views: views)
self.rect.addConstraints(verticalConstraints)
Step 4 :
Update height and width constraints in pan gesture method.
func panTopLeft(gesture: UIPanGestureRecognizer) {
let location = gesture.locationInView(rect)
//To avoid zero sized view.
if (location.y < 0) || (location.x < 0) {
return
}
rectHeightConstraint.constant = location.y + 20
rectWidthConstraint.constant = location.x + 20
}

iOS Tinder/Twitter like slider paging navigation and menu

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
}
}
}

Resources