I have a UITableView which covers half of the screen in iPad portrait mode. Whenever I click, expand button which calculates and animates the tableview's superview's frame to cover the whole screen, scrolling becomes very messy and flickering even with a single row. Especially bounce animation seems to be longer. TableView is masked with autoresizeheight. After I restore superview's frame, tableview scrolling becomes smoother again. Are there any relation between tableview's initial frame and the scrolling speed? What are the possible root causes for this kind of behavior?
Maybe you inserted the resize inside your cellForRowAtIndexPath method, so it sets the size tableview every time you scroll. I inserted this code snippet inside a check in viewDidLoad, then the size will be set just once at the beginning and everything works.
CGPoint tvFrameO = _TableView.frame.origin;
CGSize tvFrameS = _TableView.frame.size;
float valueToResize = 50.0f;
_TableView.frame = CGRectMake(tvFrameO.x,
tvFrameO.y,
tvFrameS.width,
tvFrameS.height + valueToResize);
Related
So I have created a UIScrollView as a subview of the view controller's view in Interface builder and set all auto layout constraints so that it resizes to fill its superview (Trailing, leading, bottom and top constrains set to zero with regards to its superview).
When I run the application, the scrollview does not initially update its frame to be the same size as its superview. the scrollview frame.size.width = 320 even though I am running it on iPhone 6 or iPhone 6 plus simulator.
As soon as I start scrolling, the scrollview frame gets updated to the correct value (same as its superview). why is this happening? shouldn't auto layout automatically resize the scrollview in relation to its superview?
The only way I managed to fix this is to add the following in viewDidLoad:
scrollView.frame = view.frame.
Any ideas why this is happening? It does not seem logical.
Many thanks
Ok, so after some experimentation, I figured it out.
I was checking the scrollview frame size in viewDidLoad and it was returning 320
However, it seems that auto layout will only do resizing AFTER viewDidLoad and will call viewDidLayoutSubviews() after it has finished resizing/repositioning...etc
Therefore, when I check the frame size inside viewDidLayoutSubviews, I get the right frame size 375 (for iPhone 6).
Thank you
Description
If you use the Spotify app on iOS or Android (I am developing on iOS), you'll notice that if you select a playlist, and drag the UITableView with your songs up, the following happens:
The table doesn't scroll, it just moves up at the same speed it would scroll, and the images above it move slower than the table, creating a parallax scrolling effect.
Once the tableview reaches the top of the view, however, it behaves like a normal scrolling tableview.
I've tried to achieve this effect a few different ways, which didn't work for me.
Here is a video of this effect: https://www.dropbox.com/s/n7npk4lrzmag0sn/IMG_9331.MOV
What I tried
I wanted the UITableView and the UIScrollView above it, to move upwards when the user scrolled either one, so I used
- (void)scrollViewDidScroll:(UIScrollView *)scrollView
and based on the direction of the scroll, I changed the frame position of the tableview and the UIScrollView above it.
The problem with this method is that the tableview bounces, which ruins the effect.
To get rid of bouncing, I tried the following:
_userTableView.bounces = NO;
However, now because the tableview wouldn't scroll, scrollViewDidScroll is never called.
The other thing I tried was subclassing the UITableView, and overriding the
- (UIView *)hitTest:(CGPoint)point withEvent:(UIEvent *)event
hitTest method to detect a scroll gesture on the tableview, the problems with this are:
Only 1 CGPoint is passed -- it's impossible to know if the UITableView was touched, or scrolled.
Since scrolling is disabled, I can't use self.decelerating to check if the tableview was just scrolled -- the tableview will never be decelerating
Making the table decelerate as it moves up the view, and continue scrolling with the same momentum after its reached the top will be very challenging; In the Spotify app, a user can drag the table with a speed high enough to make the table view move to the top of the view AND continue scrolling, all in one motion.
The tableview should grow in size to accommodate more cells added to the view (without scrolling), as it moves up the view, or it should start out with the same size as the view. After it reaches the top it should begin scrolling like a normal tableview -- with the same momentum it has after the upward movement.
Any suggestions on how I can solve this?
Thank you very much.
For the effect you have shown, I think a tableHeaderView with the parallax content as a subview will suffice.
In -scrollViewDidScroll: (or KVO for contentOffset), you set the center of the parallax subview to the center of the visible bounds of the tableHeaderView. You can also adjust how much the content "sticks" to the center by multiplying a factor.
CGRect tableViewHeaderVisibleBounds = tableViewHeader.bounds;
tableViewHeaderVisibleBounds.origin.y = MAX(0, MIN(CGRectGetHeight(tableViewHeader.bounds), tableView.contentOffset.y));
tableViewHeaderVisibleBounds.size.height -= tableViewHeaderVisibleBounds.origin.y;
CGFloat factor = 1.8f; // less than 0.5:stick to top // greater than 0.5:stick to bottom
parallaxContentView.center = (CGPoint){
.x = parallaxContentView.center.x,
.y = (CGRectGetMinY(tableViewHeaderVisibleBounds)
+ (CGRectGetHeight(tableViewHeaderVisibleBounds) * factor))
};
I coded this inside my head so just make necessary adjustments, but I hope you get the basic idea.
THE PROBLEM:
I have an NSScrollView. I'm using it to implement a custom "Table View" with rows of data that are actually NSViews. (Note: this is not an instance of NSTableView.)
As I scroll vertically (there is no horizontal scrolling), I use a boundsChanged notification to add (as subviews of the scrollView's contentView) the NSViews that become visible (the ones with frames that intersect the scrollView's document visible rect) and to remove the ones that are no longer visible (frames outside of the scrollView's visible rect.)
The process works wonderfully except when it comes to inertial scrolling. If I have my cursor over cell X and I flick the trackpad to scroll downwards FAST with inertia, cell X quickly leaves the visible rect and, as such, is removed from the scrollView's contentView. BUT, that kills inertial scrolling. If I do NOT remove cell X as a subView, then inertial scrolling works perfectly.
WHAT I NEED:
A way to keep inertial scrolling while still removing the NSView that the cursor happened to be on top of when the user started the scrolling gesture.
WHAT I'VE TRIED:
I've looked at NSResponder's method:
-scrollWheel:(NSEvent *)theEvent
The default implementation passes scrollWheel to the next responder. So, I subclassed NSScrollView and implemented this method to try to stop it from passing the scrollWheel event to the individual subViews inside the scrollView's contentView. Didn't work.
So then I went into my NSViews (the ones I'm adding to the contentView) and overrode scrollWheel to pass the event back to the scrollView itself. Didn't work.
I still get scrolling in both cases, but not with inertia.
Any ideas? Thanks!
I haven't done this exact thing in Cocoa, but I'd probably be thinking about simply recycling your NSView object, as soon as its off the visible rect, by removing its subviews, then changing its frame to be in place to scroll back onto the visible rect from the top.
You can obviously do this by simply updating its frame, and avoid having to remove and re-add it to the NSScrollView.
I've built an app using the UITabBar template. I have a few tabbar items, one item displays a view. That view has a UIScrollView element that has paging enabled to mimic the behaviour of the iPhone springboard i.e. pages that can be scrolled left to right.
I'm trying to drop in a UIPageControl, so I've resize the UIScrollView so that it's slightly shorter than the parent UIView height and have placed a UIPageControl below it.
When I run the app the UIScrollView is always 100% of the height of the parent UIView and I can't see the UIPageControl.
I've got the following code in my viewDidLoad method of the view controller for the tab:
UIScrollView *tempScrollView=(UIScrollView *)self.view;
tempScrollView.contentSize=CGSizeMake(640,377);
This sets the content size ok and I can scroll left to right. I've tried adding:
tempScrollView.frame=CGRectMake(0, 0, 640, 377);
To to resize the scroll view but it still shows 100%. See diagram below showing the issue:
I think you shouldn't resize the frame to 640, 377 because it would make the paging stop working, once the contentSize would be the same as the frame size.
One solution would be to set the desired frame size in the interface builder (like the left most figure) and set proper autosizing masks. I gues what you are looking for is the configuration below
To check if the changes are working, I would use a uiscrollview of height visibly smaller, just to make sure the behaviour is the desired.
If you want your view to scroll you need to change the tempScrollView.contentSize to be bigger than tempScrollView.frame
If you do this:
CGFloat contentWidth = tempScrollView.frame.size.width*2;
tempScrollView.contentSize=CGSizeMake(contentWidth,377);
You will have 2 pages.
You need to activate paging too with:
[tempScrollView setPagingEnabled:TRUE];
I have a NSScrollView with a custom view inside and when I resize the NSScrollView, the height grows and it scrolls upward. Unless there is an easier way, I'll probably have to register a notification to see if the view changes size and then adjust the scrollPoint: to a new point. I'm having trouble getting method to work smoothly.
Thanks!
This question comes up from time to time, because it's not obvious.
The content will pin to the top left if [contentView isFlipped] == YES.