View controller origin changes every time it's presented - ios

This is what my view controller should be:
This is what it is sometimes:
I want to display a view controller in the circle, however, almost every time the view controller in the circle (ResultViewController) is presented, it's place is different, though its properties doesn't change at all. Here's my code:
func openCircle(withCenter center: CGPoint, dataSource: ([Items], Int, String)){
self.addCircle(withCenter: center, dataSource: dataSource)
}
func addCircle(withCenter circleCenter: CGPoint, dataSource: ([Items], Int, String)) {
let longerSide = fmax(view.frame.size.height, view.frame.size.width)
let shorterSide = fmin(view.frame.size.height, view.frame.size.width)
let circleRadius = longerSide / 2
var resultViewOrigin = CGPoint()
var resultViewSize = CGSize()
if UIDevice.current.userInterfaceIdiom == .pad {
let rectWidth = shorterSide / 2
let rectHeight = sqrt(abs(circleRadius * circleRadius - rectWidth * rectWidth)) + view.frame.size.height - circleCenter.y
resultViewSize = CGSize(width: rectWidth, height: rectHeight)
resultViewOrigin = CGPoint(x: (view.frame.size.width - rectWidth) / 2, y: view.frame.size.height - rectHeight)
} else {
resultViewOrigin = CGPoint(x: 0.0, y: 0.0)
resultViewSize = CGSize(width: view.frame.size.width, height: view.frame.size.height)
}
let resultViewController = UIStoryboard(name: "Main", bundle: Bundle.main).instantiateViewController(withIdentifier: "ResultVC") as! ResultViewController
resultViewController.transitioningDelegate = self
resultViewController.modalPresentationStyle = .custom
resultViewController.dataSource = dataSource
resultViewController.view.frame = CGRect(origin: resultViewOrigin, size: resultViewSize)
transition.circle = UIView()
transition.startingPoint = circleCenter
transition.radius = circleRadius
transition.circle.frame = circleFrame(radius: transition.radius, center: transition.startingPoint)
present(resultViewController, animated: true)
}
It works well on the iPhone, not on the iPad, what's the problem?

I found the problem, it's actually a missing constraint on Regular-Regular size class caused this problem, I fixed it by adding a spacing to bottom layout guide to the part that used to get misplaced.
Thanks to everybody for your idea.

You can use a container view instead of presenting the view controller. You can create them programmatically or in interface builder (see Apple docs).

Related

Swift -Position new UIWIndow in center of Screen

The user taps a cell, I get the touchLocation, create and then animate a new UIWindow to the center of the screen. The problem is when the new window (purple) appears on screen instead of its center being in the center of the screen, its x,y coordinate starts at the center of the screen.
I get this:
But I want this:
// the collectionView is dimmed black, that's why the background color is dark
guard let keyWindow = UIApplication.shared.keyWindow else { return }
let startingRect = CGRect(x: userTouchPointX, y: userTouchPointY, width: 10, height: 10)
let newWindow = UIWindow(frame: startingRect)
newWindow.backgroundColor = .clear
newWindow.windowLevel = UIWindow.Level.normal
newWindow.rootViewController = UINavigationController(rootViewController: PurpleVC())
newWindow.isHidden = false
newWindow.makeKey()
let endingCenterX = keyWindow.screen.bounds.midX // I also tried keyWindow.frame.width / 2 and also UIScreen.main.bounds.width / 2
let endingCenterY = keyWindow.screen.bounds.midY // I also tried keyWindow.frame.height / 2 and also UIScreen.main.bounds.height / 2
let endingWidth = keyWindow.frame.width
let endingHeight: CGFloat = 200
let endingCenter = CGPoint(x: endingCenterX, y: endingCenterY)
UIView.animate(withDuration: 0.4, delay: 0, usingSpringWithDamping: 1, initialSpringVelocity: 1, options: [.curveEaseIn], animations: {
newWindow.center = endingCenter
newWindow.frame.size.width = endingWidth
newWindow.frame.size.height = endingHeight
}) { (_) in
newWindow.layoutIfNeeded()
}
Change your center After setting the frame of the window will solve your issue ... hopefully it will help
// newWindow.center = endingCenter remove from here
newWindow.frame.size.width = endingWidth
newWindow.frame.size.height = endingHeight
newWindow.center = endingCenter // add it here

