Design for annotating UICollectionView selections with additional controls - ios

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.

Related

Swift Animation Similar to Line Chart

my question can be a little bit confusing, however I will do my best to explain it. So I need to create a view like below in the image, which looks like a line chart.
In other words, the line thumbs should be interactive, so that user can move them up and down, which will led to the movement of "ropes" between each pair. The problem is I can not figure out to start what kind of structure in swift so that I can create this view. So far, I am thinking about to create separate sliders and connect them by drawing, lines between them, but I think there should be some better solution. Any help, idea, advice or hint is appreciated. Thanks in advance.
Part 1. Learning to use "drawRect" in a UIView
Make a custom view, i.e. subclass UIView. To draw the nine angled line segments (and indeed the grid behind) you'll need to master core graphics. Fortunately there are many of QA on this very topic:
How to draw a line in the simplest way in swift
Part 2. Custom layers in UIView
You'll have to learn about adding custom CALayers to views. There are many examples of this, eg
https://stackoverflow.com/a/57465440/294884
https://stackoverflow.com/a/41553784/294884
(Note that for the small text labels, I would probably simply add many UILabels programmatically, which you will also need to learn about.)
Part 3. Using UISlider
There's really nothing wrong with using a UISlider for each of your red dots. If you're just getting started with iOS, I suggest trying that first to become familiar with it.
A handy tip is, simply use a horizontal stack view to hold them all - you can space them as you wish.
Part 4. Using gestures
Beyond UISlider. The red buttons would most likely be custom UIViews. And, most simply, you would use UIPanGestureRecognizer to detect the finger moving.
Again you can find many QA on this field of study, example Move UIView within parent view using pangesture
If you master these four general fields you will be able to achieve the view in question, good luck!

XCode autocomplete

I'm new to IOS development, I have a few questions.
1) What's the purpose of property rowheight on table view cell, I mean it does nothing even if I change its value, it always takes the value from its parent view i.e a tableview property rowheight? It visually changes in the IB but nothing happens when I run the app.
2) What's the purpose of Content View why is it even there? Let's say If I have to make some image equal to the height of the cell it restricts me. Or is there any way a content view can be changed to be equal to the cell height & width? I have to put constraints on the image in relation with the cell which is not the immediate parent of the image and I don't know if this is the correct way to do it.
3)How does Xcode Autocomplete works? like if I want to write a function tableview(_:tableview didselectrowwithindex:IndexPath) and I type tableview it shows a list, what to do next? I mean I can't type the whole fucntion with params or find the func in the huge list.
The height of the cell set at the IB is primarily used for simulation, the views described at IB are normally resized when actually used. E.g. you can set rows height to be 100 for the table view, 30 for some of the cells and keep the whole controller simulating a nice screen of iPhone 6. The same view will be used for all devices and will be scaled accordingly as well as the cells with the help of your delegate.
The content view is there for the reasons directly related to your additional requests. It holds all the content while there other views that accompany your content and are part of the cell like separators, accessory views, slide action views. Without a content view the responsibility of managing all the additional parts would most likely fall on you as a developer and while you might think that that is fine at the simple layouts, a simple enhancement to it would make a huge impact.
Fuzzy autocompletion at Xcode seems to be something Apple is working on now. If you can't wait and find it too difficult to navigate through the list, there are Xcode plugins available that provide fuzzy autocompletion.
Answering the question in the topic:
example: tableview(_:tableview didselectrowwithindex:IndexPath)
if you write tableview it will show all the symbols that start with tableview. For functions, it will show all the functions sorted by the second parameter name (didSelectRowWithIndex).
[EDIT]
it will autocomplete as far as the answer is unique and then show you a list full of options. I don't know any tricks to skip looking through the massive list. But after a while you'll know what you're looking for and it gets faster.
[\EDIT]
when you press tab, it
by the way: the delegate functions names start with the name of the object they're related to.
So UITableViewDelegate functions start with tableview.
as for your first two questions there are tons of answers for those questions on SO. This one seems closely related to yours.

How do I make a 'card stack' kind of UICollectionView?

