How to wrap self sizing UICollectionViewCell - ios

My goal is to have a Swift implementation of a UICollectionView with dynamic content where each cell hold parts of a sentence. Each part of the sentence can be edited by the user. The problem is that some parts of a sentence might be longer than the container itself. Using sizeToFit is not an alternative because all content should have the same font size to maintain readability throughout the collection view.
Right now the behaviour I get, when I have a part of a sentence longer than the container is the following:
As you can see the third row has leading ellipsis.
What I would like to achieve is the following, the overflowing part of the cell should wrap as analogous to a span tag in HTML, like so:
Is this possible? How can I achieve such a thing?

As far as I can tell, it's possible but complex - here are a few pointers of what I'd say you're going to need:
2 additional collection view cell types: in the first, only the left edges are rounded, in the second only the right
Use Core Text API to measure where your text needs to be wrapped
In your datasource, you're going to have to then recognize the situation before you create the cells and then instead of creating a single cell, you create two, using those new types you have.

Related

Laying out UITableView contents

The title itself might a bit misleading and I believe the problem is best explained with an example.
Take Facebook's feed, for instance. Every item consists of the following:
Header (user's name, etc), static height
Main content (text, attachment), dynamic height
Footer (number of likes and a couple of buttons), static height
At a minimum, the main content has one of the following:
Title, optional
Textual preview, optional
Attachment (of variable height), usually an image, optional
So, a few possible combinations of parts:
Title
Title, text
Title, text, attachment
Text
Text, attachment
etc
I've come up with two approaches:
1. Sections for each post, cells for parts
Note: the UIKit-provided header and footer wouldn't do, as I need specific spacing between each item. Therefore, I'd use these to get the spacing needed.
Also, I'm using RxSwift. This approach breaks the simplicity of data binding to the table view, although there's always a more complex alternative.
2. Multiple cell types
Not sure. Separate cell type for each possible combination of the above? Seems like an overkill.
3. Single cell type
The easiest approach. But, considering all the optional parts, there's quite a few constraints to switch and tweak (depending on the attachment height). UIStackView is not an option evidently, since the attachment must take the whole screen width, whilst the other parts use custom padding on each axis.
I'm looking for an outside perspective here, mainly from those who happen to have solved a similar problem in the past. An example of code would also be lovely (especially if it's scalable).
Target: iOS 13+.
Will AutoLayout perform alright in each of these?
What approach would you use?

Access child views in custom UITableViewCell

Background:
I am trying to create a table view with around 4 types of different cell layout.
At first, I considered using static table view to solve the issue since the number of rows are somewhat fixed (nor more than 10)
But, after some thinking, I decided that I don't really want to be tied up to the UITableViewController. Thus, I tried to implement it with dynamic table view.
Question:
After I create 4 prototype cells, I found out that I'll need to access the child views in cell (to update their value). But the only possible ways I know seem to be:
1. Create a subclass for each prototype cell, and create `IBOutlet` to the child views
2. Assign `tag` for each child view for later access
But I don't really like these two methods...
The first one is too cumbersome, and the tag in the 2nd solution does't seem to be very sepcific (access the child view by just some magic number..)
So, I would like to know:
Is there any better practice for implementing this kind of
tableview. (multiple cell prototypes, and fixed row numbers)
Is static table view a better way to do it? If yes, will there be
any limitations when I am tied up to UITableViewController?
For example, if I need more complex UI, and decide to add more views on to it, will UITableViewController be less flexible than UIViewController
Thank you so much!
If the cells are very similar but with different layouts they could share a common UITableViewCell subclass provided the class doesn't need to know the layout it is in just configure the available outlets.
If the code does need to be aware of the layout used then it is probably best to make them separate subclasses.
For Swift use is or as? to confirm the correct subclass for the cell (for Objective C it would be the isKindOfClass method).
1.You do need to subclass the UITableViewCell if you want to access his IBOutlets.
In order to distinguish between the cell just use isKindOfClass
2.It depends how different your cell are from one another. If they have slightly different structure you might want to consider lodging the elements in cellForRow. Try to take a look at the built in structure cause it might save you some subclassing.
These structures have built in parameters such as: image,text etc.
Their structure is more strict though
Theses are the available types:
UITableViewCellStyleDefault, // Simple cell with text label and optional image view (behavior of UITableViewCell in iPhoneOS 2.x)
UITableViewCellStyleValue1, // Left aligned label on left and right aligned label on right with blue text (Used in Settings)
UITableViewCellStyleValue2, // Right aligned label on left with blue text and left aligned label on right (Used in Phone/Contacts)
UITableViewCellStyleSubtitle // Left aligned label on top and left aligned label on bottom with gray text (Used in iPod).
I don't really understand why you want to use tags?

TextView(s) or Tableview to work on both paragraphs and single words?

