My goal is pretty straightforward:
The user should be able to move cells in the UITableView up and down by using the provided buttons. I want the new selected cell to appear exactly where the old selected cell was with the exception of the scrolling being at the the beginning of end of the tableview.
I tried using
[table selectRowAtIndexPath:newIndexPath animated:false scrollPosition:UITableViewScrollPositionMiddle];
But the problem is that the row is always moved to the same position near the center of the screen which I don't want.
I want to center the
table.contentOffset.y
exactly where I am programmatically placing it. However, when I set this with
[table setContentOffset:CGPointMake(0, newVerticalContentOffset)];
so I did exactly that. Now I have the problem of the scrolling going way outside the the table and even the normal bounce range. The only way to get it to 'bounce' back is if the user scroll touches the list.
I also tried programmatically setting the offset to the 'min' and 'max' of it happened to go out of those bounds. However, I realized that this was complicated because I have to add the height of the navigation bar and the status bar to get the top coordinates and get the content size to determine the bottom. I think it would be easier if there was simply a way to programmatically 'bounce' or 'release' the tableview back into place. I tried calling the table's delegate with flags like
scrollViewDidScroll
This crashes my application. I realized that even if I did perform one of these last two solutions, that the action would still not represent my goal. If I move a cell down from the top, the view scrolls with it. I do not want that to happen because it is very close to the top. In this case, I wouldn't mind it making its way to the middle before scrolling the view.
The best idea I have so far is somehow attempting to center scroll the cell and if it is able to be centered (meaning it is not near the top or bottom), not to actually center it.
I thought about performing a centering then checking if the y coordinate changed by exactly 1 cell and leaving it if it did, otherwise using the old position. However, I imagine that the user may be somewhere near the middle of the list and happens to be exactly 1 cell away from the middle. When he moves the cell, it will move 'unexpectedly' which is not what I want.
Related
I work on a app, nothing fancy, but since is my first app, there alot of stuff I never did before.
So, I'm trying to build a view like the image attached.
I've looked up on the Internet how to do something like that but I don't know what is better/cleaner way to do.
As you can see I have 3 areas: the title, the tableview in the middle and a button on the lower side.
The table will expand based on the content (3 lines or 30 lines) so the button must move down and a scroll bar should appear.
So, my idea:
Using a tableview having 3 static cells: one to put my title, second to put a tableview having prototypes cells, and a third one for the button.
That way I would have a scroll bar when the table in the middle grows, pushing the button.
Here I have a question: how to have the table view (the inner tableview) resize itself, pushing the height of the middle row, instead of having a fixed width with a scroll.
Is the the best way to achieve that?
Thanks for any idea.
C.C.
Are you sure you want to push the bottom UI down as the table grows? You say whether the table has 3 or 30 cells, but what if it has 300 cells? Your user then has to scroll to the bottom to reach the button and tab bar. I think you'll find that it would be better to use Auto Layout and let the table fill the screen space between the title and the button. The table will scroll so if you have 300 cells then you can scroll through inside the table's available area.
The advantage here is you won't be fighting with Auto Layout. If your user rotates an iPhone 4S into landscape you'll only have a few rows displayed but conversely if they run in portrait on an iPad you'll fill all of that space.
As for how to do it, the other advantage is that you don't need the nested table you describe. Use a constraint to attach the title label to the top layout guide, then attach the tab bar to the bottom layout guide. Put a vertical space constraint between the button and the tab bar. Finally, put vertical space constraints between the table and the title & the table and the button. (You'll need to implement constraints for the horizontal axis as well, but that's pretty simple.)
There's are refinements you can put into place if you want the table to shrink to fit if there are only 3 rows, but this should get you started and you may not want that anyway.
Key point: the tableView wants to scroll naturally, inside a view sized to fit the display. Don't change that behavior unless you really have to. Neither your users nor UIKit expects what you're trying to do, and the table is going to fight you all the way about it.
Nesting UIScrollViews (which your nested table would do) works, but it opens up a lot of bad UI flow problems. In my experience every time somebody wants nested scrollViews there's some other approach which is more "natural" to iOS interface paradigms.
If you're dead set on the UI you described I wouldn't use a table for the outer structure. Just make it a UIScrollView and calculate your content size based on the number of rows the table will display. You can actually do that, and then use Auto Layout as I described.
How can I stack cells (in a UICollectionView) on top of each other? Feedly does it quiet well and I was wondering if I can somehow manipulate the zIndex property to get a similar effect in navigation of a UICollectionView.
Or am I wasting my time with UICollectionViews and should be looking into changing my approach with perhaps a Container View Controller?
In order to accomplish this my team added a basic full page horizontal cover flow layout to a uicollectionview. We then added a pan gesture recognizer and disabled scrolling on the collectionView controller. As soon as the pan gesture starts we screen cap the cell and place the image over the collectionView. Once that is done we manually change the page of the collectionView to the next page behind the screenshot. We then animate the uiimage (the screen cap of the previous page) along the path of the gesture. If it goes past a threshold we commit the animation and remove the image and you get the full effect of a previewed collectionView cell.
Unfortunately the threshold checking is a bit tedious because you must revert. Also the animation for bringing a cell back is a little quirky. With this method if you don't add it as a special case then it looks the cell is always behind. Since we want it to look like a stack we made sure that it looks like you are pulling the previous cell from offscreen to the top of the stack. This is done by keeping a collection (NSArray) of cell screenshots that matches are data source so basically we can just grab the image based on indexPath.row. Do the pan gesture recognizer to bring it back on to the stack. If it passes the threshold we commit the animation and at the end change the current cell of the collection view and remove the screenshot. So it feels seamless.
There is really nice write up regarding this, jump onto this website and you will find everything you need.
http://skeuo.com/uicollectionview-custom-layout-tutorial
Basically what you are looking for is the CustomLayout.
You can use CHTCollectionViewWaterfallLayout to create pinterest-like-layout. It's created on top of UICollectionView.
I've got a UICollectionView that is formatted as a single, horizontally scrollable row across the screen. It represents the next-up entries in a queue, so whenever items are added and deleted, it always happens at Index 0 (the far left of the View) and then the whole thing moves forward or back by one space. It's super-simple in the code, just:
[_collectionviewNextUp insertItemsAtIndexPaths:[NSArray arrayWithObject:[NSIndexPath indexPathForRow:0 inSection:0]]];
and
[_collectionviewNextUp deleteItemsAtIndexPaths:[NSArray arrayWithObject:[NSIndexPath indexPathForRow:0 inSection:0]]];
Everything is working properly, except the animations for insertItemsAtIndexPaths: and deleteItemsAtIndexPaths:, specifically when the CollectionView items extend beyond the edge of the screen. As long as there are only 6 items in the queue (the number that can be seen at once), it animates perfectly; but 7 items or more and the animation gets weird. Delete an item (from the left) and it also animates one being added to the right; add an item (on the left) and it also animates one being deleted from the right. Even if the queue is 50 items long, it always animates item #6 (the last visible one onscreen) disappearing and reappearing. There are no errors or warnings or anything, and I'm left with the correct number of items in the View after the animation is over, it just animates a cell being added/deleted at the edge of the screen.
My theory is that the reusable cells are being animated. Does that sound like it could be a thing? Scrolling left and right works perfectly, but inserting and deleting seems to only animate in pairs, and they always "fly in" and "fly out" in the same direction, as though one is taking the other's place. It looks (to my inexperienced eye) like the cell on the end is being flown over and added to the front, or the one on the front is being moved over to the end.
I've tried to do research on this but all I can find are animation problems that throw errors and exceptions, which mine doesn't do. Has anyone else experienced this? And can anyone offer a fix, wherein the Index 0 item gets animated and the rest just smoothly slide onto and off of the screen?
I assume you're using flow layout. Flow layout is very buggy animating items across the layoutAttributesForElementsInRect: boundary (i.e. items moving in and out of view). In my experience, you can fix some of these issues by overriding the 'initialLayoutAttributesForAppearingItem' & finalLayoutAttributesForDisappearingItemAtIndexPath: methods and correcting the frames when the super class returns incorrect values. Here is a successful answer to a very similar issue.
I open sourced a simple uniform grid layout VCollectionViewGridLayout that greatly improves animations over what UICollectionViewFlowLayout provides. However, it currently only does vertical scrolling. But if you went in there and transposed all of the horizontal and vertical calculations, I'm sure it would solve your issue.
I'm trying to create a custom accordion-list. On tap it should expand the tapped line and the next lines should change their position relative to the expanded one. By tapping it again it should contract. By tapping another non-expanded line, the expanded line should contract and the tapped one should expand.
I tried to solve this by using subviews with TapGestureRecognizers. I have a undefined number of lines. On tap I change the height of the tapped line and rearrange the position of the following lines manually. Now, it's getting really confusing to handle all possibilities of expanding/contraction/positioning. I'm looking for a more comfortable way to handle this.
Is there any way to align the subviews vertically so that the positions of the lines change automatically if one height changes?
I think a better solution is to use the tableView where the cells will contribute your custom view.Positioning and all will be handled by tableview itself.
If you are working with iOS 6, this should be pretty easy with constraints. Specify that each view is to be located a certain distance from the bottom of the one above it, and when the ones above it move or expand or contract, that constraint should force everything else to move to keep the gap you specified.
EDIT: I just realized that you mentioned in your OP that you may not know for sure how many views you are going to need ahead of time. That probably makes the table view method others have suggested more favorable. It is still possible to do with constraints though (and I found a pretty detailed tutorial here that goes over everything).
I'm using the great iOS control iCarousel's Wheel type and I want all of the buttons it contains to be usable / selectable at any time (i.e. I can tap any of them, no matter which one is currently at the top of the wheel). The user can still scroll the wheel as normal, but no matter which button they tap, it should register.
The current behavior seems inconsistent: if I tap one of the buttons directly next to the center one (to its left or right), that button moves into the center slot. Clicking one of the buttons two positions away 'sometimes' causes it to scroll to that letter, sometimes it's ignored. Any other buttons are always ignored.
Is this possible to set up, preferably without hugely modifying the class? I'm by no means an expert, but am learning every day :)
Thanks in advance.
Set carousel.centerItemWhenSelected = NO;
That will disable the behaviour where buttons other than the centre one are scrolled to the centre when you tap them.
As for the reason why some are not responding to taps at all, it is most likely because the frame of your carousel view is too small and the tap events are outside of the frame.
If you set carousel.clipsToBounds = YES; it will crop the carousel views to the frame as well so you'll be able to see exactly what size your carousel actually is.