UIScrollView - set negative contentOffset when bounce animation starts - ios

I am using a UITableView to achieve a scale/unblur effect on my user's profile picture (like in the Spotify App) when I pull down the UITableView to a negative contentOffset.y. This all works fine...
Now, when a user pulls down to a contentOffset.y smaller or equal to a certain value -let's call it maintainOffsetY = 70.0- and he "lets go" of the view, I would like to maintain this contentOffset until the user "pushes" the view up again, instead of the view to automatically bounce back to contentOffset = (0,0) again.
In order to achieve this, I must know when the touches began and ended, which I can do with the following delegate methods:
- (void) scrollViewWillBeginDragging:(UIScrollView *)scrollView {
// is like touches begin
if ([scrollView isEqual:_tableView]) {
NSLog(#"touches began");
_touchesEnded = NO;
}
}
- (void) scrollViewWillEndDragging:(UIScrollView *)scrollView withVelocity:(CGPoint)velocity targetContentOffset:(inout CGPoint *)targetContentOffset {
// is like touches ended
NSLog(#"touches ended");
if ([scrollView isEqual:_tableView]) {
_touchesEnded = YES;
}
}
Then in
- (void)scrollViewDidScroll:(UIScrollView *)scrollView
I check if the contentOffset.y is smaller than or equal to maintainOffsetY and if the user has already "let go" of the table, so it is about to bounce (or already bouncing) back to contentOffset = (0,0).
It does not seem to be possible to let it bounce back only to the maintainOffsetY. Does anybody know a workaround or have an idea on how to solve this?
Any help is much appreciated!

To set a negative offset to a scroll view you can use this.
You need to save the initial content inset of scroll view. It can be not 0 already, if you have translucent nav bar for example.
- (void)viewDidAppear:(BOOL)animated {
[super viewDidAppear:animated];
contentInsetTopInitial = self.tableView.contentInset.top;
}
Then write this.
- (void)scrollViewWillEndDragging:(UIScrollView *)scrollView withVelocity:(CGPoint)velocity targetContentOffset:(inout CGPoint *)targetContentOffset {
CGPoint contentOffset = scrollView.contentOffset; // need to save contentOffset before changing contentInset
CGFloat contentOffsetY = contentOffset.y + contentInsetTopInitial; // calculate pure offset, without inset
if (contentOffsetY < -maintainOffsetY) {
scrollView.contentInset = UIEdgeInsetsMake(contentInsetTopInitial + maintainOffsetY, 0, maintainOffsetY, 0);
[scrollView setContentOffset:contentOffset animated:NO];
}
}
Hope this will help.

Related

Zoom two UIScrollViews synchronously.

I have two UIScrollViews. Both the scroll views contain an image. Now, I want to zoom second scroll view programmatically if I zoom in the first scroll view manually. I am using -(UIView *)viewForZoomingInScrollView:(UIScrollView *)scrollView method to manually zoom the first scroll view. The second scroll view should be zoomed to the same point and scale. How can I achieve this?
By using the tag or object of those two scrollviews you can identify the which scroll view you need zoom in viewForZoomingInScrollView method.
e.g
//need to set the tag for scrollviews
-(UIView *)viewForZoomingInScrollView:(UIScrollView *)scrollView
{
if(scrollView.tag == 1)
{
return firstImageView;
}
return secondImageView;
}
OR
//need to create the object of used scrollviews
-(UIView *)viewForZoomingInScrollView:(UIScrollView *)scrollView
{
if(scrollView == objScrollViewFirst)
{
return firstImageView;
}
return secondImageView;
}
How about something like this:
CGRect zoomRect;
zoomRect.size.height = manualScrollView.frame.size.height / manualScrollView.zoomScale;
zoomRect.size.width = manualScrollView.frame.size.width / manualScrollView.zoomScale;
zoomRect.origin.x = manualScrollView.center.x - (zoomRect.size.width / 2.0);
zoomRect.origin.y = manualScrollView.center.y - (zoomRect.size.height / 2.0);
[autoScrollView zoomToRect:zoomRect animated:YES];
[autoScrollView setZoomScale:manualScrollView.zoomScale animated:YES];
Try something like this in the UIScrollViewDelegate method:
override func scrollViewDidScroll(scrollView: UIScrollView){
otherScrollView.contentOffset = scrollView.contentOffset
otherScrollView.zoomScale = scrollView.zoomScale
}

How can I get how the Scrollview is moving?

I'm trying to move a view while the scrollview is being scrolled with the same intensity.
I'm trying:
- (void)scrollViewDidScroll:(UIScrollView *)scrollView {
// here I detect when user scroll
}
How could I get the intensity that the scrollview is being scrolled?
Try to use these methods:
- (void)scrollViewWillBeginDragging:(UIScrollView *)scrollView
{
//scrolling on
NSLog(#"scrollViewWillBeginDragging");
}
- (void)scrollViewDidEndDragging:(UIScrollView *)scrollView willDecelerate:(BOOL)decelerate
{
if(!decelerate) {
//not scrolling
}
NSLog(#"scrollViewDidEndDragging");
}
You can do that by reading the contentOffset property on the scrollView
// You can save this as a property or an iVar
CGPoint lastContentOffset;
-(void)scrollViewWillBeginDragging:(UIScrollView *)scrollView{
lastContentOffset = scrollView.contentOffset;
}
-(void)scrollViewDidScroll:(UIScrollView *)scrollView {
CGPoint difference = CGPointSubstract(scrollView.contentOffset, lastContentOffset);
lastContentOffset = scrollView.contentOffset;
// Use difference to know by how much the scroll view scrolled
// IMPORTANT: CGPointSubstract is not a standard function, you can implement it yourself.
}
I don't want to give you the full code but i'll help with how to achieve it.
1) You need to use the time.
2) When the time difference is greater than an amount of time passed to measure (0.05s?)
3) Check what the old content offset is compared to the new one
4) The difference is your velocity
5) reset your current timer
6) set current offsets to last offset
Hope this helps
Ben
distance calcs
CGFloat distanceY = currentOffset.y - lastOffset.y;
CGFloat distanceX = currentOffset.X - lastOffset.X;

