Resizing a UITableView as shown in the Rdio iOS app

Im trying to reproduce the screen resizing behavior displayed in iOS Rdio app. The screen in question gives an overview of the selected album and contains a UIView in the upper half and a UITableView in the lower half. When the View table scrolls, it first resizes up to fill the screen, and then starts scrolling its contents as soon as the maximum height is reached.

After some searching, I found this question: Dragging and dropping a UITableView , which basically ask for the same thing, however its accepted method is the same as my original thoughts and trial versions, which was to use UIPanGestureRecognizer and resize the table height according to the translation of the pan.

This means that it does not provide the behavior I'm looking for. Using this method allows you to statically drag the table height up or down, and it has an added panGesture problem that overrides the tableViews function, which then prevents the content from scrolling.

The modified behavior of the functions of the Rdio application and feels just like a UIScrollView, it has inertia. You can drag it all the way, click up or down and it resizes smoothly. When the tableView reaches its full-size or original half-size, the remaining inertia is apparently transmitted in the form of a table, causing the cells to scroll as usual for this amount. I know that they have to manipulate UIScrollViews, I just can't figure out how to do this.

As a final note, in the end, I will use AutoLayout on this screen, so I'm wondering how this could potentially interfere or help in this situation.

Update

This approach has brought me closer to the behavior that I'm still looking for. Clicking the View table up behaves exactly the way I wanted (resizing with inertia and continuing to scroll when I reach the maximum height), although with less sensitivity than I would like. However, clicking down does not provide inertia and instantly stops.

- (void)scrollViewDidScroll:(UIScrollView *)scrollView { CGRect scrollViewFrame = scrollView.frame; CGFloat scrollViewYOffset = scrollView.contentOffset.y; if (scrollViewFrame.origin.y <= kTableViewMaxYOrigin || scrollViewFrame.origin.y <= _originalTableViewFrame.origin.y) { scrollViewFrame.origin.y -= scrollViewYOffset; if(scrollViewFrame.origin.y >= kTableViewMaxYOrigin && scrollViewFrame.origin.y <= _originalTableViewFrame.origin.y) { scrollViewFrame.size.height += scrollViewYOffset; scrollView.frame = scrollViewFrame; scrollView.contentOffset = CGPointZero; } } } 
+4
source share
3 answers

I made a version that uses autolayout instead. It took me some time for trial and error to get it right!

Please use comments and ask me if the answer is unclear.

In viewDidLoad save the initial height of your layout constraint by specifying the smallest value by which you want to scroll.

 - (void)viewDidLoad { ... _initialTopLayoutConstraintHeight = self.topLayoutConstraint.constant; ... } - (void)scrollViewDidScroll:(UIScrollView *)scrollView { BOOL leaveScrollAlone = self.topLayoutConstraint.constant == _initialTopLayoutConstraintHeight && scrollView.contentOffset.y <= 0; if (leaveScrollAlone) { // This allows for bounce when swiping your finger downwards and reaching the stopping point return; } // Do some capping of that layout constraint to keep it from going past the range you want it to be. // In this case, I use self.topLayoutGuide.length so that my UICollectionView scales all the way until // it hits the bottom of the navigation bar CGFloat topLayoutConstraintLength = _initialTopLayoutConstraintHeight - scrollView.contentInset.top; topLayoutConstraintLength = MAX(topLayoutConstraintLength, self.topLayoutGuide.length); topLayoutConstraintLength = MIN(topLayoutConstraintLength, _initialTopLayoutConstraintHeight); self.topLayoutConstraint.constant = topLayoutConstraintLength; // Keep content seemingly still while the UICollectionView resizes if (topLayoutConstraintLength > self.topLayoutGuide.length) { scrollView.contentInset = UIEdgeInsetsMake(scrollView.contentInset.top + scrollView.contentOffset.y, scrollView.contentInset.left, scrollView.contentInset.bottom, scrollView.contentInset.right); scrollView.contentOffset = CGPointZero; } // This helps get rid of the extraneous contentInset.top we accumulated for keeping // the content static while the UICollectionView resizes if (scrollView.contentOffset.y < 0) { self.topLayoutConstraint.constant -= scrollView.contentOffset.y; scrollView.contentInset = UIEdgeInsetsMake(scrollView.contentInset.top + scrollView.contentOffset.y, scrollView.contentInset.left, scrollView.contentInset.bottom, scrollView.contentInset.right); } // Prevents strange jittery artifacts [self.view layoutIfNeeded]; } 
+5
source

It turns out that the key component for obtaining smooth inertial resizing in both directions was updating the contents of the scroll contentInset.top by its contents Offset.y.

I believe that this makes sense in retrospect, as if the content inside was already at the top, it can no longer scroll, therefore, a sudden stop, rather than a smooth scrolling. At least that's my understanding.

Another important point was to make sure that the cells had just begun scrolling after reaching their maximum or initial height. This was done simply by setting scrollViews contentOffset to CGPointZero each time the view was resized to its maximum or original height.

Here's an example - (void)scrollViewDidScroll:(UIScrollView *)scrollView , demonstrating how to achieve this effect.

 - (void)scrollViewDidScroll:(UIScrollView *)scrollView { CGRect scrollViewFrame = scrollView.frame; CGFloat scrollViewTopContentInset = scrollView.contentInset.top; CGFloat scrollViewYOffset = scrollView.contentOffset.y; if (scrollViewFrame.origin.y <= kTableViewMaxYOrigin || scrollViewFrame.origin.y <= _originalTableViewFrame.origin.y) { scrollViewFrame.origin.y -= scrollViewYOffset; if(scrollViewFrame.origin.y >= kTableViewMaxYOrigin && scrollViewFrame.origin.y <= _originalTableViewFrame.origin.y) { scrollViewFrame.size.height += scrollViewYOffset; scrollViewTopContentInset += scrollViewYOffset; scrollView.frame = scrollViewFrame; scrollView.contentInset = UIEdgeInsetsMake(scrollViewTopContentInset, 0, 0, 0); scrollView.contentOffset = CGPointZero; } } } 
+3
source

I have not seen the application in question, but from your description ... in the delegate method of tableView -scrollViewDidScroll: set tableView.frame.origin.y to albumView.frame.height - tableView.contentOffset.y and change its height accordingly .

(If you use autorun, you will have to change the restrictions that apply to the tableView frame, not the frame itself.)

0
source

Source: https://habr.com/ru/post/1501185/


All Articles