How to add multiple view controllers on scrollview without them overlapping

I'm trying to fit multiple view controllers on a scroll view. But the views overlap on the screen
let settingView: SettingsView = SettingsView(nibName: "SettingsView", bundle: nil)
self.addChild(settingView)
self.scrollView.addSubview(settingView.view)
settingView.didMove(toParent: self)
settingView.view.frame = self.view.bounds
let mainView: MainView = MainView(nibName: "MainView", bundle: nil)
self.addChild(mainView)
self.scrollView.addSubview(mainView.view)
mainView.didMove(toParent: self)
mainView.view.frame = self.view.bounds
var mainFrame: CGRect = mainView.view.frame
mainFrame.origin.x = settingView.view.frame.width
mainView.view.frame = mainFrame
let connectionView: ConnectionView = ConnectionView(nibName: "ConnectionView", bundle: nil)
self.addChild(connectionView)
self.scrollView.addSubview(connectionView.view)
connectionView.didMove(toParent: self)
connectionView.view.frame = scrollView.bounds
var connectionFrame: CGRect = connectionView.view.frame
connectionFrame.origin.x = 2 * self.view.frame.width
connectionView.view.frame = connectionFrame
self.scrollView.contentSize = CGSize(width: (self.scrollView.frame.size.width) * 3
, height: self.scrollView.frame.size.height)
self.scrollView.contentOffset = CGPoint(x: (self.view.frame.width), y: self.view.frame.height)
each view controller should fit the size of the screen but they overlap onto each other screen

Adding View Controllers side by side into a Scroll View

How can i add my existing View Controllers into a Scroll View. I have tried the code below inside 'viewDidLoad' but it didn't work. Thanks
let view1 = ViewController6()
let view2 = ViewController2()
let view3 = ViewController3()
contentView.addSubview(view1)
contentView.addSubview(view2)
contentView.addSubview(view3)
self.contentView.contentSize = CGSize(width: self.view.frame.width * 3, height: self.view.frame.height)
Check this code Here I am doing the exactly thing that you want to achieve.
func setupScrollView()
{
//loop for
for i in 0..<3 {
//we instantiate our viewController from storyboard
let news2 = self.storyboard?.instantiateViewController(withIdentifier: "NewsMasterViewController") as! NewsMasterViewController
//we adjust the frame according
news2.view.frame = CGRect(x: CGFloat(i) * self.scrollView.frame.size.width + CGFloat(MasterViewController.margin), y: 0, width: self.scrollView.frame.size.width - CGFloat(MasterViewController.margin * 2), height: self.scrollView.frame.size.height)
//we call layoutSubviews for constraints adjustments
news2.view.layoutSubviews()
self.addChildViewController(news2)
//added the view of my viewController "news2" to scrollView
self.scrollView.addSubview(news2.view)
news2.didMove(toParentViewController: self)
//added the viewController "news2" to my array of viewControllers
newsMasterViewControllers.append(news2)
}
//adjusted contentSize of scrollView according the number of viewControllers added
self.scrollView.contentSize = CGSize(width: self.view.frame.size.width * 3, height: self.scrollView.frame.size.height);
}
I hope this helps you

Return Animation Function

