Xcode horizontal UIScrollView - ios

I have 4 buttons in a UIViewController in XCode. I already added code to them so I would prefer to keep the buttons. I want to have the buttons side by side in the view where there is only one button on the screen at a time and the edge of the other buttons on the edge of the screen. Where you can just barely see them. I wanted to know how would I be able to accomplish this? If you need more information than this just let me know?

var scrollView: UIScrollView!
private func addButton() {
for index in 0...2{
let button = UIButton()
let x = scrollView.frame.size.width * CGFloat(index)
button.frame = CGRect(x: x, y: 0, width: scrollView.frame.width, height: self.view.frame.height)
button.backgroundColor = UIImage(named: ColorArr[index])
scrollView.contentSize.width = scrollView.frame.size.width * CGFloat(index + 1)
scrollView.addSubview(button)
}
}
You can call this function in viewDidLoad() and i took color array to differentiate buttons

Related

Swift 4 - Button over Tab Bar Item

I am trying to position a custom button over one of the item of my Tab bar.
func setupMiddleButton() {
let numberOfItems = CGFloat(tabBar.items!.count)
let tabBarItemSize = CGSize(width: tabBar.frame.width / numberOfItems, height: tabBar.frame.height)
let menuButton = UIButton(frame: CGRect(x: 0, y: 0, width: tabBarItemSize.width, height: self.tabBar.frame.size.height))
var menuButtonFrame = menuButton.frame
menuButtonFrame.origin.y = self.view.bounds.height - menuButtonFrame.height
menuButtonFrame.origin.x = self.view.bounds.width/2 - menuButtonFrame.size.width/2
menuButton.frame = menuButtonFrame
menuButton.backgroundColor = UIColor.white
self.view.addSubview(menuButton)
self.view.layoutIfNeeded()
My issue is that with the previous code the button is not perfectly over the bar item (see picture):
Any suggestion? I really don't know how else to try.
Thank you!
I notice that this screenshot is of an iPhone X Simulator, which has a different layout at the bottom of the screen.
Your code works well on any other iPhone. In iOS 11 they introduced what's called the "Safe area". When you calculate the size and origin for your button, you will have to take that into account.
When you calculate the origin.y for your buttonFrame, you have to subtract the height for the safe-area at the bottom, like this:
menuButtonFrame.origin.y = self.view.bounds.height - menuButtonFrame.height - self.view.safeAreaInsets.bottom
This won't solve your problem though, as your code probably runs in viewDidLoad, which happens before the view knows it's supposed be displayed on an iPhone X with a safe area.
You can override viewDidLayoutSubviews for this, and set the correct frame for your button each time that is called.
This will fix your issue:
class CustomTabBarViewController: UITabBarController {
let menuButton = UIButton(frame: CGRect.zero)
override func viewDidLoad() {
super.viewDidLoad()
setupMiddleButton()
}
func setupMiddleButton() {
let numberOfItems = CGFloat(tabBar.items!.count)
let tabBarItemSize = CGSize(width: tabBar.frame.width / numberOfItems, height: tabBar.frame.height)
menuButton.frame = CGRect(x: 0, y: 0, width: tabBarItemSize.width, height: tabBar.frame.size.height)
var menuButtonFrame = menuButton.frame
menuButtonFrame.origin.y = self.view.bounds.height - menuButtonFrame.height - self.view.safeAreaInsets.bottom
menuButtonFrame.origin.x = self.view.bounds.width/2 - menuButtonFrame.size.width/2
menuButton.frame = menuButtonFrame
menuButton.backgroundColor = UIColor.green
self.view.addSubview(menuButton)
self.view.layoutIfNeeded()
}
override func viewDidLayoutSubviews() {
super.viewDidLayoutSubviews()
menuButton.frame.origin.y = self.view.bounds.height - menuButton.frame.height - self.view.safeAreaInsets.bottom
}
}
I know it's tempting to simply call setupMiddleButton from inside viewDidLayoutSubviews, but do not do that. viewDidLayoutSubviews should not be used to create buttons etc., it should only be used to move them accordingly to the rest of the view. You might want to set the entire frame of menuButton inside viewDidLayoutSubviews rather than only the origin.y like I did, especially if you need to support rotation/landscape-mode. In this very simple example, updating origin.y is enough.

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

center element when pressed in a ScrollView

i really how to do a thing wich is probably easy..
I've a ScrollView with some button in it.
That's how i create all my button in the scrollview.
var buttonList = [UIButton]()
func createButton() {
let imageArray = fillImageArray()
var lastButtonWidth: CGFloat = 0
for index in 0..<6 {
let frame1 = CGRect(x: ((self.view.frame.size.width / 2) - 27.5) + CGFloat(index * 70), y: 0, width: 55, height: 55 )
let button = UIButton(frame: frame1)
button.setImage(imageArray[index], forState: .Normal)
button.tag = index
button.addTarget(parentViewController, action: #selector(ViewController.buttonClicked(_:)), forControlEvents: .TouchUpInside)
self.scrollView.addSubview(button)
lastButtonWidth = frame1.origin.x
buttonList.append(button)
}
self.scrollView.contentSize = CGSizeMake(lastButtonWidth + 55, 0)
}
I want when i press one of my button to center him and positioning correctly the other buttons.
example :
If i press on 5 i want this result :
the button 5 is moved to the center.
Now what I would suggest using is the scroll view method scrollView.scrollRectToVisible(CGRect, animated: Bool). This will move the scroll view to make a certain part of your content visible.
To create the CGRect you could do something like this:
let scrollWidth = scrollView.frame.width
let scrollHeight = scrollView.frame.height
let desiredXCoor = button.frame.origin.x - ((scrollWidth / 2) - (button.frame.width / 2) )
let rect = CGRect(x: desiredXCoor, y: 0, width: scrollWidth, height: scrollHeight)
scrollView.scrollRectToVisible(rect, animated: true)
My math may be a bit off, but the essence is that you use the size of the scrollView and the UIButton to create a CGRect for the scroll view to move to. This means when a button is clicked, you could use an implementation like this:
func myMethod() {
button.addTarget(self, action: "buttonClicked:", forControlEvents: UIControlEvents.TouchUpInside)
}
func buttonClicked(sender: UIButton){
let scrollWidth = scrollView.frame.width
let scrollHeight = scrollView.frame.height
let desiredXCoor = sender.frame.origin.x - ((scrollWidth / 2) - (sender.frame.width / 2) )
let rect = CGRect(x: desiredXCoor, y: 0, width: scrollWidth, height: scrollHeight)
scrollView.scrollRectToVisible(rect, animated: true)
}
If adjusted properly to your project, this should allow you to do what you have outlined.
Hope this would help you.
In button action method write below code.
func buttonClicked(sender:UIButton) {
for view in self.scrollView.subviews {
if view.isKindOfClass(UIButton) && view.tag == sender.tag {
let xCenter = max(0, (view.center.x - self.scrollView.frame.width/2))
self.scrollView.setContentOffset(CGPointMake(xCenter, self.scrollView.contentOffset.y), animated: true)
break;
}
}
}
I suppose you want the button touched to be placed in the center,so there is a easy solution, you can use the button's center.x - scrollview.width / 2 as the offsetX to construct the contentOffset and take two boundary situation into consideration:offsetx < 0 and offsetx + scrollview.width > scroll.contentSize.width
Ok i just found by myself.
let centerScrollView = scrollView.frame.size.height * 2
UIView.animateWithDuration(0.2, delay: 0, options: UIViewAnimationOptions.CurveLinear, animations: {
self.scrollView.contentOffset = CGPoint(x: sender.frame.origin.x - centerScrollView, y: sender.frame.origin.y)
}, completion: nil)
and it's perfectly center. Thx everyone.

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

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