How can I use Autolayout to create a layout that expands in height based on the content of a UILabel - uilabel

I am attempting to build a dynamic layout using the new autolayout api in iOS 6.0. The layout that I am attempting to build has 2 buttons with a label inbetween them as shown in the image below:
What I would like is for the container view shown in grey to increase or decrease in size depending on the amount of text in the label.
So far I've managed to get the layout to work exactly as described with one small issue that I've not been able to resolve. The problem I am having is that the intrinsic height of the label is alway calculated with the original width of the label (e.g. the one set in interface builder) and not the width of the label that is set from the constraints I have on it.
The constraints that I have on the views are as follows:
H:|-[leftButton]-[label]-[rightButton]-|
Both buttons are centered Vertically
V: |-[label]-|
the content hugging priority of the buttons is higher than the label
the compression Resistance of the label is higher than the container view
All of these constraints together create the desired layout.
However:
If the Width of the label in interface builder (the literal size in interface builder) is less than the width of the view at runtime, then the height of the container is too large.
To help clarify this, the IB view of the above layout was as follows (note much narrower)
If the Width of the label in interface builder (the literal size in interface builder) is greater than the width of the view at runtime, then the height of the container is too small and lines of text get cut off.
What appears to be happening is that although there is no constraint on the labels width, the label seems to calculate its height (and thus the autolayout calculated height of the container) based on the original width of the label when it was created. However whats so strange is that the text appears to be the correct width and height but the label itself has a frame thats just too big or small.
I guess this is related to the order in which things are happening, and have tried calling updateConstraintsIfNeeded in the containerViews layoutSubview method however this doesn't appear to do anything.
Any suggestions would be greatly appreciated.

May be I am late but any way I've found solution. Any time when label width is changed you need to manually update preferredMaxLayoutWidth for Label. For example:
Label.preferredMaxLayoutWidth = 200;
Interface builder sets preferredMaxLayoutWidth with initial label width.
Hope this helps.

Have you tried calling -invalidateIntrinsicContentSize on your label?

Yes, -invalidateIntrinsicContentSize can also be used for this.
Make a Custom Class like 'CustomLabel'.
Set this Class for UILabel in interface builder.
Override the functions which returns the IntrinsicContentSize
-(CGSize)intrinsicContentSize {
//If the width is Zero.
if (self.frame.size.width == 0) {
return [super intrinsicContentSize];
}
return [self.text sizeWithFont:self.font constrainedToSize:CGSizeMake(self.frame.size.width, MAXFLOAT)];
}
Inform the system, to reCalculate it's Intrinsic Size by calling the method.
[CustomLabel invalidateIntrinsicContentSize];
Hope this would help.

Related

Codenameone Slider cannot set height

I am finding it difficult to set the right look and feel of a CN1 Slider control. Essentially i want it to look like the one in the CN1 Default Demo of the Theme window, and have it with the Thumb image to allow the user to set the scroll.
But when i code it up as per online examples, it comes out skinny on the simulator (as below)
...but doesn't display the line at all on the actual iphone device.
When i start messing with the methods, such as 'getSliderEmptyUnselectedStyle()' then this makes the background show and can see the progress but its tall and i cannot seem to shrink it.
Container container = new Container(new FlowLayout());
container.getAllStyles().setBgTransparency(255);
container.getAllStyles().setBgColor(0xffffff);
Slider slider = new Slider();
// slider.getAllStyles().setFgColor(0);
// slider.getAllStyles().setMarginLeft(0);
// slider.getSliderEmptyUnselectedStyle().setBgTransparency(255);
// slider.getSliderFullUnselectedStyle().setBgTransparency(255);
// slider.getSliderEmptySelectedStyle().setBgTransparency(255);
// slider.getSliderFullSelectedStyle().setBgTransparency(255);
// slider.getSliderEmptyUnselectedStyle().setBgColor(0xffffff);
// slider.getSliderFullUnselectedStyle().setBgColor(0x42B72A);
// slider.getSliderEmptySelectedStyle().setBgColor(0xffffff);
// slider.getSliderFullSelectedStyle().setBgColor(0x42B72A);
Style sliderStyle = UIManager.getInstance().getComponentStyle("Label");
sliderStyle.setFgColor(0);
slider.setThumbImage(
FontImage.createMaterial(FontImage.MATERIAL_RADIO_BUTTON_CHECKED, sliderStyle, 4).toImage());
slider.setMinValue(0);
slider.setIncrements(25);
slider.setProgress(entity.getCompletion_pct());
slider.setEditable(true);
container.add(slider);
return container;
How can i get it pretty much to the CN1 example?
Thanks
The slider in the example used a 9-piece border or a 3-piece border both of which have a fixed minimum height/width. This minimal height is applied to the way the slider is rendered.
Your code can be made thicker with padding but it will create a problem when you add a thumb. Once you add the thumb it will increase the overall size and make the entire height of the thumb have that background. So you need to style this via the designer and for this specific case you would want to use an image border that is carefully measured to align with the thumb image.
Also notice you used getAllStyles() which is wrong. Slider is a special case and uses the Slider and SliderFull UIID so effectively the component has two UIID's and two separate sets of Style objects.

IOS 7 Approach for create container with two elements?