I'd really like to do something similar to Tinder's "pile of cards" interface, but with a UICollectionView.
I would assume that if you need the other cells to dynamically move given the cell you are interacting with, one would be in Edit Mode on a UICollectionView, but I'm not sure.
Please don't reply with specific Cocoapods that do this and "why don't I just use those?"; it goes beyond just that. I have all sorts of content, and this is just one of the layouts / presentation types I need. Sometimes it's a grid. A lot of the controller actions are the same; just the display and interaction is different.
That said, please DO refer me to any code that may already do this, that I could use as a starting point.
Otherwise, I would be grateful to know where I would get started. I'm thinking maybe one of those projects that re-creates Springboard with a collection view??
EDIT: I was looking for something like a card stack, but not like Tinder in that you can interact with the top card before swiping or letting it return. In the end what I was trying to accomplish was similar to the old iPod-style 'Cover Flow' view.
I'll try to answer my own post. I made a few incorrect assumptions. In the end it was a lot less complex than I thought.
To get a collection view whose layout isn't just 'static within a scrollview' but changes dynamically with the contentOffset property, you need to subclass UICollectionViewLayout and make sure first of all you return YES for - (BOOL)shouldInvalidateLayoutForBoundsChange:(CGRect)newBounds
from there, most of your heavy lifting will be done in the - (void)prepareLayout method.
I basically used the following tutorial as a starting point and kind of followed what they were trying to do (or just downloaded the final project and saw how they did it, and mimicked the same effect), but obviously had a different prepareLayout method:
Ray Wenderlich

iOS Nested View Hierarchy to support drag drop functionality to allow end-user to configure forms

