Implementing a 7x7 grid programmatically using UICollectionView - cocoa-touch

How would you implement a 7x7 grid using UICollectionView? This grid would have no spaces in between each cell and also when it rotates the cells would simply resize to fit the screen, so it will always be 7x7 no matter what.
I have the following classes already done, a ViewController, a Cell class, a CollectionViewLayout class.
My original thinking was that I would have to do this in the CollectionViewLayout class, but which methods should I target to do this?

Apart from adjusting the datasource methods to return 7 sections and 7 rows per section, you have to have your view controller comply to the UICollectionViewDelegateFlowLayout protocol.
Assuming you want no spaces (having set the minimum spacing to 0) you can then use this method to size the cell:
-(CGSize)collectionView:(UICollectionView *)collectionView
layout:(UICollectionViewLayout *)collectionViewLayout
sizeForItemAtIndexPath:(NSIndexPath *)indexPath {
return CGSizeMake(self.collectionView.bounds.size.width/7.0,
self.collectionView.bounds.size.height/7.0);
}
Actually, to make this work, you need another 2 tweaks. First, you should react to interface orientations, like this:
-(void)didRotateFromInterfaceOrientation:
(UIInterfaceOrientation)fromInterfaceOrientation {
[self.collectionView.collectionViewLayout invalidateLayout];
}
Second, to ensure one section does not get broken into 2 lines, you might have to use 7.01 for the division rather than 7.0.

Related

How to use UICollectionViewDelegateFlowLayout?