So, i am new to xcode and iOS7 and i'm trying to create simple container with two elements inside.
I prefer to make it 100% programmatically. (no IB)
I want to create container with two elements Image and Label.
I want to achieve variable width depends on the text element inside.
Here is example:
Based on user action i want to change text on the fly. Let's assume longer text, and main container have to change width too.
And now the question is: What is best approach to to that?
UIView with subviews or something else i'm just expecting direction.
Code examples with be gratefully appreciated.
Thank you in advance.
What you have described is exactly what a UIButton does automatically: it is a container containing an image and a title (text) and it resizes itself automatically when the text changes.
Let us assume, however, that you want to do this yourself. That is, let's say you want a UIView ("container") containing two other UIViews (subviews). Then we need to discuss this requirement:
Based on user action i want to change text on the fly. Let's assume longer text, and main container have to change width too.
This is not going to happen automatically. You can use constraints (auto layout) to describe the size / position of the subviews in relation to the superview, but it works the other way: the superview changes, and the subviews obey. So you will have to change the superview size manually after you change the text.
You can still use auto layout to help you. Let's say the text is in a UILabel. Well, a UILabel wants to change width automatically when the text changes. So far so good. But you must still change the container view width yourself. You can call systemLayoutSizeFittingSize: to learn what the size of the container should be, using constraints, working from the inside out; but then you will have to change its size yourself to that size.
(You can easily create the view, the subviews, and the auto layout constraints in code.)
If you don't want to use autolayout, then you will just calculate the sizes and positions of everything when the text changes and adjust it all yourself (in code). You can learn the size the label needs to be, to fit its text, by calling sizeThatFits: (or sizeToFit which will actually resize it correctly).

Objective C: Adaptive Toolbar On Orientation Change

I am having a problem with my toolbar when i change the orientation of my iPad.
i set my nib file into landscape and everything is all right but when i turned it to portrait my toolbar still has the width from the landscape orientation.
how will i make my toolbar adaptive to the orientation change to portrait?
Landscape:
Portrait:
thanks!
Try adding UIViewAutoresizingFlexibleWidth to the toolbar autoresizingMask like so:
myToolbar.autoresizingMask |= UIViewAutoresizingFlexibleWidth
Or, if your doing this in the Interface Builder, make sure this horizontal bar is selected (others may be selected as well, which is fine):
More from the UIView Class Reference about autoresizingMask:
When a view’s bounds change, that view automatically resizes its
subviews according to each subview’s autoresizing mask. You specify
the value of this mask by combining the constants described in
UIViewAutoresizing using the C bitwise OR operator. Combining these
constants lets you specify which dimensions of the view should grow or
shrink relative to the superview. The default value of this property
is UIViewAutoresizingNone, which indicates that the view should not be
resized at all.
When more than one option along the same axis is set, the default
behavior is to distribute the size difference proportionally among the
flexible portions. The larger the flexible portion, relative to the
other flexible portions, the more it is likely to grow. For example,
suppose this property includes the UIViewAutoresizingFlexibleWidth and
UIViewAutoresizingFlexibleRightMargin constants but does not include
the UIViewAutoresizingFlexibleLeftMargin constant, thus indicating
that the width of the view’s left margin is fixed but that the view’s
width and right margin may change. Thus, the view appears anchored to
the left side of its superview while both the view width and the gap
to the right of the view increase.
If the autoresizing behaviors do not offer the precise layout that you
need for your views, you can use a custom container view and override
its layoutSubviews method to position your subviews more precisely.
In addition to adjusting the flexible width of your toolbar you could create 2 arrays of toolbar items. One for portrait and one for landscape. Fortunately you only have to create the toolbar items once and just add them to the appropriate array(s).
Then during the orientation change you can set the toolbar's items array to the appropriate one.
Good Luck

Setting ScrollView Height

I have a window. That window has a header (variable size) and should have a scrollable body that sits directly under the header. How can I set the height of the body so that it actually scrolls? If I set height: 'auto', the body extends beyond the bottom of the viewport to fit all of its content. If I set its top and bottom properties, nothing shows up at all.
I can't imagine that I'm the only one who's come across this, but I haven't found a single definitive answer for how to create properly sized, scrollable view within a window. Heights seem tricky since the value is so different in portrait and landscape modes on a single device, much less across devices.
Can someone provide tips on how to manage this scenario? I'm hoping I can extrapolate it to handle other view height scenarios.
Thanks.
It depends on what you are trying to achieve. If you're trying to create a ScrollView that just has the ability to scroll when empty, you should add a empty View into the ScrollView, which has the "top" property.
For example:
var win = Ti.UI.createWindow();
var scrollView = Ti.UI.createScrollView();
var emptyView = Ti.UI.createView({top: 460});
scrollView.add(emptyView)
win.add(scrollView);
Note that the "top" property has 460 set, which is 40 bigger than the iPhone screen res of "420". This will case the scrollView to scroll. If you're looking for a specific size based on the window's navBar controlTitle, you will have to run an equation based on what you think the size will be, applying that size to the view's "top" property accordingly.

Way to return bounds of non-hidden elements in UIView

Right now, I have a UIScrollView which scales its UIView contents on zoom events. When I hit a certain zoomScale threshold, I want to be able to toggle on and off extra information within the UIViews. Right now, I am simply setting the hidden flag to YES/NO to accomplish this.
However, a problem occurs while attempting to get the bounds of the UIView. The bounds always returns a width and height that extends to include the invisible content.
Is there a way to limit the bounds to only return the size of visible content within a UIView?
You could derive new bounds as you zoom and not rely on the view's automatic bounds adjusting.
OR
If it doesn't make your code too complicated, I would remove those subviews from your resizing view instead of just hiding them.