How to align subviews horizontally in iOS? - objective-c

In Android, when you add subviews to the horizontal LinearLayout, you would see that all the subviews would be aligned horizontally.
|subview1|subview2|subview3...
In iOS, how do I achieve this?
I have a UIView as the parent view, but when I add subviews, it would get stack on top of each other. How do you use UIView.addSubView such that all the subviews would align horizontally?
One way, that I am attempting now is changing the frames.origin.x of each subviews
for example
subview1.origin.x = 0
subview2.origin.x = subview1.origin.x + subview1.size.width
subview3.origin.x = subview2.origin.x + subview2.size.width
...
Is there better ways? thanks, and would appreciate any suggestions, or comments.

Using the Auto Layout feature, which can be done from the interface builder GUI, or else programatically:
https://developer.apple.com/library/ios/documentation/userexperience/conceptual/AutolayoutPG/AutoLayoutinCode/AutoLayoutinCode.html#//apple_ref/doc/uid/TP40010853-CH11-SW1

Yes, u r doing in right direction - you will have to change view's frame manually. there are convinient API for that:
subview1.origin.x = 0
subview2.origin.x = CGRectGetMaxX(subview1.frame);
subview3.origin.x = CGRectGetMaxX(subview2.frame);
Take into consideration that constraints are available form ios 6.0

Either:
AutoLayout as suggest in another answer if using Interface Builder (Nibs or Storyboards).
AutoResizingMasks by aligning them once and setting flexible top and bottom margins.
Manually by using UIView's center property.
CGFloat centerY = ...;
for (UIView * view in superview.subviews)
{
view.center = CGPointMake(view.center.x, centerY);
}

As of iOS 9 you can use UIStackView, which works very similarly to LinearLayout: you add views and the stack view arranges them as needed based on your sizing option. If you're using Interface Builder you can experiment with each of the options to see which one suits your needs. You can also set spacing between views in the stack view, adding some padding.
For your particular needs, use stackView.axis = UILayoutConstraintAxisHorizontal; to make your views line up horizontally.
WARNING: When adding stack view child views in code you should always use addArrangedSubview() like this:
stackView.addArrangedSubview(someView)
If you try to use plain old addSubview() it won't work correctly, because the stack view won't know to arrange it.
As for removing, you need to be careful to use stackView.removeArrangedSubview(someView) and someView.removeFromSuperview() otherwise the view won't be removed correctly.
You might find my UIStackView tutorial useful.

Related

How to replace a view

Application requires more than one window (Lets call A,B,C). Each window has more than one view (table views, image views as well as web view). Lets say window A has three views (x, y,z) and window B has three views (d,e,f). Application needs to display images of different size on orientation change.
I have achieved the same using gesture event listener and looping through windows for views and replacing the view with new images. The problem I have is when we navigate from one window to other and the orientation changes, the loading of view after looping goes for a toss. Is there a better way to achieve the same ?
Is there a method in titanium like following code to replace a view ?
var self=Ti.UI.currentWindow
var newView=Ti.UI.createImageView({image:'abc.png'})
self.replace(self.children[1],newView )
Unfortunately there is now replace method.
You need to remove the whole view and add it again but this can cause a wrong layout if you have more than one view on a same level. The implementation then depends on the layout which was set (vertical, horizontal, composite etc).
For example in vertical layout removing an item and simply add a new one would remove your specified item but appends the new one at the end since you can't specify in which order it should be added.
If you have a composite layout you can specify absolute positions but adding a new view causes a higher zIndex for this view so that it will hide views that were previously added at the same/similar position.
Why not simply change the image link ?
var self = Ti.UI.currentWindow;
self.children[1].image = 'bcd.png';
Well you could always lock the orientation of your window. But this isnt exactly good practice (especially for iOS).
Generally orientation changes are handled pretty well if you define the width and height of your views to be percentages or Ti.UI.FILL, if you have a composite layout. Check that you are not giving the views absolute coordinates as this could cause layout problems. If you have a vertical or horizontal layout you usually don't have to worry about orientation change, unless you did not nest your views in a main container correctly.
Prasad,
If this is about just ensuring that the images look good on different orientations,you can make use of the different folders provided by Titanium in the android/images folder.You can just make different images for each of the orientations and device sizes.For IOS you can change just the images on orientation change as you are already doing.
https://wiki.appcelerator.org/display/guides/Using+density-specific+resources+on+Android
If you are concernced about the layout there are couple of things you can do:
1.Give all the height or width values in percentages.This way all elements will be re sized once the orientation changes automatically.
2.On each window open check if the orientation is vertical or horizontal by default and accordingly set the image attribute of the imageView.
Ti.UI.orientation
This property will give you the orientation of the window by default.Values of this property could be this
Ti.UI.PORTRAIT
Ti.UI.UPSIDE_PORTRAIT
Ti.UI.LANDSCAPE_LEFT
Ti.UI.LANDSCAPE_RIGHT
Use "if else" and accordingly set the images.

