How to focus a UICollectionViewCell in UITableViewCell in tvOS? - swift

Description:
I have a list of UITableViewCells that have each have a UICollectionView with X amount of UICollectionViewCells (see image below for more clarity)
The idea behind this is to be able to implement sections with a header on top and a horizontal scrolling UICollectionView
Everything is working great, except when I try to focus the UICollectionViewCells (aka: CategoryCell). The UITableViewCell gets focused and highlights all the content making it impossible to focus any of the UICollectionViewCells.
What I've tried:
According to other posts the fix for this would be deactivate User Interaction and/or set the selection style to none on the UITableViewCell:
cell.selectionStyle = UITableViewCellSelectionStyle.None
and to enable User Interaction on the UICollectionViewCell instead.
Here are posts that talk about it:
UITableViewCell with UITextField losing the ability to select UITableView row?
How can I disable the UITableView selection highlighting?
I've attempted to implemen these solutions without success.
Question:
What step did I miss? Does the fix not work on tvOS? How do I focus my UICollectionViewCell that is in a UICollectionView that is in a UITableViewCell?
More:
Image showing my UITableViewController and all it's contents from my StoryBoard.

The problem is most likely that your table view cells are returning true to canBecomeFocused. You can disable that by either implementing the UITableViewDelegate method tableView(_, canFocusRowAt:) to return false, or by subclassing UITableViewCell and returning false from canBecomeFocused.
The focus engine will try to focus on the top-most view that returns true from canBecomeFocused, which is why it can't find your collection view cells: they're "hidden" inside the focusable table view cells. If you disable focus on the table view cells, then the focus engine will be able to find your collection view cells.
override func tableView(tableView: UITableView, canFocusRowAtIndexPath indexPath: NSIndexPath) -> Bool {
return false
}

Related

Horizontal NSCollectionView in vertical NSTableView does not select until collection view is clicked

I have a weird question regarding NSCollectionView. Basically, I have a collection view that scrolls horizontally in a vertically scrolling table view. I have implemented the data source and delegate of the collection view within my NSTableCellView subclass. The data source works just fine and the collection view is able to load some images.
Here comes the problem. I want the collection view to be selectable. I have implemented this delegate method into my table cell view subclass:
func collectionView(_ collectionView: NSCollectionView, didSelectItemsAt indexPaths: Set<IndexPath>) {
// Do things here
}
This method works, but with a caveat. It only gets called when I click on an empty space in the collection view first and then selecting a cell. If I only click on a cell, it will not get called, which is quite bizarre to me. Any idea on how to fix this?
I designed the table cell view in the storyboard, the collection view has it's Selectable and Allow Empty Selection checked in the storyboard. Allow Multiple Selection is not checked because I don't want multiple selection, but I tried having it on and it doesn't change anything.
Thanks
Subclass NSTableView. In your subclass, override validateProposedFirstResponder(_:for:) to return true for your collection view and its subviews (or maybe just return true always).

UITableView get smaller

I will try to explain my problem with the help of pictures :
Firstly, I just added an UITableView to my UIViewController. I selected it to show its frame and there was no problem.
Next, when I connect my button to my UIViewController, my UITableView gets smaller.
I selected it to see that the frame doesn't match with the contents. I noticed that the tableview reduces exactly of 64 (44 from the UINavigationBar + 20 from the bar with the battery)
At the beginning, I thought it was juste a display problem from XCode, but next when I tried to run it with cells, the problem still exist.
So I put a UIContainerView in my UIViewController and my tableView in the controller of the container. XCode display properly my table view, but when in run it, I get the same problem.
Thank you in advance,
Sorry for my english.
The problem is that your containing view controller's Adjust Scroll View Insets is checked (in its Attributes inspector). Uncheck it.
You can use this function to explicitly set the size of your cell.
func tableView(_ tableView: UITableView, heightForRowAt indexPath: IndexPath) -> CGFloat {
}

Swift UITableViewCell subview do not register tap

Background: I'm making a calendar and for that I'm combining a UITableView and a UICollectionViews. The UITableView is holding month cells. Each month UITableViewCell is holding a UICollectionView with UICollectionViewCell days.
Problem: The UICollectionViewCells aren't clickable.
I can fix this by calling self.bringSubviewToFront(self.collectionView) in the month UITableViewCell. However this makes the UITableView not scroll because the collectionView is now top view.
So, I can either choose between be able to scroll the UITableView or be able to click the UICollectionView.
What I tried: I tried to capture the click before it happens and bring the collectionView to front and then put it back again. Not a good solution though:
//In UITableViewCell class
//UIGestureRecognizerDelegate
//Bring collectionView to front before tap
override func gestureRecognizer(gestureRecognizer: UIGestureRecognizer, shouldReceiveTouch touch: UITouch) -> Bool {
self.bringSubviewToFront(self.collectionView)
return true
}
//UIScrollViewDelegate
//Bring collectionView to back again
func collectionView(collectionView: UICollectionView, didSelectItemAtIndexPath indexPath: NSIndexPath) {
self.sendSubviewToBack(self.collectionView)
//Do stuff
}
Question: How can I achieve to both be able to scroll and have the UICollectionView clickable without bringing back and forward the view between taps? Is there a way to have the UICollectionView in front and still make the UITableView scrollable?
Nested UIScrollView with same scroll directions is against Apple's Human Interface Guidelines and your app might even get rejected for this so try disabling the scroll of your UICollectionView.
Hope this helps.

