How can I fill image in scroll view to fill screen? - ios

I am playing around with scroll views, and I've run into an issue I'be stuck with. I have a view controller create in Storyboard. The view controller contains a scroll view which fills the entire superview.
I then added the images programmatically to the scroll view. The images do show within the scroll view and paging works just fine. Only problem is the scroll view is set ti fill superview but the image view that hold the images seems like it stops above where the navigation bar would be. How can I have the image view fill the whole view within the scroll view?
#IBOutlet weak var scrollView: UIScrollView!
#IBOutlet weak var pagingView: UIPageControl!
var images = [UIImage]()
var frame = CGRect(x: 0, y: 0,width: 0,height: 0)
override func viewDidLoad() {
super.viewDidLoad()
scrollView.delegate = self
scrollView.isPagingEnabled = true
images = [UIImage(named: "Slide1")!, UIImage(named: "Slide2")!, UIImage(named: "Slide3")!, UIImage(named: "Slide4")!]
pagingView.numberOfPages = images.count
// This is where I think I'm having the height problem.
for i in 0..<images.count {
let imageView = UIImageView()
let x = self.view.frame.size.width * CGFloat(i)
imageView.frame = CGRect(x: x, y: 0, width: self.view.frame.width, height: self.view.frame.height)
imageView.contentMode = .scaleAspectFill
imageView.image = images[i]
scrollView.contentSize.width = scrollView.frame.size.width * CGFloat(i + 1)
scrollView.addSubview(imageView)
}
}
func scrollViewDidEndDecelerating(_ scrollView: UIScrollView) {
let pageNumber = scrollView.contentOffset.x / scrollView.frame.size.width
pagingView.currentPage = Int(pageNumber)
}
After setting nav bar to hidden, here is the output
Scroll view background color is red

In this case you need to enable the parent view clipsToBounds. Set UIScrollview clipsToBounds property to True.
Programmatically scrollView.clipsToBounds = true
In UIStoryBoard - Click the view->Attributes Inspector
If you would like to see the whole screen, make sure to add the topConstraint of scrollView assigned superView and hide the navigationBar in viewWillAppear,
override func viewWillAppear(_ animated: Bool) {
super.viewWillAppear(animated)
navigationController?.setNavigationBarHidden(true, animated: animated)
}
Make sure to remove the status bar by
override var prefersStatusBarHidden: Bool {
return true
}
Update the Y position of Image.
imageView.frame = CGRect(x: x, y: **self.scrollView.frame.minY**, width: self.view.frame.width, height: self.view.frame.height)
Update the scrollView topConstraint by -20.

Related

How to show an image behind a navigation bar?

Any ideas how to show an image behind a navigation bar and also show the "full" navigation bar on scrolling down?
Thanks in advance!
navigationController?.hidesBarsOnSwipe = true
Simply you can do like this. I hope It will work.
Your Reference Image can be achieved by using the below code.
Here 180 is the header size of the TableView.With This condition scrollOffset > 180 you can change the UIColor of the NavigationBar elements.
func scrollViewDidScroll(_ scrollView: UIScrollView) {
let scrollOffset = scrollView.contentOffset.y
UIView.animate(withDuration: 0.1) {
self.navigationView.alpha = scrollOffset > 180 ? 1 : 0
}
}
In your Header of the TableView, you should assign the Desired Image as HeaderView.
You can add image in the title view of the navigation item in viewDidLoad() of the view controller
override func viewDidLoad() {
super.viewDidLoad()
// Do any additional setup after loading the view.
let image = UIImage(named: "YOURIMAGE")
navigationItem.titleView = UIImageView(image: image)
}
And here is an example how you can do it with CGRect.
override func viewDidLoad() {
super.viewDidLoad()
// Do any additional setup after loading the view.
let imageView = UIImageView(frame: CGRect(x: 0, y: 0, width: 38, height: 38))
imageView.contentMode = .ScaleAspectFit
let image = UIImage(named: "YOURIMAGE")
imageView.image = image
navigationItem.titleView = imageView
}

Add button overlay on UITableViewController with use static cells

