What is the section number of a supplementary view? - swift

I'm working with UICollectionViewController. At some point In need to make some configurations to the visible footers and for each one of them, I need to know its' current section number. Current because sections may be replaced and the section of a reusable view may change.
self.collectionView.visibleSupplementaryViews(ofKind: UICollectionView.elementKindSectionFooter)
.filter { $0.reuseIdentifier == reuseIdentifierFooter}
.forEach {
// Here I need to know the section number of each view
}

Get the index path for the visible views: https://developer.apple.com/documentation/uikit/uicollectionview/1618034-indexpathsforvisiblesupplementar
Then iterate through the indexPaths and query the view with https://developer.apple.com/documentation/uikit/uicollectionview/1618041-supplementaryview

Related

Adding a full width row to a CollectionView two-column structure

I created such a structure with CollectionView, there are two items in one line. The whole structure should go on like this, everything is fine until here, but I must add (only 1) slide at the top. So I want to place one more full width image in 1 line. What path should I follow?
An image of my app
If the full-width image that you need to display is just a first item of the data set you're displaying, make the collection view return a custom size for it based on its index path. In order to do it, assign a delegate to your collection view and implement the UICollectionViewDelegateFlowLayout protocol, specifically the collectionView(_:layout:sizeForItemAt:) method. Alternatively, if you're targeting iOS 13+, you can do the same with the UICollectionViewCompositionalLayout, but the implementation will be different, in that case I encourage you to read its documentation.
If the item doesn't really belong to the data set, better create a section header with just that item inside.

Scrolling two UITableViews together

I have a weird design case in which to implement I need to place two UITableViews on the same view. I would just use sections, but I need an index on the second table.
I'd like them to both scroll together like they were actually two sections of the same table view. Is this possible?
Here's a basic mockup illustrating why:
As far as I understand it, you cannot move the index. Also, when you add an index to a table, it appears over the entire tableview, not just one section.
If I have to implement this as two table views, they both need to scroll as if they were one. If it's possible to do this using sections, that's even better.
Update
After seeing your update my old answer is not very good but I'll leave my previous answer for anyone else who wants it.
New answer - It depends how you want the tables sync'd.
If you know
Which cells are in the top 5
How tall each cell is
The offset the table view
Then you can calculate which cell is visible at the top of the top 5 table. You can use this information to scroll the bottom table to the correct index.
Old answer
I'm with the other guys not sure why you would want to or if I am misinterpreting but it's pretty simple.
UITableView is a subclass of UIScrollView so you can set yourself as the UITableViewDelegate and override
- (void)scrollViewDidScroll:(UIScrollView *)scrollView;
{
UITableView *slaveTable = nil;
if (self.table1 == scrollView) {
slaveTable = self.table2;
} else if (self.table2 == scrollView) {
slaveTable = self.table1;
}
[slaveTable setContentOffset:scrollView.contentOffset];
}
This gives me something that looks like this:
The top UITableView is self.table1 and the bottom is self.table2 if either table is scrolled the scrolling is mirrored in the other table.
in swift this code:
func scrollViewDidScroll(scrollView: UIScrollView) {
if tb_time1 == scrollView {
tb_time2.contentOffset = tb_time1.contentOffset
}else if tb_time2 == scrollView {
tb_time1.contentOffset = tb_time2.contentOffset
}
}
From the mock-up it seems like this can be accomplished with a single UITableView with two sections.
Instead of maintaining two tableViews you could maintain two collections (one for each section). Then in cellForRowAtIndexPath choose the collection to use based on the section specified in the indexPath.

iPhone: Cells order changes in UITableView Section After Call to reloadSections: Method

I have a table with two sections. A segmented control in first sections changes which rows are displayed in the second section. My problem is that the order of the rows and which row are displayed in the second section shifts improperly upon each subsequent press of a button in the segmented control.
I allow a user to add a product to a shopping list 3 different ways: by name, by barcord and by taking a picture with a camera. I have 3 buttons in a UISegmentedControl so the users can select which method to use. Depending on which segement the user selects the fields in the second segment should change to show cells relevant to that method.
Section 0:
0 row with segmented control showing name, barcode and camera buttons
Section 1:
// button zero, name button
0 row with textfield
1 row with textfield
or
// button 1, barcode button
0 row with textfield
or
// button 2, camera button
// shows camera view
I've put placeholders in each UITextField.
Each time a button in the segmented control is clicked, I call a pickOne: method that updates the tablevew. In that method, I construct a NSIndexSet with NSRange of (1, 1), and then I call the reloadSections: method of the UITableViewController with the NSIndexSet as a parameter.
When the view appears for the first time, everything is ok but when I click the buttons repeatedly, the order of the cells changes. Cells containing the two textFields for the button0 and the new placeHolders are written over the old ones.
Worse, sometimes when I click on button 0, it shows me only the second cell of the two cells.
My detailed code can be seen here http://pastebin.com/9GwMpCS9
I'm seeing a couple of problems.
The first big one is that you're adding subviews into the cells bypassing the contentView. Subviews in predefined styles are broken up into different parts depending on their roles. You have the editing control, the content view, and the accessory view. While you can add directly to the cell's view, there'll be odd behavior because the predefined cells are expecting the content to be in the content view.
I think what's causing your problem is that you're adding subviews every time a cell is decorated but you never remove them. When a cell is dequeued there's no guarantee that everything is restored to the pristine new condition as if it was alloc'ed. Things like custom accessory views that aren't removed can be left behind. I'm pretty sure that's happening. You're collecting visual trash on cells that should be clean.
I believe your problem is here.
// Customize the appearance of table view cells.
- (UITableViewCell *)tableView:(UITableView *)tableView cellForRowAtIndexPath:(NSIndexPath *)indexPath {
//....
if(addMode == NAME) {
if(indexPath.row == 0) {
[cell addSubview:nameTextField];
}
else if(indexPath.row == 1) {
[cell addSubview:categoryTextField];
}
}
else if(addMode == BARCODE) {
[cell addSubview:barcodeTextField];
}
else if(addMode == SCAN){
//Scanning mode
}
}
return cell;
}
This because the table always shows has having two sections, this method is always called for section 1. Regardless of the input type selected, it creates or dequeue a cell and returns it. Whenever addMode==SCAN, it randomly dequeues one of the previously used cells for the name or barcode addMode and returns that.
I suggest that you remove the SCAN logic from the table altogether or that you create a row for the camera.
I think the latter the best UI. With the first two buttons, the users is presented with a choice in the second section. You should maintain that pattern with the camera choice. Just have a cell that displays a button that evokes the camera. Yes, it adds a second step but establishes a kinetic pattern for the user: Select input type in section one then select an appropriate cell in section two. The user shouldn't have to stop and think each time whether they need to hit one of the rows in section two or not. They should just do so automatically.