Segmented controller

UIView,SegmentedController & UIContainerView in a ScrollView or something similar?
In my storyboard I have a VC containing a UIView at the top, segmented controller in the middle & 2 ContainerViewControllers at the bottom with embeded segue's to new VC's.
In the new VC's I have a TableView & a CollectionView (For example, the Instagram profile).
My issue is that I need the SegmentedController and UIView to scroll with the ContainerView(TableView/CollectionView), at the moment only the ContainerView part scrolls and the parts above that are fixed.
Now I'm guessing I probably need to put everything into a UIScrollView, so I tried that & placed all the costraints correctly. But when It came to configuring it in the Swift file, I only really now how to set the height of the scroll but oviously the height I need can vary and isn't a fixed height!
If anyone can help me here that would be fantastic, or maybe point me towards a similar question already asked here? I have already looked, but did not find anything unfortunately!
Here's an image below explaining basically what I'm after, if above I wasn't very clear..
here is an example you can see: https://github.com/Jackksun/ScrollIssue
the image is here, as I dont have enough reputation I cannot place it in the post!
You can use only UITableViewController. You will define three custom cells and in cellForRowAtIndexPath ask for the Index number, if it is 0 you will set the elements in that cell accordingly
func tableView(tableView: UITableView, cellForRowAtIndexPath indexPath: NSIndexPath) -> UITableViewCell {
var cell: TableViewCell!
// stuff in UIView
if indexPath.row == 0 { set the cell here}
// for UISegmentedController
if indexPath.row == 1 { set the cell here}
// cells that will repeat
if indexPath.row >= 2 { set the cell here}
return cell
}
Update1
Define how many custom cells you will use in Attribute inspector for tableView, you will see them instantly in Storyboard
Update 3
Did you mean this? It is completely table view with 4 custom cells. I didnt use Collection view at all but I think it works as you wanted

(iPhone/iOS) UISearchBar Scope Buttons cover first row of UITableView

I know this question has been asked before, but I have yet to find a true solution. I have a UITableView with a UISearchBar as its tableHeaderView. Whenever the scope buttons appear, they cover the first row of the UITableView.
I have tried using UITableView.contentOffset to offset the UITableView by the height of the scope buttons, and this works until the user taps the UITableView or scrolls it, at which point the UITableView jumps back to its original offset.
The best I've been able to do is set the UISearchBar as a separate item in the view, and simply resize the UITableView dynamically to show or hide it when the user taps a search button. The only problem is that there is no animation, so the transition is sharp.
UPDATE: I solved the problem by implementing a UISearchDisplayController, as this was the cleanest and easiest solution to work with. The UISearchDisplayController automatically shows/hides the scope buttons and moves the UITableView down accordingly. I didn't do this at first because I wanted the UITableView to remain visible rather than initially being blacked out by the UISearchDisplayController, however I've come to realize that the blackout does not hinder any functionality; the user would not have initiated a search if he wanted to continue looking at the UITableView the way it was.
Ideas:
Set the tableHeaderView to a UIView that has the UISearchBar as its subview, and resize that UIView when the scope buttons appear. The UITableView will hopefully respond to that view changing its frame.
Set the UISearchBar as the content of the first cell of the UITableView and use (void)reloadRowsAtIndexPaths:(NSArray *)indexPaths withRowAnimation:(UITableViewRowAnimation)animation when the scope buttons hide or show. Return the proper height to have the cell animate to its new height.
Or you could use the method you describe (UISearchBar as a separate item in the view), and use an animation block to animate the transition so it's less sharp.
[UIView animateWithDuration:1.0 animations:^
{
//change table view frame here
}];
If you adjust the cell height of the header based on if the search controller is active or not, all works well
func tableView(_ tableView: UITableView, heightForHeaderInSection section: Int) -> CGFloat {
var headerHeight: CGFloat = 0.0
if searchController.isActive
{
headerHeight = searchController.searchBar.frame.size.height
}
return headerHeight
}