I try to add button overlay on UITableViewController with static cells. But i get this result, button is working, but i not see result of search:
I'm trying to get this result:
I want to button was always at the bottom regardless of scrolling up or down.
In my code i use framework InstantSearch:
import UIKit
import InstantSearch
import WARangeSlider
class SearchTableViewController: UITableViewController {
#IBOutlet weak var resultButton: StatsButtonWidget!
override func viewDidLoad() {
super.viewDidLoad()
resultButton.frame = CGRect(x: 0, y: 0, width: 150, height: 60)
navigationController?.view.addSubview(resultButton)
InstantSearch.shared.registerAllWidgets(in: self.view)
LayoutHelpers.setupResultButton(button: resultButton)
resultButton.addTarget(self, action: #selector(resultButtonClicked), for: .touchUpInside)
}
}
How can i add button overlay on bottom in UITableViewController? Me need use only UITableViewController, not UIViewController with TableView.
You could directly add the button to the UITableView without AutoLayout, and make sure TableView's delegate is the controller, like:
override func viewDidLoad() {
super.viewDidLoad()
self.button.frame = CGRect(x: 0, y: self.tableView.frame.size.height - 50, width: self.tableView.frame.width, height: 50)
self.tableView.addSubview(self.button)
self.tableView.delegate = self
}
Then you are able to fix the button's position by UIScrollView delegate (UITableViewDelegate inherited from this) while TableView is scrolling:
public func scrollViewDidScroll(_ scrollView: UIScrollView) {
if (scrollView == self.tableView) {
let originY = scrollView.frame.size.height - self.button.frame.size.height + scrollView.contentOffset.y
self.button.frame = CGRect(x: 0, y: originY, width: scrollView.frame.width, height: self.button.frame.size.height)
}
}
Alternatively, if you want to position the button by AutoLayout, just define a NSLayoutConstraint property, and bind it to button's bottom space constraint to its super view. Then adjust the constraint's constant value by same mechanism in scrollViewDidScroll function.
You can just add an view at the bottom of your tableview.
override func viewDidLoad() {
super.viewDidLoad()
addResultButtonView()
}
private func addResultButtonView() {
let resultButton = UIButton()
resultButton.backgroundColor = .red
resultButton.setTitle("Hello", for: .normal)
tableView.addSubview(resultButton)
// set position
resultButton.translatesAutoresizingMaskIntoConstraints = false
resultButton.leftAnchor.constraint(equalTo: tableView.safeAreaLayoutGuide.leftAnchor).isActive = true
resultButton.rightAnchor.constraint(equalTo: tableView.safeAreaLayoutGuide.rightAnchor).isActive = true
resultButton.bottomAnchor.constraint(equalTo: tableView.safeAreaLayoutGuide.bottomAnchor).isActive = true
resultButton.widthAnchor.constraint(equalTo: tableView.safeAreaLayoutGuide.widthAnchor).isActive = true
resultButton.heightAnchor.constraint(equalToConstant: 50).isActive = true // specify the height of the view
}

Adding gestures to uiimageview in uiscrollview (pan, doubletap, pinch)

Currently i am trying to create some kind of an imageviewer, where you can click on an image which is then displayed in full size. Now i want to add gestures to it to zoom. I want to understand and see how to add the pinch gesture to zoom in and out, to be able to pan around the image and to zoom in quickly with the double tap gesture. I did not found much good tutorials.
I know that you zoom into the view, not into the image. That is why you use a ScrollView containing an ImageView. Now what is missing to enable zooming, pinching and moving the image around?
Thank you in advance for any helpful post.
In the following is "my" current code base for this feature. What needs to be added?
class DetailViewController: UIViewController, UIScrollViewDelegate {
var scrollView: UIScrollView!
var imageView: UIImageView!
override func viewDidLoad()
{
super.viewDidLoad()
self.navigationController?.isNavigationBarHidden = false
scrollView=UIScrollView()
scrollView.frame = CGRect(x: 0, y: 0, width: self.view.frame.width, height: (self.view.frame.height - (self.navigationController?.navigationBar.frame.size.height)! + 44))
scrollView.minimumZoomScale=1
scrollView.maximumZoomScale=3
scrollView.bounces=false
scrollView.delegate=self
self.view.addSubview(scrollView)
imageView=UIImageView()
imageView.image = UIImage(named: "inlinelogo.jpg")
imageView.frame = CGRect(x: 0, y: 0, width: scrollView.frame.width, height: scrollView.frame.height - (44 + UIApplication.shared.statusBarFrame.size.height))
imageView.backgroundColor = .black
imageView.contentMode = .scaleAspectFit
scrollView.addSubview(imageView)
}
func viewForZoomingInScrollView(scrollView: UIScrollView) -> UIView?
{
return imageView
}
}
you missed the userInteractionEnabled property of UIImageView add
imageView.isuserInteractionEnabled = true

Scrollview ContentSize

I am trying to make a scrollview with 3 pictures on a sign up/join page for a small app I trying to make. I was using this code below:
import UIKit
class ViewController: UIViewController, UIScrollViewDelegate {
var signInButton: UIButton!
var joinButton: UIButton!
var pageControl: UIPageControl!
#IBOutlet weak var scrollView: UIScrollView!
var colors:[UIColor] = [UIColor.redColor(), UIColor.blueColor(), UIColor.greenColor(), UIColor.yellowColor()]
var frame = CGRectMake(0, 0, 0, 0)
override func viewDidLoad() {
super.viewDidLoad()
signInButton = UIButton(frame: CGRectMake(1/3.0 * self.view.bounds.size.width, 5/6.0 * self.view.bounds.size.height, 23, 60))
joinButton = UIButton(frame: CGRectMake(2/3.0 * self.view.bounds.size.width, 5/6.0 * self.view.bounds.size.height, 23, 60))
pageControl = UIPageControl(frame: CGRectMake(1/2.0 * self.view.bounds.size.width, 70/100.0 * self.view.bounds.size.height, 23, 60))
self.view.addSubview(signInButton)
self.view.addSubview(joinButton)
self.view.addSubview(pageControl)
signInButton.addTarget(self, action: "signInButtonClicked:", forControlEvents: .TouchUpInside)
joinButton.addTarget(self, action: "joinButtonClicked:", forControlEvents: .TouchUpInside)
pageControl.addTarget(self, action: Selector("changePage:"), forControlEvents: UIControlEvents.ValueChanged)
configurePageControl()
scrollView.delegate = self
for index in 0...3 {
frame.size = scrollView.frame.size
frame.origin.x = scrollView.frame.size.width * CGFloat(index)
scrollView.pagingEnabled = true
let view: UIView = UIView(frame: frame)
view.backgroundColor = colors[index]
scrollView.addSubview(view)
}
self.scrollView.contentSize = CGSizeMake(self.scrollView.frame.size.width * 4, self.scrollView.frame.size.height)
}
func configurePageControl() {
self.pageControl.numberOfPages = colors.count
self.pageControl.currentPage = 0
self.pageControl.tintColor = UIColor.redColor()
self.pageControl.pageIndicatorTintColor = UIColor.blackColor()
self.pageControl.currentPageIndicatorTintColor = UIColor.greenColor()
}
I put a scrollview on my view controller (using the size class width: Any and height: Any) and pinned all four sides of the scrollview to the view controller. For some reason each of the views I add to the scrollview are not exactly the same width as the iPhone.
For example when, I tried running it on an iPhone 6 the first view extends past the width of the iPhone. And that happens to the second and third view. I want the first view to be the exact width of the iPhone and the second view to be exactly to the right of the first view and so on. There seems to be some overlapping with the first view going past the width of the iPhone.
Could this be because I am using the size class (width: any and height: any) and I should disable size classes and add a scrollview for each iPhone width?
Can someone help me identify the problem here.
Add:
scrollView.setNeedsLayout()
scrollView.layoutIfNeeded()
at the beginning of the viewDidLoad() method.
Always call these two methods before accessing a view's frame when using Auto Layout, otherwise you'll probably get an incorrect size.
The problem is that when viewDidLoad() is called, your view still has a width of 600 (due to your storyboard view controller size of 600x600).
Your constraints dictate that the scroll view should be the same width as the device, but these constraints are only applied after viewDidLoad() finishes, when Auto Layout's next scheduled pass is calculated.
Adding the code above forces Auto Layout to perform a pass, thus giving you the correct frame sizes for subsequent use in your size calculations.
Put your scroll view in , set your constraint. Then grab a UIView, put it IN the scroll view, set it as equal width, equal height, and center it (use CTRL + drag to the scroll view, you'll get a small pop up menu)
Then put your content in the UIView you just created... Bam ! also I personally rename my UIView to ContentView, just for sake
Here's a screen to help :
Now I myself am still having issue with the height, I usually simply use a fixed height for the content view because if I don't it doesn't scroll....

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

Resources