UICollectionViewController Push Transitions - ios

I'm trying to implement an interface where the user drills down through successive collection views of data, and would like to have each collection view animate to the next one as it's pushed. This has been very frustrating.
I've boiled it down to a very simple test case which I still can't get to work the way I think it ought to.
1- A UINavigationController has a UICollectionViewController which is hardwired to return a numberOfSections == 1, an itemsInSection = 8, and the backgroundColor of the cells is set to redColor in cellForItemAtIndexPath. The associated UICollectionViewFlowLayout.itemSize is set to 80, 80.
2 - When a cell is selected I push a new UICollectionViewController which is hardwired to return a numberOfSections == 1, an itemsInSection == 30, and the backgroundColor of the cells is set to blueColor in cellForItemAtIndexPath. The associated UICollectionViewFlowLayout.itemSize is set to 60, 60.
If I push the second controller with its useLayoutToLayoutNavigationTransitions property set to false, the controller slides in with the proper data display (30 blue cells). If I set useLayoutToLayoutNavigationTransitions to true before pushing, only the layout changes on push. The 8 red cells from the first controller are still displayed, but their size changes to 60, 60.
Apple's UICollectionViewController class reference says that when you set useLayoutToLayoutNavigationTransitions to true, "the navigation controller performs an animated layout change between the contents of the two collection view controllers instead of the traditional push animation", but I'm only getting the layout change.
My test code is stupid simple, so not sure what I might be doing wrong here. Does Apple's class reference misrepresent what the expected behavior should be? Is there any reason to just change layouts when you've pushed a new controller (and theoretically a new data source)? Is there an alternative way to animate to the next collection view?
For what it's worth, here is the only code in my test program other than returning appropriate values for numberOfSections and numberOfItems, and setting appropriate cell background colors.
override func collectionView(collectionView: UICollectionView, didDeselectItemAtIndexPath indexPath: NSIndexPath) {
let itemSize = (collectionViewLayout as! UICollectionViewFlowLayout).itemSize;
let theLayout = UICollectionViewFlowLayout()
theLayout.itemSize = CGSizeMake(itemSize.width - 20, itemSize.height - 20)
let toVC = SecondCollectionViewController(collectionViewLayout:theLayout)
toVC.useLayoutToLayoutNavigationTransitions = true
navigationController?.pushViewController(toVC, animated:true)
}

Related

How to equally space labels in a UIStackView?