I am wanting to create a function so I can easily implement and make modifications to a loading animation that I am using. I am not sure how to return everything I need to properly and get it to display. Here is the code that I used to create it:
let x = (self.view.frame.size.width / 2)
let y = (self.view.frame.size.height / 2)
self.loadingUI = NVActivityIndicatorView(frame: CGRectMake(x, y, 100, 100))
self.loadingUI.center = CGPointMake(view.frame.size.width / 2,
view.frame.size.height / 2)
self.loadingBackground.backgroundColor = UIColor.lightGrayColor()
self.loadingBackground.frame = CGRectMake(0, 0, 150, 150)
self.loadingBackground.center = (self.navigationController?.view.center)!
self.loadingBackground.layer.cornerRadius = 5
self.loadingBackground.layer.opacity = 0.5
self.navigationController?.view.addSubview(loadingBackground)
self.navigationController?.view.addSubview(loadingUI)
self.loadingUI.type = .BallRotateChase
self.loadingUI.color = UIColor.whiteColor()
self.loadingUI.startAnimation()
Is it possible to write a function that would create that so that I can use it multiple time throughout the app? Most everything is in a navigation controller for this custom app.
Here is an easier and simpler version.. I have added everything in viewDidLoad(), but you can make a new seperate function to take care of this.
I have changed the default loader type to ballClipRotateMultiple and default color to blue. Since the color of the load is also white either change bg color or color of loader.
import NVActivityIndicatorView
class ViewController: UIViewController, NVActivityIndicatorViewable {
override func viewDidLoad() {
super.viewDidLoad()
// Do any additional setup after loading the view, typically from a nib.
let x = self.view.center.x
let y = self.view.center.y
let frame = CGRect(x: (x - 50), y: (y - 50), width: 100, height: 100)
let activityIndicatorView = NVActivityIndicatorView(frame: frame)
activityIndicatorView.type = .ballClipRotateMultiple
activityIndicatorView.color = UIColor.blue
self.view.addSubview(activityIndicatorView)
activityIndicatorView.startAnimating()
}
}
Got it,
func loadingAnimation(loadingUI : NVActivityIndicatorView?, loadingBG : UIView, view : UIView, navController : UINavigationController) -> (NVActivityIndicatorView, UIView) {
var loadUI = loadingUI
var loadBG = loadingBG
let x = (view.frame.size.width / 2)
let y = (view.frame.size.height / 2)
loadUI = NVActivityIndicatorView(frame: CGRectMake(x, y, 100, 100))
loadUI!.center = CGPointMake(view.frame.size.width / 2,
view.frame.size.height / 2)
loadBG.backgroundColor = UIColor.lightGrayColor()
loadBG.frame = CGRectMake(0, 0, 150, 150)
loadBG.center = navController.view.center
loadBG.layer.cornerRadius = 5
loadBG.layer.opacity = 0.5
navController.view.addSubview(loadBG)
navController.view.addSubview(loadUI!)
loadUI!.type = .BallRotateChase
loadUI!.color = UIColor.whiteColor()
loadUI!.startAnimation()
return (loadUI!, loadBG)
}
Did the trick!
install pod
pod 'NVActivityIndicatorView'
then
In App Delegate Class
var window: UIWindow?
var objNVLoader = NVLoader()
class func getDelegate() -> AppDelegate
{
return UIApplication.shared.delegate as! AppDelegate
}
then did finish lunch method add
self.window = UIWindow(frame: UIScreen.main.bounds)
then
func showLoader()
{
self.window?.rootViewController!.addChildViewController(objNVLoader)
self.window?.rootViewController!.view!.addSubview(objNVLoader.view!)
objNVLoader.didMove(toParentViewController: self.window?.rootViewController!)
objNVLoader.view.frame=Constants.kScreenBound
self.window?.isUserInteractionEnabled = false
objNVLoader.showLoader()
}
func dismissLoader(){
objNVLoader.removeFromParentViewController()
objNVLoader.didMove(toParentViewController: nil)
objNVLoader.view.removeFromSuperview()
self.window?.isUserInteractionEnabled = true
objNVLoader.dismissLoader()
}
then
AppDelegate.getDelegate().showLoader()
AppDelegate.getDelegate().dismissLoader()

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.

Resources