I'm building a native iOS app that will allow end users to build forms by dragging and dropping from a toolbox of custom controls. A typical scenario would be a power-user dragging some UILabels and UITextField representations around on a UIView. Groups of controls would be supported, allowing several controls to be visually contained within a section. The whole thing will probably be contained in a UIScrollView allowing horizontal scrolling between 'pages'.
'Normal' users will then use the form for data entry.
So, I have two related requirements: to allow different types of UIView/UITableView/UIImageView/UILabelView/UITextField etc to be laid-out and grouped (and probably contained within an outer UIScrollView), and to allow the layout to be adjusted/dragged/dropped by power-users.
My question is rather broad, but is essentially this: what is the most appropriate nested UIView hierarchy to support these two related requirements? Is a basic structure of UITableViews contained within an outer UIScrollView fundamentally sound if I want to drag-drop within nested views within the UITableView? Should I avoid UITableView because it will complicate dragging?
I appreciate this question is borderline subjective in scope, but I'd really appreciate some guidance from people who have tacked this sort of thing before and who have some words of wisdom for me.
Many thanks.
Sounds like an interesting app! I would say that using a UITableView would make the app horribly complicated. A UIScrollView would be a good base to drag and drop controls onto. Perhaps with an "add page" button, the user could tap this it required, and you could extend the contentSize of the UIScrollView to be the width of +1 pages, and then scroll it so the user can drag more controls onto that page.
To drag the controls around, you could use a UIPanGestureRecognizer attached to each control, and when triggered it changes the centre position of the control. You might need to turn off user interaction of some of these controls - e.g. for a UITextField the power user will want to drag it around but not want to enter a value into it.
For grouping controls, you could do something like this:
a "group mode", whereby the user taps a button to enter this mode, then taps a number of controls (would need some visual indication on them to show they are selected) and then taps done.
the selected controls are then be removed from the UIScrollView
a new UIView is created and positioned at the centre point of the selected controls, and is big enough for the controls to fit in at the same distances apart. It is added as a subview of the scroll view
the controls are all added as subviews of this view
the gesture recognizer is added to this view, instead of the individual controls. Then when dragging around, this group of controls will all move as a group with fixed layout.
If you have groups of controls that you think might be commonly used, you could even create them in advance, each in their own nib, and then allow the user to drag them onto the scroll view as a pre-made group.
What you might find, especially if some of your controls are quite large (e.g. I'd expect an image view to be significantly bigger than a label or text field), the pan gesture recognizer gets a bit limiting because when trying to drag views around you'll inadvertently pick the wrong one if they are positioned close together or overlapping. In which case, you might need the extra precision of handling all the touch events yourself - so when a touch starts, you test against all the controls (or groups) to see which has the closest centre to your tap position, and then as you get the touch moved events you can update this centre position.
I've not made anything quite as complex as what you're describing, but I did make an app where the user could drag small images onto a large image to apply as "decorations". They could drag on any number of these decorations, and also scale them with a pinch gesture. In this case, I had a UIImageView as a background which held the main image. Then the decorations were on the edge of the image, and a pan gesture recognizer was used to detect them being dragged onto the image. On drag, I'd actually create a new instance of the decoration (UIImageView) so that there was always another one left in the toolbox. A pinch gesture recognizer was used for the user to scale the decorations. For the user to move around a decoration they had already placed, I had to use manual touch handling to detect the right decoration (since they could easily be overlapping, and ones that looked round to the user are actually square in terms of UIViews, so it was easy for the user to accidentally drag the corner of one when they intended to drag a different one). Mixing an matching gesture recognizers and manual touch handling seemed to work out just fine, which was good because it's much easier to use the gesture recognizers for the more complex behaviour like pinching.
Back to your app, once your power user has set up everything, then when the normal user loads the app, you can just turn off any touch handling code (and remove or don't create the gesture recognizers) and they will get static forms as laid out by the power user. Then make sure user interaction is enabled on all of the controls (e.g. UITextField) and they will be able to enter data into them.
Doing all of the above with controls onto a scroll view will be complex enough I think, and you may end up having to deal with lots of niggly behaviour in trying to get it working nicely for both normal and power users. I think this would be 100x harder if you were also dealing with UITableViews and UITableCells at the same time.
Please let me know if you'd like me to elaborate on any aspect of the app I outlined above, as it does seem to have a fair chunk of functionality in common with your app. Hope to see/hear more about your app in the future!
EDIT
One more thing occurred to me - if you are keen to use a UITableView in your solution, then I would suggest that your power user lays out one UITableViewCell at a time. In fact, they would be dragging UILabels and other controls onto just a basic UIView, which when they've finished you then use to record the positions of the controls. You then use these positions when presenting those controls in a cell - in cellForRowAtIndexPath you would create and init all of the chosen controls, and position all of them in a newly created cell at the positions and layout the power user had chosen. The power user could also have a control to change the height of the cell they are laying out, for more flexibility. They would create a series of cell layouts one after the other (I guess each of these would be a "group" of controls), and then those cells would be presented in order in the table view. You could then give the power user some final tweaking control by letting them put the table into edit mode so they can reorder the cells (or even remove some).
Depending on the application, perhaps the user could also have these cell layouts they've previously created always available, so after they've built up a few common control groups, they can just keep reusing them to very rapidly build up a form. And then occasionally they would create a new cell layout when none of the ones they have created so far are suitable, and again it would be saved as a template for them to use again in future forms.
I would just make an EditView class that is just a UIView with some transparent background color. When you want to drag controls around, then set some type of edit mode where you overlay a bunch of EditViews on all the appropriate controls. The EditView would then support whatever gestures / touch handling you want to resize or move it. Dragging a view onto another view and releasing might prompt something like "Nest view A in view B?" which then you can make the related addSubview calls.
Nesting tableviews inside scrollviews won't be an issue, though I'm not sure what kind of behavior would be expected if you were trying to nest anything inside a tableview...that would have to be specified using standard UITableView methods.
For saving layouts and such, you might need to create your own pseudo-view hierarchy that contains various pieces of meta-data needed to recreate the final layout which you would then be able to store somewhere.

iOS UI development: approach to building document "selector" screen

I'm looking to build a document "selector" screen, similar to Pages and Numbers on the iPad/iPhone:
I come from a WPF background and have some iOS experience. That being said, I'm looking for a good approach to building something like the tile-based interface Apple uses for opening documents in Pages.
I'm not concerned with the Folder animation.
What is the best way to approach building just the tile interface? I'd imagine I'd build some sort of view that sits within a UIScrollView - but it's the nature of that subview that I'm a little confused about. Does iOS have any wrap-panel or grid-like controls I could load a set of tiles (i.e., documents) into?
What do you guys think?
I don't know of any third-party classes to handle this for you, but there might be some out there.
The basic structure will be a UIScrollView containing a set of views, each representing one cell on the grid. You set the scroll view's contentSize based on the total number of tiles. Then you create tile views on demand, and place them inside the scroll view.
The scroll view's delegate object will be responsible for monitoring the scroll position, putting down tile views as they become visible, and (optionally) removing tile views that move out of view. This is basically how UITableView works: there are only about six or so instances of UITableViewCell at any given time, they are recycled as you scroll up and down the view. (Imagine a train where somebody at the back end is pulling out the rails and passing them forward to somebody in the front, putting them down in front of the train. As far as the train knows, the rails go on for miles.)
If you wind up having to place all the views yourself, take some time to learn the CGRect family of methods, including CGRectDivide. They will be useful in laying out the views and also in computing what's visible and what's not.
There are a few third party classes/libraries you can get to produce this functionality, AQGridView comes to mind. But there are no default easy classes for this.
If I was to develop this type of implementation, I would subclass UITableViewController. Expand it to have columns. Then subclass a UITableViewCell to display the image. That way all the container code and everything would already be there, and all you have to do is customize it to f it your needs.

Resources