I'm trying to implement iPhone and iPad versions gracefully. They're essentially the same controller, but one the iPhone presents in a single column tableView and the iPad in a multi-column collectionView.
Here are the options I thought of:
One ViewController that asks for a different DataSource and different Delegate for tableView vs collectionView. I haven't thought this option all the way through. It does seem like it might get overly complicated.
One baseViewController and then 2 subclasses, one with a tableView and one with a collectionView. Similar to option #1 but using subclasses. Option #1 is cleaner, but this would be easier to implement.
Just use a collectionView for both, but use different UICollectionViewFlowLayouts. This was the last option I thought of and seems like by far the best option, but I'm wondering if there's a reason why #1 or #2 might be better.
So I ended up going with 1 UICollectionView, and IMO it works great.
I had to write conditionals for only 3 parts:
Returning different collectionViewFlowLayouts
Returning different sizes for collectionView:layout:sizeForItemAtIndexPath:
Different layouts for layoutSubviews of the UICollectionViewCell
Being able to use the same UICollectionViewCell was a really big plus since I am implementing a number of buttons within the cell, and I didn't have to replicate delegates for exactly similar logic in a UICollectionViewCell AND a UITableViewCell.
Related
When should I use which, and what are the disadvantages or disadvantages of each? I'm mainly confused with scrollview vs collectionview, I know tableview is limited to one column (I heard it gets messy when more than one column), but scrollview difference with collectionview seem the same to me.
Both CollectionView & TableView are basically subclasses of UIScrollView.But as compared to UIScrollView here you are provided with proper methods to provide your dataSource & delegates to handle operations user performs on data. Along with this you are provided predefined layout classes.
Now to choose between them completely depends on your UI Requirements. Suppose you want to display just a list of items with a simple UI go with TableView.If you want a custom Layout like a grid or like the one you see in Apple's photo's app CollectionView is the choice.
if you have a complex UI & you have no idea about Custom CollectionView layout classes go with scrollView.
Consider UITableView and UICollectionView first and if you cannot achieve the effect you want with them, try UIScrollView then. UIScrollView is more basic class. UITableView and UICollectionView have more delegate method for us.
If you want a list,UITableView would be better. And if you want a multicolumn,use UICollectionView.
Problem
I have a UICollectionView initialised from code and I register a custom class for its cells. The custom class has a few UIStackViews to lay out a bunch of UILabels and UIViews.
One of the arranged subviews should contain a variable number of UIViews. To make this less abstract, let’s think of them as “seats" that will display faces of users attending this event (can be up to four, can be none)
Solutions that come to mind
(I’m a novice)
Solution 1
Have the custom class lay out all the "seat" UIViews so I can treat them as placeholders;
Have the UICollectionView’s cellForItemAt method iterate over the data source and unhide the “seats” that have been filled
Solution 2
Make sure that the UIStackView in the custom class can be referenced from UICollectionView’s cellForItemAt method
From cellForItemAt use addArrangedSubview to add all the needed “seats”
Solution 3
Register 5 different classes (zero “seats” to “four seats”)
Dequeue each one as dictated by the data source
This one seems to me like the least dignified, but might be the one with least performance penalty
I'm perfectly aware that there could be more, and better, solutions. So, what would be the optimal way of implementing this variable number of UIViews, and why?
EDIT:
While I think that the layout of the cell here is irrelevant, it's been requested that I post it
so here it is...
I propose Solution 3, as it will be much more performant.
Also, I have two advices:
Avoid using UIStackView, as it has slow layout performance (it is based on AutoLayout). Also, try to avoid AutoLayout in UITableViewCell and UICollectionViewCell for better performance. Here are some of the most popular and powerful open source layout libraries PinLayout, LayoutKit.
You can write base UICollectionViewCell, move all of the relevant logic there, and then just make all the needed subclasses with minimal logic overriding.
For creating a login page or something like that, in autolayout case I use tableView instead of using a scrollView in viewController. For IndexPath majority cases I reuse the customCell. For entirely different items only I use another customCell. Since the Cell Class are increasing in my project. I dont know is it a good practice. Please share your opinion to increase the overall performance and least memory usage for my application.
Putting UITableView in all views is not a good practice every time.
I recommend using scrollviews and content views inside them in pages like login.
Use Tableviews only in those screens which show repeated contents.
I have seen codes generated through tableview controllers in every page.
I dont do in that way.
Better you go for Scrollviews.. Its a good method as far as I have seen.
I'm trying to develop a universal iOS app and ideally I'm trying to get as much code re-use as possible.
I'm using storyboards so the UI is segmented into scenes.
In the iPhone storyboard the particular scene in question is best suited to a table view.
In the iPad storyboard, the equivalent scene in the storyboard would ideally implement a UICollectionView and so render the content in a grid.
Both views should implement a pull-to-refresh control which in one case is going to call a [UITableView reloadData] and in the other a [UICollectionView reloadData].
Anybody any advice on how to get the maximum amount of code re-use, ie. what does the controller class look like?
1 option would be to have 1 monolithic class that conforms to both the UITableView protocols and the UICollectionView protocols but this doesn't feel right.
Another option would be to have a base class and then subclass it with specialisations for iPhone and iPad. Whilst this feels cleaner, I'm still thinking there might be a better way. In my first attempt at this it felt like there was more code in the specialisation classes than there was in the base class.
The third plan I've considered is simply to use a UICollectionView in both apps therefore eliminating the complexity of the controller. Hopefully I could force the layout of the collection view to be a grid on the iPad whilst tell it to mimic a table view on the iPhone.
Whilst on the face of it this sounds easy I'm struggling to make a UICollectionView work exactly like a table view would do normally.
Any advice guys?
Many thanks,
CA.
If you are not using some of the specific UITableView features[1], making UICollectionView look exactly like a table is trivial. I think I would go for using UICollectionView as it will allow more flexibility in the future and you will have to use it anyways.
When you are talking about code reuse you probably mean the DRY principle. It just says you should not write the same code or the same information twice, but I don't think this is your main issue here.
I would use a UITableViewController on the iPhone and a UICollectionViewController on the iPad. I think this is the cleanest and easiest way to go. What exactly do you hope to reuse among both controllers? The both require two different delegate protocols, so most of the methods will be specific to one platform. You will need two NSFetchedResultsController if you're using Core Data, but reusing the fetched results controller code only makes sense if you need the same data on both platforms.
If you create a new universal project in Xcode you will get a basic project setup that looks different on iPhone and iPad. Try to understand it (there are some details to pay attention to) before you start programming, I think it will answer at least some of your questions.
I am trying to build a custom UIPickerView replacement class mainly for learning purposes but with a view to implementing this within an application I am developing. I have put a lot of time and effort into the UI of my application and now the default UIPickerView just doesn't fit right.
I saw this Dribble mock up of a really slick looking date/time picker but realise that theres not a chance in hell that UIPickerView can be customised this heavily without some major hacking.
After a whole lot of reading and investigation, I have found that UIPickerView uses UITableViews for it's components rather than a plain UIScrollView as I had first assumed. This is confusing for two reasons:
Customising UITableViewCells is a major pain in the derriere. It's not that it's hard work, just laborious and rarely yields the required result. Somehow UIPickerView manages to pull this off though with very little overhead. I would assume that each row in a component just uses UITableViewCellStyleDefault with a custom view for it's contentView but you know what they say about assumptions.
The second thing that is throwing me off is that UIPickerView conforms to the UITableViewDataSource protocol, but not the UITableViewDelegate protocol. This seems a little odd as the delegate is responsible for providing the correct height via – tableView:heightForRowAtIndexPath: UIPickerView however does allow you to set the size of a component via – pickerView:rowHeightForComponent:
In line with this, it also seems a strange choice to utilise a table view as natively these do not "snap" to a specified row the way a scroll view would with pagingEnabled.
Can anyone offer up an explanation of why the default UIPickerView doesn't conform to the aforementioned delegate? Would it be easier for me to implement my custom picker with a UIScrollView instead or should the UITableView provide the functionality required?
UIPickerView actually conforms to UITableViewDelegate protocol but just does not expose that in public headers. You can check that yourself using class_copyProtocolList function.
Using UITableView internally makes it much easier to implement pickers with large amount of rows as UITableView provides great support for reusing cells, otherwise Apple would need to reimplement that logic once again for picker - that would not make much sense (sorry I don't see any big problems in customizing UITableViewCell for this case, so it is hard to comment on that)
As UITableView is UIScrollView subclass you can make it "snap" to a specific position, check scrollViewWillEndDragging:withVelocity:targetContentOffset: method in UIScrollViewDelegate protocol that can be used for exactly that purpose.
Custom UIPickerView are done by mimicking it's behavior using an UIViewController subclass containing as many UITableView you need for fields.
Eg: if you want a time picker, use 2 tableviews
You should style them in a xib using images and such.
What's -kinda- hard about reproducing the behavior is the part where UIPickerView "snaps" to the closest cell, and especially getting it right.
Also, cells in a UIPickerView are simple, just no borders/delimiters between cells, text label is centered, and voilà. What you see are just images overlaid in front of the UITableViews.
As to why it doesn't fully conform to the UITableViewDelegate, it's because in fact, it's a lightweight UITableView that snaps automatically that is used internally in UIPickerView. Thus, it lacks some delegates that are not specially useful for this.
But I guess we all agree on one thing: Indeed, building custom UIPickerView is a big pain and should be easier.
Take a look at this component, looks quite nice, though I haven't tested it myself. computerlogicx/AFPickerView
I managed to implement an "alternative" UIPicker by extending UICollectionView.
Although UICollectionView is usually used for cases where you have multiple items in a section, you can just have one item and it works fine. If you enable paging you get similar behaviour to a UIPicker, but it has a "stickier" scroll that only lets you scroll one item at a time, which might be better if that is what you want. Furthermore, you can scroll vertically or horizontally. You could even have a 2D picker with some extra code.