How do I get a Row count from a UITableView

I have a tableview I'd like to customize based on how many rows it has.
If it has no rows, I'd like the background image to prompt the user to add content.
If it has 1 or more rows, I'd like it to have a different background image, in order to display the content.
I'm using a fetched results controller to populate my tableview, by the way.
Any ideas?
Well this is generally very easy to accomplish as you need only to have UITableView properly delegated to your ViewController with appropriate delegate methods included in your .m file.
Then you can anywhere get row count like this:
[tablePropertyName numberOfRowsInSection:SECTION_NUMBER];
where section number is 0 for first section, 1 for second, etc.
In Swift, you can get the UITableView rows count by
yourTableViewName.numberOfRows(inSection: Int)
example:
yourTableViewName.numberOfRows(inSection: 0) // returns rows count in section 0
I agree with Sixten Otto's answer.
[myFetchedResultsController.fetchedObjects count];
However there's more. Above line would return the number of objects regardless the sections. However if you would want to perform this on a table with multiple sections, you would have to call it the following way.
[[myFetchedResultsController.sections objectAtIndex:<section>] numberOfObjects];
You can get the objects for the section like this.
[[myFetchedResultsController.sections objectAtIndex:<section>] objects];
** You have to replace with the number representing the section.
Hope this helps.
I'd recommend taking a look at the documentation for NSFetchedResultsController. It has example code for implementing the methods of UITableViewDataSource (including the ones that say how many sections the table has, and how many rows in each section), as well as documenting the property fetchedObjects, which you could use to see how many raw results you fetched.
[myFetchedResultsController.fetchedObjects count];
tableView.numberOfRows(inSection:) returns numbers of row in section, this method may not trigger fetched results controller's core data query.
let numberOfItems = (0..<tableView.numberOfSections).reduce(into: 0) { partialResult, sectionIndex in
partialResult += tableView.numberOfRows(inSection: sectionIndex)
}

Best (Any) way blend tableview section header onto top of a grouped tableview

I'd like to add section headers to my grouped table view's sections but I'd like them to appear seamless (see image). The default, as we're all well aware of, is rounded top corners on the first row of a grouped table view cell so it ends up looking like crap when you merge them.
Any way to specify when indexPath.row = 0 that the UITableViewCell should use row style "middle" or something like that?
If not then what are my options? I guess I could scratch the section header and use Row 0 as a quasi-header then push my array data +1 to fill the rest of the table? I'd rather not roll my own from scratch...if possible.
Sample Table http://img35.imageshack.us/img35/8181/sampletable.png
Edit:
"Crap" looks like this:
alt text http://img25.imageshack.us/img25/9748/crapsection.png
Don't do what you're doing, it's against HIG
Ok, ok, I'll tell you how to do it:
You're going to want to do your own cell background views. The default grouped one is not what you want.
When a tableview asks you for a cell, set its backgroundView and selectedBackgroundView to something that looks appropriate for its place in the tableview.
Usually, this means a UIImageView with the appropriate image, though you can go wild here with a custom view, but there are gotchas.
So in your case, you would do
if (indexPath.row > sectionRowCount - 1) {
//Not the last row
//Put in the middle background
} else {
//Put in the end background
}
Then you'll want a custom table section header, but that's pretty easy.
In your case, you probably won't have to worry about when there's just one row, so that makes things even easier.
Take a look at the tutorial here:
cocoa with love basically what you need is 3 different images. One for the top row, one for the bottom, and a 3rd for the middle rows.
You could also not use the section header, but instead use a custom cell as the first cell of the section. So when ([indexPath row] == 0), return a custom cell that is the "header" and then return the "regular" cells (offset by one row) for the rest. You'll also have to make adjustments to the numberOfRowsInSection function to return +1.