As a technical assessment for a job I'm interviewing for, I'm making a basic word search game, where the user looks for translations of a given word in a given language. I've got a fair amount of iOS experience, but I've never done dynamically-generated views with run-time-determined text labels, etc. before.
To be clear, I know this is a job assessment, but regardless of whether I get the job, or whether I'm even able to finish the assessment in time, I think this is an interesting problem and I'd like to learn how to do this, so I'll be finishing this as an app to run in the simulator or on my own phone.
So. I have a view embedded in/controlled by a UINavigationController. I have a couple of informational labels at the top, a set of buttons to perform actions across the bottom of the view, and the main view area needs to contain a 2D grid of characters. I'd like to be able to take an action when a character is tapped, such as highlight the character if it's part of a valid word. I'd like to be able to support grids of different sizes, so I can't just create an autolayout-constrained grid of labels or buttons in Interface Builder.
I've tried various methods for displaying the 2D grid of characters, but the one I thought had the most promise was as follows:
Use a UITableView to represent the rows of characters. Inside each table view cell, use a UIStackView with a dynamically generated collection of UILabels.
To fill my UITableView, I have the following:
func tableView(_ tableView: UITableView, cellForRowAt indexPath: IndexPath) -> UITableViewCell {
let cell = gameGrid.dequeueReusableCell(withIdentifier: "GameGridCell") as! TWSGameGridCell
if indexPath.row < word.grid.count {
cell.characters = word.grid[indexPath.row]
cell.configureCell()
return cell
}
return cell
}
The function in the custom table cell class that configures the cell (ideally to create and display the row of characters) is this:
func configureCell()
{
self.stackView = UIStackView(arrangedSubviews: [UILabel]())
self.stackView.backgroundColor = (UIApplication.shared.delegate as! TWSAppDelegate).appBackgroundColor()
self.stackView.distribution = .fillEqually
let myRect = self.frame
self.stackView.frame = myRect
let characterGridWidth = myRect.width / CGFloat(characters.count)
for cIndex in 0..<characters.count {
let labelRect = CGRect(x: myRect.origin.x + (CGFloat(cIndex) * characterGridWidth), y: myRect.origin.y, width: CGFloat(characterGridWidth), height: myRect.height)
let currentLabel = UILabel(frame: labelRect)
currentLabel.backgroundColor = (UIApplication.shared.delegate as! TWSAppDelegate).appBackgroundColor()
currentLabel.textColor = (UIApplication.shared.delegate as! TWSAppDelegate).appTextColor()
currentLabel.font = UIFont(name: "Palatino", size: 24)
currentLabel.text = characters[cIndex]
self.stackView.addArrangedSubview(currentLabel)
}
}
My guess is that it's running into trouble in that the labels have no visible rect when they're created, so they don't display anywhere.
The resulting view when run in the simulator is a white box covering as many rows of the table view as should be filled with rows of characters, and the rest of the table view shows with the custom background color I'm using), as per this image:
What I'm trying for is for that white box to have the same background color as everything else, and be filled with rows of characters. What am I missing?
Problem might be about adding 'labelRect', you already specify the rect of your stackView. I think regardless of the frame of labels, stackView should naturally be able to create it's inner labels and distribute them inside of itself.
Also can you add the following, after you initialize your stackView, inside your configureCell method:
self.stackView.axis = .horizontal
Edit: from the comment below, the solution was to create the labels (though I switched to buttons for further functionality), add them all to a [UIButton], then use that to create the UIStackView (self.stackView = UIStackView(arrangedSubviews: buttons)).

3D Touch Peek in transform-inverted table view cell

I have a chat application where I am using the inverted table view technique (table view is scaled to (1, -1) with a transform, and all the cells themselves are scale to (1, -1) as well, neutralizing the effect, thus effectively inverting the table view to display the "first" cell at the bottom) to "start" the table view from bottom. Everything works fine, except that I need to implement peek and pop gesture. I've connected a button inside my table view cell to the target view controller, and enabled peek and pop as shown:
The gesture works, though when I 3D touch partially and hold enough to stand out the touched item (but not pop the preview view controller) I am getting inverted view:
How can I make the view pop out with correct transform, while still using the inverted table view?
The reason why it shows the view upside down after a light press is not because it removes the transform from the cell. In fact the transform on the cell stays as it is but the segue pulls the cell view out of the context of the tableView. Therefore the transform on the cell is not counteracted by the transform on the table anymore.
I believe you could fix this by subclassing UIStoryboardSegue but it would probably be much easier to switch your method of starting the table at the bottom. Check out the accepted answer on this question.
I used a slightly modified version which accounts for the navigation bar and status bar:
func updateTableContentInset() {
let numRows = tableView(self.tableView, numberOfRowsInSection: 0)
var contentInsetTop = self.tableView.bounds.size.height - (self.navigationController?.navigationBar.frame.size.height)! - 20
for i in 0..<numRows {
let rowRect = self.tableView.rectForRow(at: IndexPath(item: i, section: 0))
contentInsetTop -= rowRect.size.height
if contentInsetTop <= 0 {
contentInsetTop = 0
}
}
self.tableView.contentInset = UIEdgeInsetsMake(contentInsetTop, 0, 0, 0)
}
Just add this to your UITableViewController and call it on viewDidLoad() and every time a new row is added to the table.
After adding a new row and then calling updateTableContentInset() you will have to scroll to the bottom like this:
tableView.scrollToRow(at: indexPath, at: .bottom, animated: true)
Since there is nothing upside down here you will not have problems with your Peek segue.

How to make right scrollable menu with buttons?