How to Calculate Scrollview width and height on every scroll in iOS

I have Scrollview using for displaying images along with two buttons previous and next.
Now my problem is when the user is scrolling the image I want to identify whether it is from right to left scroll or vice versa. For this purpose I have to calculate scrollview contentOffset and scrollview frame size but I don't know how to calculate those values.
Still now I used:
- (void)scrollViewWillEndDragging:(UIScrollView *)scrollView withVelocity:(CGPoint)velocity targetContentOffset:(inout CGPoint *)targetContentOffset NS_AVAILABLE_IOS(5_0){}
this method.
need any suggestions.
- (void)scrollViewDidEndDragging:(UIScrollView *)scrollView1 willDecelerate:(BOOL)decelerate;
{
CGFloat pageWidth = scrollView.frame.size.width;
float fractionalPage = scrollView.contentOffset.x / pageWidth;
NSInteger page = lround(fractionalPage);
if (previousPage != page){
if ([scrollView.panGestureRecognizer translationInView:scrollView.superview].x > 0){
NSLog(#"-1");
} else {
NSLog(#"+1");
}
}
}
Hi if you are scrolling Horizontally you will get to know whether you are going next or previous depending upon velocity.x
velocity.x > 0 ?(int) _currentIndex + 1 :(int) _currentIndex - 1;
-(void) scrollViewWillBeginDragging:(UIScrollView *)scrollView {
CGFloat xAxisVisible= self.uiScrollDetails.contentOffset.x;
self.currentIndex=xAxisVisible/320;
NSLog(#"Dragging - You are now on page %i",(int) self.currentIndex);
}

Make a UI scroll view scroll with a UIPageViewController

I am creating an app where I am trying to have a pagescrollviewcontroller swipe through screens and have the top "nav" bar titles scroll real time with the titles
i have the title bar view as a custom view and I am able to access the scroll delegate methods for both the custom scroll view and the pageview controller. However. I don't see how to access the real time scroll pos? I know it is possible because twitter does it (really can't shouldn't be in anyone's vocabulary) but I am not sure how to achieve this.
a picture
the home title swipes at the same scroll pos as the pagecontrollers.
current code:
- (void)scrollViewWillBeginDragging:(UIScrollView *)scrollView {
if(scrollView.tag == 100) {
CGPoint point = CGPointMake(mainScrollView.contentOffset.x * 1,0);
[titleSwipe setContentOffset:point animated:YES];
}
else {
mainScrollView.contentOffset = CGPointMake(0,1);
[mainScrollView setContentOffset:titleSwipe.contentOffset animated:YES];
}
}
- (void)scrollViewDidEndDragging:(UIScrollView *)scrollView willDecelerate: (BOOL)decelerate {
CGPoint point = CGPointMake(mainScrollView.contentOffset.x * 2,0);
[titleSwipe setContentOffset:point animated:YES];
}
You'll find the real time position in scrollViewDidScroll:
- (void)scrollViewDidScroll:(UIScrollView *)scrollView {
// X scroll
//
CGFloat percentage = scrollView.contentOffset.x / scrollView.contentSize.width;
NSLog(#"Scrolled percentage: %f", percentage);
}
Hope that helps!

Scrollview wrong scrolling on custom control

I have a custom control that looks like this:
It allows you to pick multiplier from 1 to 10. Inside it is scroll view with multiple UILabels in it. Each label has tag and using the tag I calculate needed positions for label.
The user may either swipe to move this or tap on the number to make it move automatically.
But I have faced the problem - if the view is scrolling and I tap on the number while it is scrolling, it will stop not on the number I tapped on, but on some other number.
When the scroll view is not scrolling taps work fine. Here is relevant code:
This method is needed to stop on the number when it ends scrolling:
- (void)scrollViewWillEndDragging:(UIScrollView *)scrollView withVelocity:(CGPoint)velocity targetContentOffset:(inout CGPoint *)targetContentOffset
{
NSInteger targetIndex = targetContentOffset->x / (self.frame.size.width / 4.0) ;
*targetContentOffset = CGPointMake((targetIndex) * (self.frame.size.width / 4.0), targetContentOffset->y);
if (targetIndex > [self.dataSource numberOfItemsInPicker:self] - 1) {
targetIndex = [self.dataSource numberOfItemsInPicker:self] - 1;
}
if (self.gameName) {
for (int i=0; i<self.labels.count; i++) {
UILabel *label = self.labels[i];
if (i == targetIndex) {
label.textColor = [GeneralHelper colorForGame:self.gameName];
}
else {
if ([self.delegate respondsToSelector:#selector(colorForTextForSmallNumberPicker:)]) {
label.textColor = [self.delegate colorForTextForSmallNumberPicker:self];
}
}
}
}
if (self.delegate) {
[self.delegate smallNumberPickerView:self didPickNumberAtIndex:targetIndex];
}
}
This is the code that determines position of labels in scroll view:
- (CGPoint)offsetForIndex:(NSUInteger)index
{
return CGPointMake(roundf((self.frame.size.width / 4.) * index), 0.);
}
And I think this is the offending code that handles tap gesture recognizer:
- (void)handleTapGesture:(UIGestureRecognizer *)recognizer
{
if (recognizer.state != UIGestureRecognizerStateEnded) {
return;
}
[self.scrollView setContentOffset:[self offsetForIndex:recognizer.view.tag - LABELS_START_TAG] animated:YES];
}
My ideas what happens is that during scrolling frame is wrong, or positions are wrong, but I have no idea how to handle this. I noticed that when I tap I NSLog target offset and it is wrong, and if it is not scrolling - I will get right offset.
What can I do about this?
There was an error in calculations. This line:
return CGPointMake(roundf((self.frame.size.width / 4.) * index), 0.);
It divided by 4 but the labels were actually smaller then 1/4 of the picker, so I got wrong results.

Resources