I am implementing a custom map view in which I want to add multiple UILabels over an UIImage. Below is the view hierarchy:
When I preview it on iPhone & iPad, UILabel stays relative to the SuperView but I want to stay it relative to a point(x,y) in UIImage so that whatever be the the device, the label should always be with Groovy room.
I can draw text on UIImage, but it is a very costly operation in my scenario as my View will be loaded once & I need to update the label frequently.
Below is the current UI:
As shown, label doesn't stay in Groovy room & goes out of the way.
You need to pin the UILabel to the leading left and top of the UIImageView you wish it to layout relative to. Set the pin offsets to be the relative x and y you wish.
Updated after comments
If you have one big image that will fill the screen and you want to position multiple labels, I think you are going to have to do the positioning in code. The reason I say this is that for different screen sizes you need to change the point the image is shown at.
Suggestion is|
1) For your map, create a table containing the relative position for the centre of each room. E.g. Centre of Room 1 is 25% across and 10% down. Put then in an array. You now have a way of defining the centre if each room regardless of screen size.
2) In your viewDidLoad method, create your UILabels and put them in an array indexed by room number. Add the labels to your main view. You could do this in storyboard if you have an exact number and assign IBOutlets you can put in an array.
3) Implement layoutSubviews and in there set the centre of each label to be the centre of the room plus an offset so it shows below the room label. Call super version first. Use the centre property of the UILabel frame to make this easy. Doing this in layoutSubviews should work around any issues with constraints the system adds itself.
This should let you handle labels for all screen sizes as you are coding the label positions as relative to the image. When running you are converting this relative position to actual points.
Related
I'm working with a custom UIableViewCell that has four UILabels inside of it.
What I'm currently struggling with is that for smaller iPhones, I'm able to get the correct portrait layout (the numbers correspond to the label numbers).
What I'm trying to do for larger iPhones (screenshot below is from a 6SPlus) is have label 3 move in the direction of the arrow:
I have three constraints for the third label. My thought was to have one of them set with a priority of 1000 to be the "base constraint", and another, set at 999, to change the spacing of the cell:
However, it doesn't seem to have any effect. How can I alter the position of the third label using constraints based on the size class? Thanks!
EDIT: This is an approximate illustration of what I'm trying to get to:
Use a UIStackView and put your labels inside it. The stack view can be configured to distribute evenly your four labels, putting the same amount of space between them regardless of how the width of the table grows or shrinks as it launches on a bigger or smaller phone. Thus, you'll look great everywhere.
(If you're not able to use UIStackView, you can achieve the same effect of even distribution using invisible spacer views.)
Summary
I'm making a receipt screen in my current project, this screen can be viewed in portrait and landscape. I've finished putting a constraints in portrait and it look like this:
. Now, in landscape it should be like this:
Problem
(1) In portrait, A1-A3 is center aligned but in landscape it should be left aligned (value of A1-A3 is dynamic, can be long or short text). So, can I add a constraints to put the alignment from center to left programmatically or is there any other way to do this?
(2) Notice in landscape that parentView of View A, B, C becomes one, is this doable? UIImageView must be put below View B
What I've tried
(1) Only system font family and size can change when in different size class using IB, if UILabel is center aligned it'll be center in all size classes
(2) I'm getting an error when moving UIImageView from View B to View C. It seems that if you move one view to another, it will be permanently moved in all size classes
For the label alignment, you'll have to update it in code. You can detect when the size class changes by implementing traitCollectionDidChange: on your view controller or a custom view.
For the image, one approach is to not make the image view a subview of B or C. Instead, make it a subview of the root view, but position it over B and C using constraints. Example:
Notice in the document outline that Image is not a subview of Green; it is a subview of the root view. Since Image comes last in the list of subviews, it is “in front of” or “closer to the screen than” the other views.
Image has constraints installed for wAny/hAny to position it with Image.centerY = Green.centerY and Image.trailing = Green.trailing - 20.
Now here is the wAny/hCompact size class:
Now the constraints that put Image on Green are not installed. Instead, I have installed constraints for wAny/hCompact that set Image.centerX = Blue.centerX and Image.top = Blue.top + 20.
Here is a demo in the iPhone 4s simulator:
I implemented a viewcontroller similar to the one in this question:
iOS two views cover exactly half of parent view
I get the desired result. The problem is that when I add a UIImageView into those two containers, the result get resized and ruins the symmetry. How do I prevent Imageviews from changing the size of their containers? I need to use AspectFill for these images.
I don't think the containers' sizes are changed. You just need to set their clipsToBounds property to true to avoid overflow.
If you use Reveal you should see the containers' sizes are not changed even if pictures inside them are bigger than themselves.
I'm unsure I understand what you mean about adding UIImageView into those controllers causing the views to resize, so forgive me if I'm getting this all wrong...
It sounds as though you've created two views of equal height that, together, consume the entire vertical space of the screen. After having done that, you want to add one or more UIImageView's to each of the original two views. Unfortunately, when you add the UIImageView, the enclosing view is resized.
Assuming I have that correct...
Are you doing this with Interface Builder either in an XIB or Storyboard file? If so, you ought to be able to achieve this with the proper set of constraints.
In the following image, I've laid out what I describe above.
As you can see, I have a red view on the top half of the window and a green view on the bottom half. The red view contains a UIImageView that is 75% of the width and height of red view, with its origin at (20, 20) within the red view.
The scene is configured as shown below:
The constraints on "Upper View" are:
You can see from this that Upper View is flush with the left, right, and top of its superview, and that its space to Bottom View is 0. You'll have to trust me that Bottom View is set up the same way.
The height of the Upper and Lower views is "Proportional" as shown in this constraint:
To achieve this "Proportional" setting, you first make the height of Upper View equal to the height of the superview, and then edit the constraint, changing "Multiplier" from "1" to "0.5."
The height (and width) of the Image View is proportional to that of the Upper view, as shown here:
If you set it up this way, you ought to be able to accomplish what (I think) you are looking to accomplish.
If my original assumption of what you are trying to achieve is incorrect, please post images of what you've got and how it's not working.
I have a setup like this in the interface builder:
(iphone5 size). I want the buttons to stay in that layout if the screen size increases i.e widens (but the buttons stay the same size). If I pin the top two buttons to their respective container edges when the screen is larger they will be too far apart from each other. I have the bottom button increasing its size fine. How can I do this? I tried putting a transparent UIView between each button and the container edge, but couldn't get it working this way. Could someone give me a pointer on how to do this please? thanks!
Assuming you already have the width, height and y-constraints in place, to create the correct x-constraints you can try something along the lines of this:
check the Horizontal Center in Container option
choose your button and double click the newly created constraint Align Center X to
change the Second Item from Center X to Trailing
enter a constant value to offset the position
Do this for both buttons. The constant value of the second button should be the negative of the first one AND its Second Item should be Leading.
Result
This method will result in equal spacing on all size classes.
The only drawback is that the spacing is no dynamic. for that purpose you would need some placeholder view in between.
I would say there are two approaches you could take:
Assumption is buttons have constraints for width and height.
1) Use a transparent view which you center horizontally within its containing view. Then pin the left buttons trailing edge to the transparent view and the right buttons leading edge to the center. You have a choice as to how to define their vertical position.
or
2) Add a transparent container view to your main view and then move your two buttons inside this view. Pin the two buttons apart the desired width and then pin the other button edges to the containing view at size 0pts. Finally center the new containing view horizontally in the view. You will need to define the height of this container view from the top or bottom.
The second is probably easier to execute within storyboard.
Here are two labels stacked directly on top of each other, with their backgrounds colored:
I always design my apps in Photoshop first. That dead space on the top and bottom of the labels makes it extremely difficult to position text precisely as in the design. How can I compensate for that top and bottom space when I want to place the label by top or bottom of the text?
Try calling -sizeToFit on the label in order to resize it.
Call this method when you want to resize the current view so that it
uses the most appropriate amount of space. Specific UIKit views resize
themselves according to their own internal needs. In some cases, if a
view does not have a superview, it may size itself to the screen
bounds. Thus, if you want a given view to size itself to its parent
view, you should add it to the parent view before calling this method.
Either use AutoLayout to size your labels exactly at the content size, or use sizeToFit in code and position your labels accordingly.
Can you not create a background UIView with the background colour, and then add the label as a subview of the background view?