I want to make scrollable menu (first view controller) with 4 buttons. Every button linked with specific view controller. But I want to make it specific: after app launching user must see only first three buttons on every iPhone version (4, 4.7, 5.5) and he needs to scroll down to see one more button. Should I use stack view with scrollview? Should I use UICollectionView (I found that's good for images but not for buttons)?
Thanks everybody for help!
If you use a UICollectionViewController (or UITableViewController, either would work) you can layout your storyboard like this:
Then in your MyTableViewController (again, this also works with a UICollectionViewController) you can implement the following method to set the cell size equal to a third of the window height:
override func tableView(_ tableView: UITableView, heightForRowAt indexPath: IndexPath) -> CGFloat {
// get the height for the current view
let viewHeight = self.view.frame.height
// since we want 3 rows to appear at a time, simply divide the viewHeight by 3
return viewHeight / 3
}

How to I build a continuous parallax scroll/Collection view?

I am looking to build a continuous parallax scroll like this.
http://www.screencast.com/t/7Z48zkkW
But my Requirement is view and then CollectionView like this
When collection view scroll then changes upper view height.
and yes upper view and collection view is separate.
I Have also navigation bar it also goes up when user scroll
You can use collectionView with section header for this effect. However, the effect collectionView bounced below the search can't be achieved by this way instead the whole view will bounce.
Simplest solution for iOS 9 +
1) Make a cell for items above the search
2) Make reusableView for search bar (section header)
3) Make cells for those pictures
i.e. you will have two cell's prototypes and one reusableView
In viewDidLoad of viewController with collectionView use following code so that header of section gets pinned always in top:
let layout = collectionView.collectionViewLayout as? UICollectionViewFlowLayout // casting is required because UICollectionViewLayout doesn't offer header pin. Its feature of UICollectionViewFlowLayout
layout?.sectionHeadersPinToVisibleBounds = true
Number of section: Keep it 2
Number of row for section == 0 will be 1 which will be items above search
Number of row for section == 2 will be number of images you have
Now, in collection view datasource you have a method viewForSupplementaryElementOfKind which you need to implement to get sectionHeaderView.
implement referenceSizeForHeaderInSection function for hiding sectionHeader for first section (section == 0) by returning CGSize(width: 0, height: 0) and for second section (section == 1) return size of searchBar as you want.
in cellForItemAtIndexPath return cells according to section.
EDIT
I think you don't need sticky header at top like that search bar. So its better you use collectionView with section header. (section header contains the red View you marked)

How do I create dynamic views in swift?

I am making an IOS app where the main layout is a UITableView, and cells are completely dynamic and loaded from server. Each tableview item is a different layout.
For example, lets take first item of the tableview:
Server tells it should have a label, 2 buttons and a textbox, it should be created by code. I figured out how to create those elements themselves, the problem is how do I position them?
Ideally I would like to add each layout item under the previous one. And tableviewcell should wrap those, grow or collapse according to views.
I am fairly new to IOS/Swift. Is there any way to implment this easily? In android I just used a linearlayout and added views one by one. Does IOS have something like that? Or do I have to manually set heights, widths, and coordinates of all items?
Thanks in advance.
Here is some code:
if let Actions = AppData["Forms"][0]["AvailableActions"].array{
for var i = 0 ; i < Actions.count ; ++i {
if Actions[i].int == 1{
let actionButton1 = UIButton(frame: CGRectMake(0, 0, 96, 30))
actionButton1.setTitle("View", forState: .Normal)
actionButton1.setTitleColor(UIColor.redColor(), forState: .Normal)
cell.actionsLayout.addSubview(actionButton1)
}
}
}
You can do with self-sizing cells, in this case you just need to
Give proper constraints to your table view cell subviews,(i.e all
your subviews should be connected to each other and topmost
subview should have top-space constraints and bottommost subview should have bottom-space constraints).
Specify the estimatedRowHeight of your table view.
Set the rowHeight of your table view to UITableViewAutomaticDimension
For step 2-3 steps mentioned above,just add following code in your viewDidLoad -
tableView.estimatedRowHeight = 44.0
tableView.rowHeight = UITableViewAutomaticDimension
For understanding of self-sizing cells you can follow this link
http://www.appcoda.com/self-sizing-cells/

Resources