Moving a button programmatically not working - Swift - ios

I'm having trouble programmatically moving a button.
I am using this code in viewDidLoad and I am NOT using auto-layout:
button.frame.origin = CGPoint(x: 0, y: 0)
But the button remains in its original position on the screen at runtime.
The strange thing is, the coordinates are actually being updated, but not being represented on the screen.
If I run the following code:
print(button.frame.origin.x) // prints 45.0
button.frame.origin = CGPoint(x: 0, y: 0)
print(button.frame.origin.x) // prints 0.0
But on screen the button remains at 45.
What am I doing wrong?

Change your button position in viewDidAppear method and it will change it's position at run time and your code will be:
override func viewDidAppear(animated: Bool) {
button.frame.origin = CGPoint(x: 0, y: 0)
}
From this post: Difference between viewDidLoad and viewDidAppear
viewDidLoad is called exactly once, when the view controller is first loaded into memory. This is where you want to instantiate any instance variables and build any views that live for the entire lifecycle of this view controller. However, the view is usually not yet visible at this point.
viewDidAppear is called when the view is actually visible, and can be called multiple times during the lifecycle of a View Controller (for instance, when a Modal View Controller is dismissed and the view becomes visible again). This is where you want to perform any layout actions or do any drawing in the UI - for example, presenting a modal view controller.

Perhaps a long shot (?), but...
Instead of:
button.frame.origin = CGPoint(x: 0, y: 0)
Try:
var frame = button.frame
frame.origin = CGPoint(x: 0, y: 0)
button.frame = frame
EDIT: The reason I suggest this is, I think button.frame returns a copy of the button's frame rect, so you are not directly changing the origin sub-property of the original CGRect instance, and that is why the change is not reflected.

Well, I guess that UIView subclasses listen on -setFrame: setter only (when talking around -frame property); changing the its sub-value, which is even non-object (and thus cannot overload setters on -size and -origin attributes to react), won't have any immediate effect IMO.
In that case, you have to modify the frame via another variable and set it back via -setFrame: as other posts suggest.

Related

View Reloads When Frame is Changed

I have a YouTubePlayer (from here) in my app. I have a UIViewController (we'll call this MainViewController) with a UITableView full of videos. Whenever a user taps on a cell, it opens another UIViewController (we'll call this DetailViewController) with my custom xib view called playerView. Like I said, playerView is a custom xib view and in that view is my YouTubePlayer. This is how I set up playerView in my DetailViewController
playerContainer.addSubview(playerView)
playerView.frame = CGRect(x: 0, y: 0, width: playerContainer.frame.size.width , height: playerContainer.frame.size.height)
playerView.player.loadVideoID(nowPlayingVideo.id)
Ok so this works great. BUT... whenever the user dismisses DetailViewController, I want playerView to be moved to the MainViewController. Like where the user can see what is playing in the background. So to do this, I added this code in DetailViewController...
override func viewWillDisappear(_ animated: Bool) {
nowPlayingView.addSubview(playerView)
playerView.frame = CGRect(x: 8, y: 8, width: width, height: height)
playerView.layoutIfNeeded()
}
nowPlayingView is another custom xib view and is added to the app's window earlier on. So this is where I start running into problems. This code works great. The frame is changed correctly and it's added to nowPlayingView, but, the YouTubePlayer in playerView seems to reload. So it pauses playback, shows a loading icon, and then resumes. It's pretty annoying. This shouldn't be happening because the video is already loaded in the YouTubePlayer. I'm pretty sure it happens only whenver I am changing the frame of playerView. Does anyone have any ideas on how to fix this?
When the video resumes playing after loading, does the video start over or does it resume where it left off before changing the view?

Tap event for a UIView with alpha set going to underlying button

When loading data from server, we mask our UI using a UIView like the following sample code:
let loadingView = UIView()
loadingView.tag = 9999
loadingView.frame = CGRect(x: 0, y: 0, width: UIScreen.main.bounds.size.width, height: UIScreen.main.bounds.size.height)
loadingView.backgroundColor = UIColor.white.withAlphaComponent(0.4);
controller.view.addSubview(loadingView)
As you can see this loadingView takes the entire width and height of the controller and practically masks the screen. Having alpha means underlying content is translucently visible. We remove this view from controller after data has loaded like this:
for view in controller.view.subviews
{
if view.tag == 9999
{
view.removeFromSuperview()
}
}
However we are seeing strange issue where-in if a user keeps tapping a UIButton on the controller while the loadingView is shown, tap on the button is invoked as many times after the loadingView has been removed from the controller. In other words, our action for UIButton tap gets invoked as many times as you tapped it while the loadingView was shown.
Are we doing something wrong? How can we prevent the tap on UIButton from being invoked while the loadingView is shown?
You should doable user interaction on the loading view.
loadingViee.userInteractionEnabled = false
As you said the loading view is on all over the screen.
You can Ignore touch of your screen during the loading view Once finished loading view you can continue Interaction as like below.
UIApplication.shared.beginIgnoringInteractionEvents()
UIApplication.shared.endIgnoringInteractionEvents()