I need to design a view in which:
A lot of text is presented, with variable paragraph length
Specific paragraphs can be called into specific parts of the view (top, middle, bottom) either by the user (search, go-to) or programmatically.
Whenever a paragraph reaches a position in the view (let's say the middle) it triggers an event
Each paragraph can be tapped/selected to trigger events.
Each word in the paragraphs can be selected.
Bonus: the paragraphs are presented continuously, without breaklines (which excludes tableviews).
The text is fixed, and each paragraph is indexed (the data comes from an sqlite database).
I thought of three possible approaches, but each of them have its own problems I could not overcome:
A single textview. This would let me free to format the text the way I want, and work on the single words. On the other hand, I haven't figure out a way to act on the individual paragraphs. I wouldn't mind adding the index number for each paragraph on the side of the paragraph, but I don't know the best way to tag it (HTML?). Moreover i don't think there is something similar to scrolltoposition for anything other than a tableview.
Textviews for the individual paragraphs. I could use the index in the database to label each of them. Yet, as above, I don't think there is something similar to scrolltoposition...
Resizable textviews inside each cell in a tableview. This would let me work easily with the paragraphs and formats, but I don't think the text within the cell is selectable.
Any advice on how to solve those specific problems?
Any suggestion of an alternative way to achieve this?
The best approach, by far, is the UITableView. Everything you have listed is easily accomplished with the delegate methods of UITableViewDelegate, and UIScrollViewDelegate (of which a table view calls). The only issue with the tableview is the fact that UILabels cannot be selected within them. This is easily solved by not using a UILabel, but a UITextView. Simply disable scrolling on the text view, and disable editing (I'm not sure if disabling editing removes the selectability. If it does, override the UITextView and block edits from there).
1. Use UITableView
2. Create UITableViewCell with UIScrollView inside it
3. Override UIScrollView to disable editing
4. Add logic to UITableViewDelegate and UIScrollViewDelegate (of the table view) for the taps and position events
good luck,
ZR

Design for annotating UICollectionView selections with additional controls

Using UICollectionView and excellent help given on here on StackOverflow, I've been able to build a "Gantt Chart" style control for my iPhone:
Cosmetics aside (I'm doing the functional right now, I've got a graphics designer on tap to look at colors and all that).
Background aside, the spans were relatively straightforward to do with a custom UICollectionViewLayout subclass. Each span is an item.
But I need to add some functionality, and am unsure how to proceed. Where I'm trying to go is illustrated roughly as:
Sketchy cosmetics aside, the point is that I want to "annotate" whatever the currently selected span is with additional information (I promise to find someone to help me look it pretty). And I want them to be active, I'm not sure if it brings up an editing control or does drag, but I want to be able recognize gestures on either the numbers or the bold lines and do things with them, distinct from touching on the span which drives selection.
I can think of (at least) 3 ways to try and implement this:
Use supplementary views. Cause selection to invalidateLayout, detect the selected state in my prepareLayout, and generate additional layout attributes for the two anchors. Implement a subclass of UICollectionReusableView which does the drawing, and adds touchable subviews (or its own gesture recognizers). This feels... wrong. I get the idea that supplementary views are more for headers and footers, not for controls that come and go as the selection state changes. But maybe it's an appropriate extension of the facility?
Use the backgroundView (or selectedBackgroundView, not sure it matters) of my current SpanCell class (which is a subclass of UICollectionViewCell). As long as I disable clipsToBounds, I can draw the annotation around the bounds of the span. I'll have to give it some knowledge of the big picture to find the endpoints, but that's not too offensive. I would just show/hide this view in response to selection changes. This seems like the best way to do it.
Do it in the main backgroundView of the entire UICollectionView. As shown, I've already got a specialized backgroundView which shows the the current time grid, strip style. I could further extend this view to draw annotations and manage touchable sub controls in response to selection changes. This would give me most direct implementation, but it feels like I'll end up with a big monster "doing too many jobs" object for the background.
Question then, for those who have more experience, is which route would you go? Would it be one of the above 3? Or something different? And why?
While your question is very technical with UICollectionView implementation, which I am not very familiar with, this seems like a job for the container (in this case, the collection view). Imagine you need your annotation to consider, in addition to the selected item, other items? Like for example, avoiding collision between annotation lines and another item?
For me, option number 3 seems like the most correct one. If you fear a large class, you can extern it to an annotation controller class, which should be notified whenever the annotations should be updated.

horizontally and vertically paging UIScrollView, i.e. multi directional paging

I'm looking for a custom component or mini-framework that is capable of handling multi directional paging! Multi directional by means of supporting horizontal and vertical paging simultaneously!
I'd actually like to display data like a grouped UITableView does, grouped by individual sections and rows. Consider the following data example:
Section-A: row-1, row-2, row-3
Section-B: row-1
Section-C: row-1, row-2
This is obviously a standard use-case for a grouped UITableView and nothing special, right?
What i'd like to acomplish is, displaying the above data as paging views!
So i.e. when i page horizontally, paging is section based and i move from Section-A to Section-B etc.!
When i page vertically, i "page" through the single "rows" of a section etc.! I hope you guys get the point!
Technically this would be obviously achieved by nesting 2 UIScrollViews with enabled paging, restricting the single UIScrollViews by either vertical or horizontal paging. Then populating the scroll-views with data (i.e. views) in the right manner etc.
Another requirement would be to have a dynamic or semi-dynamic behavior! Dynamic by means of having the possibility to add "sections" and "rows" afterwards. Much like the UITableView behaves actually, with "cell" reuse etc.!
(Semi-Dynamic by means that i don't need dynamic "row" insertions/deletions etc., just a simple "reloadData" would be sufficient)
So i looked for example into Andrey Vits ATPagingView of his SoloComponents!
ATPagingView looks like a promising foundation for solving my problems! I thought of extending the functionality to acomodate my requirments but would like to ask for advice on stackoverflow first!
So what do you think on this guys?
Is this actually a use case for a grid component?
Is there maybe a component or framework out there already matching my needs or was there never a need for multi directional paging views until yet! ;)
Right now i'm experimenting with ATPagingView for myself and i find it very useful for its purpose. It provides sort of a endless paging solution with cell reuse and is easy to set-up with only 2 delegate methods.
Why not wrap single ATPagingView instances into one "parent" UIScrollView, where each ATPagingView represents a "section" in your use case! Inside every ATPagingView you would then have pages as your "rows". You could set up the outer (i.e. parent) UIScrollView to page only for example horizontally and the single ATPagingViews to scroll vertically.
You'd need some boilerplate code (i.e. something like numberOfSections etc.) in the outer UIScrollView to manage the "inner" ATPagingViews, but that would be a feasible approach i think.

Resources