UICollectionViewCells and Buttons - ios

I've been trying to get my UICollectionView to respond differently to single and double taps but all the answers I have found seem to suggest this is not really feasible because the single taps get recognised first. It works on really slow taps, but anything faster always initiates the default gesture recogniser (if anybody has got this to work I would love to know)...
So anyway, I have now resorted to putting buttons in my UICollectionViewCell (which has it's own class and NIB file).
The question is this:
What is considered the best way to use the button in the UIViewController of the collectionView?
I currently have a protocol in the header of my subclass of UICollectionViewCell and have declared my viewController as the delegate and implemented the required protocol functions.
In collectionView:cellForItemAtIndexPath: I set the VC as the delegate of the cell.
It all works but it seems a bit long-winded, and maybe not a great way of doing this.
The other way I was thinking of was instead of using delegates to simply call addTarget:Action: on the property of the UICollectionViewCell in collectionView:cellForItemAtIndexPath:.
This seems simpler but the delegate pattern looks to me like the better fit.
Any and all advice on which would be better, why, and any more appropriate alternatives welcomed!
Thanks.

You're doing the right think using the delegation pattern. The ultimate responsible object for any action of your views is the viewController who's displaying those views. Therefore, using it as the delegate for you cell's protocol is just right.

create a custom subview of UICollectionViewCell and place your button in the initWithFrame method. Declare the button to be public so you can use it later in your uicollectionviewcontroller or uicollectionview if creating programmatically.

Related

How can I add didDisplayCell delegate to UITableView?

I am well aware of willDisplay, but I need to know exactly when it's displayed.
Is there a way I can subclass UITableView so that I can use this? It's absolutely necessary; I don't understand why Apple doesn't have this delegate.

What is a proper way for handling actions (events) of the UITableView cell subviews?

I have a UITableView with custom cells. Each cell has a rather complex layout and a lot of child views all of which has event actions: UIImageView with gesture recogniser, several UIButtons with some actions, two UILabels with gesture recognizers.
So I'm interested are there some elegant ways to handle target-action for them?
Now I see three ways:
Handle actions with blocks (BlocksKit to the rescue) right in the cellForRowAtIndexPath:
Create custom class CellEventHandler, pass to it all needed dependencies (controller's navigation controller, data array, etc.) and place all the cell's views action selectors there.
Write all the selectors in the TableViewController (default way)
But I'm not satisfied with all this ways. Can someone describe some elegant way which will help to make controller thin, and also will be easy maintainble. I'm sure there should exist some pattern for this workflow.
Use delegation. When constructing a cell, set it's delegate attribute to some instance that conforms your delegation protocol. When actions are triggered, simply delegate the behavior to the delegate.
That way, you end up with well defined delegation protocol and functionality encapsulated in that class. It is up to you whether the delegate will be e.g. TableViewController or a custom class.
I think the most efficient way to go about handling a complex cells is to subclass UITableViewCell and have all of the events handled directly in the subclass. You can create IBOutlets and inactions directly in there.
In the viewForRowAtIndexPath you can simply call a custom function initWithObject that you can declare in the header of your class so even the initial setup of the cell is out of the viewController greatly simplifying the setup.
The Views and Actions should be in View of MVC pattern that is Custom cell in your case. You should write one method for gestureRecognizer(tapGestureRecognizer added on your cell) in your custom cell class. Method will identify the type of object which invoke it through introspection i.e. isKindOfClass UIButton/ Label / ImageView. Each object will further identify with its tag like if gestureRecognizer say it is label which invoke this method but which label label1 or label2 now you can compare its tag to detect it.

How to pass a reference to UIView instance

I have a set of "controls" in a UIView that are displayed inside a UITableViewCell - this includes a UILabel, and some UIButtons. When a UITableViewCell is pressed, I'm displaying a new view from a different UIViewController. I want this view to include the "controls" from the UITableViewCell with the buttons/label in the exact same state as before.
What's the correct way to do this? Should I create a model that stores the state of the buttons/label and then access the model or is there an easier way?
Many thanks :)
If you need that for beautiful transition animation only, it would be better to take a "screenshot" of your UITableViewCell. But if they should be interactive as well, just move them to new superview. But you will need to maintain constraints/frames/outlets consistency in both places...

Why I'm getting gesture recognizers cannot be used on prototype objects?

I'm getting the above error from storyboard when I dropped a UITapGestureRecognizer inside a UIView which is inside a UITableViewCell in my scene.
Any idea why I'm getting this error ?
I'm not sure why the restriction is in place but I know why you are getting it the error.
When you design a UITableViewCell in StoryBoard you are only designing a prototype object. i.e. the object may never actually exist. It only gets ACTUALLY created in tableView:cellForRowAtIndexPath:
What might be a better approach is to create the gestureRecognizer when you configure the cell in code. This way you won't have this restriction.
I'd also possibly look at whether you actually need it? If it is just for a single tap with one finger then you may be better off coding the touchesEnded or just using a UIButton instead.
Found the reason myself. storyboard only allows that when we have a UITableViewController or it's subclass and the tableview content should be 'static cells' instead of default 'Dynamic Prototypes'. In that configures I can add a gesture recognizer inside the cell subview.
But that is a limitation and will not work in my case as I have a very customized view controller subclass instead of table view controller subclass. Need to find other way around it seems :(

QuickDialog within frame

I'm trying to employ QuickDialog for an iOS 5 iPad app which uses storyboards, but I guess the question would broadly apply to UITableViewController as well.
My understanding is that when I'm initialising the QRootElement, the tableview that QDC creates will replace the view of my class, thus rendering ineffective anything I customise in the IB storyboard. I would like to be able to design the UI in IB, and have the QD table show up as a frame instead of taking over the whole screen.
I think the solution is to have the QuickDialog tableview set up as a subview of my UIView-based class. Is this correct? What would be the best way to achieve this? Would I have to rewrite the root initialiser in my custom view controller that inherits from QDC, or is there a different way, perhaps something like the approach used here?
Thanks!
I would recommend you inherit from the QuickDialogViewController as your main controller. The QDViewController inherits directly from UIViewController (instead of UITableViewController), so it's quite easy to just move the table view around and add controls around it.
If you really want to create everything from Interface Builder, your tableview will have to inherit from QuickdialogTableView, and you'll have to provide the delegate and data source yourself. Look at the QDViewController for that, as you'll have to write pretty much the same code.

Resources