Currently, myLocationButton is buried behind a button, if you take a look at the button the myLocationButton is behind that button. How do I move the Y position of the myLocationButton?
Use GMSMapView's padding to make this happen.
self.mapView.padding = UIEdgeInsetsMake(0, 0, 100, 0)
Replace '100' with whatever space you want the location-button to be pushed up. You should probably replace it with the y-location of your book-button. For example:
let botPadding = self.view.frame.size.height - self.bookButton.frame.origin.y
self.mapView.padding = UIEdgeInsetsMake(0, 0, botPadding, 0)
You can probably put this code wherever you want, maybe it'll work in viewDidLoad. But keep in mind that you'll have to call it again if your book-button is supposed to disappear at some point.
To make it dynamically placed, you could override viewDidLayoutSubviews or similar.
Related
i have view with `UIProgressView` and 3 dot-view. It's like a page control. Each page - the video. `progressView` displays progress of video playback
ok. I do not use constraints for left and right anchors, because my progressView should swap places with dot-view. For example, when current video is ended and next start play, we should swap positions of `progressView` with next dot-view. For swap i just change frames
and the problem is: when i move app to background and returns back, my `progressView` loses his old frame. It attaches to the left side, because `.frame.minX` is 0
and the last one: this problem occurs only after first returns from background
what i tried to do:
save progressView frames before app is going to background and restore it when app comes to foreground: progressView.frame = progressViewOldFrames and call setNeedsDisplay()
add constraint to leftAnchor with constant (frame.minX) before background and remove it after foreground
combine these 2 tries
so now it looks like
func appWillMoveInBackground() {
progressBarXConstraint = progressBar.leftAnchor.constraint(equalTo: self.leftAnchor, constant: progressBar.frame.minX)
progressBarXConstraint?.isActive = true
progressBarFrame = progressBar.frame
}
func updateProgressWidth() {
progressBarXConstraint?.isActive = false
// here i use constraints because my width and height also disables
// and only constraints helps me
progressBar.widthAnchor.constraint(equalToConstant: 32).isActive = true
progressBar.heightAnchor.constraint(equalToConstant: 6).isActive = true
progressBar.frame = progressBarFrame
progressBar.setNeedsDisplay()
}
UPDATE
ok, i should explain more. I guess i cant use constraints because we have some animation while we are scrolling. When we scroll to right - we should move our progressView to some points at right. And in this moment we should move right dot-view to the left. I mean, we do not scroll page by page, we can scroll to a half on the right, then we can return to the initial position.
this code of block did change frames of progressView and dot-view. Formulas are not important. Please, just understand the behavior of this view
func scrollViewDidScroll(_ scrollView: UIScrollView) {
// calc some math variables
// and call method that make changes in frames
pageControl.moveBetweenPages(atPercentValue: distInPercents - 100)
}
// its part of body moveBetweenPages() func
progressBar.frame = CGRect(x: progStartX + progAddDist, y: 0,
width: SizeConstants.progressBarWidth.value,
height: SizeConstants.height.value)
let dotStartX: CGFloat = SizeConstants.progressBarWidth.value + SizeConstants.itemsSpacing.value + (CGFloat(currentPageNum) * dotSectionSize)
dots[currentPageNum].view.frame = CGRect(x: dotStartX - dotAddDist, y: 0,
width: SizeConstants.dotWidth.value,
height: SizeConstants.height.value)
images shows how it looks before background and after
matt from comments suggested me use constraints instead of frames and yes, it helps and it works
only thing i can say is dont forget call setNeedsLayout() after constraints update
My issue is that i need to have a single view just below the UINavigationBar on screen at all times whilst navigating through a sign up journey. This is to display the current step in signing up. This needs to stay on screen at all times as the stages animate as they change so simply pushing a new view onto a UINavigationController isn't sufficient.
See an example of what i need to achieve below
I need to have the red item persist at all times even when a new view controller is pushed on
To try fix this I have created a custom UINavigationController in order to have a sticky view be present regardless of what view controller is showing.
I have created this code which suits my needs however doesnt feel like the correct option. Especially as I need to support iOS 10 and additionalSafeAreaInsets is not available
override func viewDidLayoutSubviews() {
stickyView.frame = CGRect(x: 0, y: navigationBar.frame.maxY, width: view.frame.size.width, height: 60)
children.forEach { $0.additionalSafeAreaInsets = UIEdgeInsets(top: 60, left: 0, bottom: 0, right: 0) }
}
What would be a good way to make sure that the view controllers frame starts below this header view? Or maybe an alternative approach?
There seems to be very little stuff on this topic from what i can see on stack overflow
Here is my app with the profile on the left (ProfileViewController) and a containerView on the right (ContainerViewController). What I am trying to achieve is once the containerViewController has done its job, it will update the height of the UIView.
// ContainerViewController.swift
let heightConstraint = self.view.constraints.filter { $0.identifier == "Height" }.first
heightConstraint?.constant = height
When browsing the list of constraints, they're all emtpy, and I did set up some constraints in the storyboard. So Why ? Is there any way to access the UIView within the ContainerViewController ?
Ps:
DispatchQueue.main.async {
self.view.frame = CGRect(x: 0, y: 0, width: width, height: height)
}
Sounds to work, but I think that modify constraint is proper ? Nope ?
What I would do, is to set IBOutlet for the constraint, and store it inside ContainerView.
This way, you don't depend on order number or anything else, to get this constraint, even if code (or storyboard) will changed in the future.
And Yes, the right way is to set the constraint constant, and not changing frame.
But be aware, that even constraint constant change need to be put on the main (UI) thread - (by the look of your code, I assume, you are dealing with the threads).
I having two sub views inside scrollview. I need to position that both subviews programmatically. I did it correctly by writing code inside DispatchQueue.main.async. Here is the code:
DispatchQueue.main.async {
self.SelectClientDetailView.frame = CGRect(x: 0, y: 637, width: self.SelectClientDetailView.frame.size.width, height: self.SelectClientDetailView.frame.size.height)
self.SelectClientDetailView2.frame = CGRect(x: 0, y: 837, width: self.SelectClientDetailView2.frame.size.width, height: self.SelectClientDetailView2.frame.size.height)
}
Its working good but when I scrolling my scrollview this both views set back to old positions. How to fix it. Its Default y position will be SelectClientDetailView:400 and SelectClientDetailView2: 600
If you are using Auto Layout then setting frame will cause some weird effects. Auto Layout and Frames doesn't go together. You'll need to rearrange the constrains, not the frames. While using Auto Layout changing the frames will cause some weird effects and will eventually revert back to the constraints you've created in the original UIView.
Some solutions:
If you want to use Autolayout approach then, You need to create an outlet to each constrain just like you would to a view and change its constant when needed.
disable Auto Layout in that specific xib and start playing with frames.
If you only want to change the frame Y position, try this instead:
self.SelectClientDetailView.frame.origin.y = 637
self.SelectClientDetailView.frame.origin.y = 837
As already mentioned, you might need to check your view hierarchy to be sure you are actually adding them to the UIScrollView (and not elsewhere).
I have a label on-screen that has its height set as 300px, set to the bottom of the screen, and I want to create a UIView that exactly overlays it. The code I use is
let theFrame = CGRect(x: myLabel.frame.minX, y: myLabel.frame.minY, width: myLabel.frame.width, height: myLabel.frame.height)
newVu = UIView(frame: theFrame)
let newColor = UIColor(colorLiteralRed: 0.5, green: 0.5, blue: 1, alpha: 0.5)
newVu.backgroundColor = newColor
self.view.addSubview(newVu)
The result that I get has the new UIView shifted about 20 points higher than the label. ((EDIT: as GeorgeGreen helped me see in Comments, this is because the label is within a Vertical StackView, which is constrained to the bottom of the Top Layout Guide -- thus the Y of the label is relative to the top of the Stack View, not the top of the screen.)) Clearly there are different frames of reference at work, but what is needed to bring everything into the same frame of reference? EDIT: Or, asked another way, how can I get the "absolute" X and Y coordinates of the label in the screen, so that no matter how many views it is embedded in, I can know where to drop a new View to exactly overlay it?
Original screen in IB:
Result of the code (new view is semi-transparent; note the yellow band at the bottom):
You can get your label position in view by
let theFrame = view.convert(myLabel.frame, from: your_stack_view_here)
and You should move it to
viewDidAppear
Because
viewWillLayoutSubviews
will call any time subview will layout. That's mind at the first time it run, your "mylabel" didn't layout with correct position.
Apple document
Regarding your question of “how can I get the "absolute" X and Y coordinates of the label in the screen”, the answer is to use UIView.convert(_:to:), passing nil as the second parameter. (This will yield coordinates relative to the containing window's origin, but for practical purposes is probably what you mean by “the screen”).