How to properly create an overlay view in storyboard?

My aim is to create a popup view right below a button once is clicked, this is the concept:
The way I prepared the storyboard is by using two different UIViewController. The main one contains the two buttons and, once clicked, I modally push the second UIViewController over the current context.
My question is: what's the best or properly way to create constrain in order to move the "Tapped" image right below the button?
The way I do this is to add a childcontroller to your first storyboard vc. Then adjust the frame of the container view in the storyboard, which I hope will be easier than programmatically adjusting frames.
Then be sure to change the class on top of the VC that Xcode created for you.
When the button is clicked get the the bottom position of it (it's y in frame + height) and send it to the popup , then set them as the top constraint of the imageView in popup in viewDidLayoutSubview
You can calculate the position of the overlay using the button's and the view's positions and dimensions. For example, the overlay's y can be the button's frame.maxY + constant.
let x = ...
let y = ...
let width = ...
let height = ...
let overlay = UIView(frame: CGRect(x: x, y: y, width: width, height: height))
view.addSubView(overlay)
The translucent black view can be added as a UIView with the same frame as the view of the VC and constrained to always be the same as the frame of the VC's view. Add this view first, before you add overlay.

changing uiviewcontroller views frame?

Whatever Im trying to my view controller won't appear offscreen (as it I want to, because I have a handler(menu) that will make the animation from offscreen to onscreen. After realising (from other posts) that I can't change a views frame before it appears, makes sense to use this approach:
-(void)viewWillAppear:(BOOL)animated{
[super viewWillAppear:animated];
//self.view.frame = CGRectInset(self.view.frame, 100, 50);
self.view.frame = CGRectMake(50, 50, 50, 50);
}
But still, it is presented exactly on screen as any standard view controller would (0,0,width, height)
How to solve?
You have the method willLayoutSubviews: or viewDidLayoutSubviews
Called to notify the view controller that its view is about to layout
its subviews.When a view's bounds change, the view adjusts the position of its subviews.
So instead of doing it in view will appear,over ride the willLayoutSubviews:
-(void)viewWillLayoutSubviews{
[super viewWillLayoutSubviews];
[self.view setFrame:CGRectMake(100, 100, 100, 100)];
}
Have you considered adding all of your views to another view, functioning as a container view, and then adding that one view to your view controller's view? Then you'd be able to position that container view freely before it appears.
You could access the ViewControllers view property and set it in the loadView() and it will only be set once and therefore not messing up any custom animations.
The view controller calls this method when its view property is requested but is currently nil. This method loads or creates a view and assigns it to the view property.
Because viewWillLayoutSubviews() would be setting the frame every time subviews are laid out.
override func loadView() {
super.loadView()
self.view.frame = CGRect(x: self.view.bounds.origin.x,
y: self.view.bounds.origin.y,
width: self.view.bounds.width,
height: self.view.bounds.height * 0.8
}

UIViewAnimation works in a single view controller but not when it is segued into from another view controller

I have an animation function that works perfectly fine when there is only a single View Controller. When it runs, the block on the left hand side moves to the right hand side. The code for the animation is below.
let timerSquare = UIView()
func timerRectangle(){
timerSquare.backgroundColor = UIColor.greenColor()
timerSquare.frame = CGRect(x: 0, y: 450, width: 50, height: 20)
self.view.addSubview(timerSquare)
UIView.animateWithDuration(2.0, animations:
{
self.timerSquare.backgroundColor = UIColor.redColor()
self.timerSquare.frame = CGRect(x: 270, y: 450, width: 50, height: 20)
}, completition: nil)
}
However the problem happens when I create a view controller with a simple button that segues into the view controller with the animation code. Once it segues into the code the animation doesnt run and it displays the block in its finish position as though the animation had already completed running.
The View controller has no other code other than the animation code and Ive placed the animation function in numerous parts of the view controller including the "ViewDidLoad" section and Im unsure why it doesnt run the animation from the initial position. It works perfectly fine on its own and the only thing different is creating a button seguing into the code so its puzzling me. Any help would be appreciated thanks
I managed to find a solution to the problem. I needed to add the subview in viewDidLoad and then start the animation in viewDidAppear so it would begin as soon as the View appeared. Hope this helped anyone else out there having the same problem

Resources