This is the first time I use UICollectionView and it is quite interesting, but I hit the following problem. Can anyone help me clarify what is happening ?
With the following code:
- (CGSize)collectionView:(UICollectionView *)collectionView
layout:(UICollectionViewLayout*)collectionViewLayout
sizeForItemAtIndexPath:(NSIndexPath *)indexPath
{
return CGSizeMake(280.0,36.0);
}
I have this display:
Obviously I need a higher space to display the cell reading "Nous sommes" because it has a second line now invisible.
Since this is the fifth line I use the following code (expecting to solve the problem):
- (CGSize)collectionView:(UICollectionView *)collectionView
layout:(UICollectionViewLayout*)collectionViewLayout
sizeForItemAtIndexPath:(NSIndexPath *)indexPath
{
return CGSizeMake(280.0,indexPath.row!=4?36.0:72.0);
}
But here is the result:
Returning a size with a larger height causes the cell to extent horizontally (which I do not want) while still giving the space (vertically) without using it.
I am missing something. Please explain if you can.
I assume the blue rectangle is a subview of the cell (because it is less than your cell width of 280 in the first example). The problem is likely that you need to set your struts & springs (or constraints if you're using Auto Layout) such that your subviews resize the way you want when the cell gets resized. Looking at your layout, I think you want to specify fixed width and flexible height (or the Auto Layout equivalent).
If you're still stuck, please post details about your struts & springs (or Auto Layout constraints).

Why do we need to change the backgroundcolor of a cell in willDisplayCell?

Note: If you want to change the background color of a cell (by setting
the background color of a cell via the backgroundColor property
declared by UIView) you must do it in the
tableView:willDisplayCell:forRowAtIndexPath: method of the delegate
and not in tableView:cellForRowAtIndexPath: of the data source.
Changes to the background colors of cells in a group-style table view
has an effect in iOS 3.0 that is different than previous versions of
the operating system. It now affects the area inside the rounded
rectangle instead of the area outside of it.
I noticed that changing the background color of a cell in cellForRowAtIndexPath doesn't do anything for plain style cell though it works fine on group cell.
Can anyone explain the design decision?
Also changing the background color of cell.contentView works nevertheless.
Note: I am aware of the work around of simply putting UIView and set the background on our custom TableView Cell. I am asking why and not asking how to fix it.
It seems that apple override the background with the background of the table.
To really change the background, we need to do that after the overriding, and that means in:
- (void)tableView:(UITableView *)tableView willDisplayCell:(UITableViewCell *)cell forRowAtIndexPath:(NSIndexPath *)indexPath { ... }
I tried and it works.

Setting Up a UICollectionView in iOS

I've been hunting around for ways to setup a UICollectionView for an iOS app. Google only turns up a few blogs with posts about what it is, not how it works. Then of course, there's the Apple documentation which is helpful, but doesn't provide as much information as I'd like to be able to setup a UICollectionView.
How can one setup a UICollectionView?
The uicollectionview class is almost identical to the uitableview Class. They share many of the same methods and functions. And if the methods / functions are different, most of the time it's just a matter of swapping out "row" for "cell" and vice versa. However there are a few methods that don't exist on UICollectionView that do on UITableView. First though, I'll explain how to setup a UICollectionView:
Begin by adding your UICollectionView to a current ViewController, or creating a new UICollectionViewController. The steps aren't that much different for the view and controller.
If you're using the View and not the ViewController, make sure that the Delegate and DataSource of the CollectionView is the view controller it's on. Also make sure to add the Delegate and DataSource to your header file: <UICollectionViewDataSource, UICollectionViewDelegate>
Next, make sure to include these three methods in your view controller's class:
-(NSInteger)numberOfSectionsInCollectionView:(UICollectionView *)collectionView
-(NSInteger)collectionView:(UICollectionView *)collectionView numberOfItemsInSection:(NSInteger)section
-(UICollectionViewCell *)collectionView:(UICollectionView *)collectionView cellForItemAtIndexPath:(NSIndexPath *)indexPath
These are the only required methods. The first tells the collection view the number of sections it should have. This should return an integer value. The second method gets the number of cells in each section. Again, this should return an integer value. The last method populates each cell using the data given (usually from an NSArray). This last method should return a CollectionViewCell. If you set breakpoints on this method, you'll notice that it is called once for every cell defined in the numberOfItemsInSection method.
UICollectionViews provide advanced animation methods and allow cells to be deselected and selected (similar to apps like Pages when in 'Edit' mode). However, to my knowledge, UICollectionViews do not provide features such as "swipe to delete" or and kind of disclosure indicator.
UICollectionViews also allow you to create custom cells using xib (AKA nib) files, this allows for some very advanced-looking and unique interfaces without lots of complicated code.
Sadly, UICollectionView is only supported in iOS 6 and up. There are a few projects available such as PSTCollectionView which adds support for CollectionViews in iOS 4.3+, but I haven't figured out how to use them. In my case, when the view loads I just check if the UICollectionView Class is available and if it isn't then I load a Table instead.
Here is a link to Apple's official documentation on Collection Views. You might also want to check out this tutorial.
I created a step-by-step tutorial for setting up UICollectionViews with custom layouts. Hopefully it helps some people to get familiar with the API.

NSTableView Drag and Drop not working

I'm trying to set up very basic drag and drop for my NSTableView. The table view has a single column (with a custom cell). The column is bound to an NSArrayController, and the array controller's content array is bound to an NSArray on my controller object. The data displays fine in the table. I connected the dataSource and delegate outlets of the table view to my controller object, and then implemented these methods:
- (BOOL)tableView:(NSTableView *)aTableView writeRowsWithIndexes:(NSIndexSet *)rowIndexes toPasteboard:(NSPasteboard *)pboard
{
NSLog(#"dragging");
return YES;
}
- (NSDragOperation)tableView:(NSTableView*)tv validateDrop:(id <NSDraggingInfo>)info proposedRow:(NSInteger)row proposedDropOperation:(NSTableViewDropOperation)op
{
return NSDragOperationEvery;
}
- (BOOL)tableView:(NSTableView *)aTableView acceptDrop:(id <NSDraggingInfo>)info
row:(NSInteger)row dropOperation:(NSTableViewDropOperation)operation
{
return YES;
}
I also registered the drag types in -awakeFromNib:
#define MyDragType #"MyDragType"
- (void)awakeFromNib
{
[super awakeFromNib];
[_myTable registerForDraggedTypes:[NSArray arrayWithObjects:MyDragType, nil]];
}
The problem is that the -tableView:writeRowsWithIndexes:toPasteboard: method is never called. I've looked at a bunch of examples and I can't figure out anything I'm doing wrong. Could the problem be that I'm using a custom cell? Is there something I'm supposed to override in the cell subclass to enable this functionality?
EDIT: Confirmed. Switching the custom cell for a regular NSTextFieldCell made dragging work. Now, how do I make drag and drop work with my custom cell?
I was banging my head against the wall in search of a more elegant solution to the same problem, and then I came across this:
http://www.wooji-juice.com/blog/cocoa-10-bindings.html
For instance, if you want to support drag-and-drop from a table, you need to set up a data source for it — even if you’re using bindings to supply the actual data, you can set a data source on it, and Cocoa needs one to handle the tableView:writeRowsWithIndexes:toPasteboard and related messages.
Yep. If you've got everything bound to your array controller, what you can do is to have the array controller implement the necessary drag/drop functions and then set the table view's data source to the array controller with setDataSource:.
I fixed the issue. There seems to be an issue with using bindings with custom NSCells in a table view. Switching to the traditional NSTableViewDataSource methods rather than bindings and an array controller solved it.
What works for me is to call initTextCell rather than init or initImageCell within the initializer of my custom cell (in my case, init). It doesn't seem to matter whether the superclass is NSCell or NSActionCell. Also, I have binding, and dragging still works.
That should be sufficient to allow the drag to start. Are you sure you've connected the delegate methods?
I ran into this problem, your custom cell needs to extend NSActionCell not NSCell if you want drag and drop to work properly. There is probably something you could implement in NSCell that would make it all work too, but I didn't dig any further after switching to NSActionCell. At least, that fixed the issue for me.
I ran into the problem. I have a NSCell subclass, and I did implement the tableView:writeRowsWithIndexes:toPasteboard and the dataSource was set for the NSTableView. Dragging would not work.
If I set the cell type in my init for the custom subclass
self.type = NSTextCellType;
Then I get dragging. If I don't, it defaults to NSNullCellType and dragging doesn't work. I'm guessing the people who got it working by using another subclass NSTextFieldCell works because the cell type is different.
I also observe the similar issue, NStableView drag & drop is not working. I have 4 column in my tableview and two of them are custom cells. Dragging for non-custom cell is working fine even though its working on cell separator as well however its not working with custom cells.
My custom cell was subclassed from NSButtonCell which was causing the
issue. So as suggested, I changed my parent class from NSButtonCell to
NSActionCell. Now, dragging is working perfectly.
It works with both NSCell as well as NSActionCell however I required action on my cell so used NSActionCell.

iPad - More than one UITableView in the same screen

I coding app from iPad and I have to put two separate UITableView in the same screen. For this app I can´t put the UITableView and divid in two sections for requisits reason. It must be two separated. Well, in this case how I can fill the rows of UITableView. Can I have create a DataSource and Delegate in separate classes, one for a first UITableView and other DataSource and Delegate class for the second UITableView or have other approach more elegant?
tks a lot.
You can do this a few different ways. The most straightforward is to use separate classes to handle the datasource and delegate protocols for each table view.
Alternatively, you could use a single class as the datasource and delegate for both, and check the identity of the tableview that's passed into the protocol methods.
It would looks something like this: (I'm assuming this code is on your view controller.)
- (CGFloat)tableView:(UITableView *)tableView heightForRowAtIndexPath:(NSIndexPath *)indexPath {
CGFloat height = 44.0; // default height
if (tableView == self.myLeftTableView) {
height = // Compute the cell height for the left table view.
} else {
height = // Compute the cell height for the right table view.
}
return height;
}
This could get ugly quickly, which is why I'd recommend the first approach.
Yes, you can make different classes for datasource and delegate methods for different UITableView and in-fact this is the best approach for using multiple tables on same view as this approach implements MVC architecture.
For this try these 2 solutions in which first approach is for implementing 2 tables datasource and delegate method in same class and second is to implement different datasource and delegate method in different classes either by using UITableViewController or NSObject class
For more detail try these links where you can find sample code too:
Handle more than one table in a View Part-1
Handle more than one table in a View Part-2