UITableView floating view like iPhone Maps app

In the iOS 6 Maps App, when looking at the details for a location, there is a control that acts like a UISegmentedControl. It has 3 "tabs": 'Info', 'Reviews', and 'Photos'.
This control scrolls up and down when the picture is visible, but becomes anchored to the top of the screen and floats when scrolling down more. These pictures may help clarify what I'm trying to state:
Any tips on how I can create this behavior on my own UITableView? The tableview needs to be of the Grouped style, and I need to have multiple sections, so using the Section Header View is out of the question.
make use of the UITableView's tableHeaderView property to add your segmented control.
MapView and TableView should be siblings, and added as a subviews to a scrollView.
The tableView.frame.size.height should be what you see in the image2 (parentViewHeight-navBarHeight)
scrollView.frame.size.height = tableView.frame.size.height
scrollView.contentSize.height = tableView.frame.size.height + mapView.frame.size.height
this should be enough to get the effect you are trying to do. let me know if you have any issues with it.
PS: mapView is just a place holder I assumed for the view you see above the segmented control. you can replace it with any view you want. I am assuming you know how to do the grouped tableView part of these views.

iOS stretch image to full screen

I have a scroll view with a image view inside. I was wondering whether it's possible to have the image inside the image view be much smaller than the resolution of the screen, and somehow be able to stretch it to fit the screen.
Set contentMode on the UIImageView and change its size.
[UIImageView setContentMode:UIViewContentModeScaleToFill];
Check the docs for more informations regarding UIViewContentMode:
http://developer.apple.com/library/ios/#documentation/uikit/reference/uiview_class/UIView/UIView.html#//apple_ref/doc/uid/TP40006816-CH3-SW69
Sure, just change the bounds of the imageView.
Am I missing something here?
Your UIImageView is within an UIScrollView I understand?
That would work by adjusting the scroll view plus adusting the image view appropriately. However that is not advisable to do. You will get lost in small errors with annoying effects.
I'd suggest to add an additional UIView that can match the bounds of the screen.
Add that view to the underlying "view" object and use the bringSubviewToFront method.
You could as well make sure that this new UIView is the first subview of the most underlying view object. You could achieve that by manipulating the subviews array structure - which I do not recommend in general wihout having fully understood everythng about the view hierarchy.
You can as well achieve that by adding the additional view at first before adding any other view. (Within IB just make sure that the new view is the topmost in the tree, coming next to the view controllers "view".) And then make it hidden until you actually need it. Then you unhide it. When it is not needed anymore then hide it again and neither delete it nor erase it from its superview.

How to make a shadow between two table views?

I have two table view controllers. How can I make shadow like this?
Take a look at CALayer class from CoreAnimation framework. Here is a nice tutorial with examples: http://nachbaur.com/blog/fun-shadow-effects-using-custom-calayer-shadowpaths
Then you apply the shadow to the right tableview(however, it might be required embedding the tableview in container view)
The easy way if you don't know about core graphics is to make a gradient png and position/size it to the right of your cell, under everything else.
In UIBuilder, select the view containing the table. You may need to play around with the exact level of what you select. On the far right in the inspectors, is the View Effects inspector. There you can set a shadow, including the blur radius and offset. If you just set the shadow without either a blur radius or an offset, you won't see the shadow, since it will be directly behind your table.
You can create a drop shadow easily, using QuartzCore.
Code:
#import <QuartzCore/QuartzCore.h>
UIView *myView = <your view here>
myView.layer.shadowOffset = CGPointMake(5, 5);
myView.layer.shadowRadius = 5.0f;
That should do it.
Please note that, when setting the shadowOffset, using positive values will drop to the right and bottom, using negatives will do the opposite.

float:left in objective-c

I'm trying to make a bunch of buttons behave somewhat like float:left in CSS.
So whenever the view changes size, on orientation change for example, the buttons should adjust so they fit within their container view.
In landscape mode, this UIScrollView should scroll horizontally, in portrait mode, it should scroll vertically.
I'm trying to make an ScrollView similar to the "Featured" tab in the iPad YouTube app. Landscape has 4 columns, portrait: 3 columns, "Subscriptions" tab, portrait, the same view has 2 columns.
I have implemented a layout system to do things like this. There is a demo project on how to use it checked into that repository. I'd be happy to answer any questions about it. This is much more lightweight than AQGridView, so if you don't need the extra functionality he is providing, I would recommend an approach similar to mine.
you might want to check out AQGridView, which is basically a re-implementation of Cocoa's NSCollectionView: https://github.com/AlanQuatermain/AQGridView
Otherwise, you might need to override layoutSubviews in your parentView and then rearrange the subviews (buttons) accordingly when the dimensions of the parentView change.
Cheers,
Johannes
If you had to implement this manually (by overriding layoutSubviews), I think the algorithm would be something like this:
Start with X = 0, Y = 0 (assuming flipped coordinates)
For each button:
If (X + button width) > container width, set X = 0, increase Y
Place button at (X, Y)
Increase X by button's width