How to zoom when scroll UIScrollView - iphone

I add few labels in UIScrollView and I want when I scroll, the the middle label font size can become bigger. And the previous middle label font size shrinks to smaller. And the change happens gradually. Like below. Label 1 move to left shrink smaller and label 2 move to middle becomes bigger. All labels in a UIScroll view.
I tried some, like when scroll I tried zoom scroll page, seems complex than I thought...
Anyone has good idea? Thanks!

Pretty simple really. Just stick a UIScrollViewDelegate to the scrollview and do something like this..
-(void)scrollViewDidScroll:(UIScrollView *)scrollView
{
for (int i = 0; i < [scrollView.subviews count]; i++) {
UIView *v = [scrollView.subviews objectAtIndex:i];
float position = v.center.x - scrollView.contentOffset.x;
float offset = 2.0 - (abs(scrollView.center.x - position) * 1.0) / scrollView.center.x;
v.transform = CGAffineTransformIdentity;
v.transform = CGAffineTransformScale(v.transform, offset, offset);
}
}
But, if you aren't impressed by the affine transform, you could still scale the rect using the offset factor and set the UILabel to adjustsFontSizeToFitWidth... and you are done!
Just make sure there is enough space! Else it could get out of hand very easily.
Assumptions :
There are no other views in the scrollview apart from these labels.
Its required to work just horizontally.

It could be done with CoreAnimation. You have to keep the index of the main label (that one in the center), and after scrolling is done or when scrolling starts (use some proper for you method in UIScrollViewDelegate) and simply shrink side labels by animation.

Just make the size of the font bigger (with an animation block) when it is the middle one, and smaller when it is not.
You can add a category to UILabel with -(BOOL)isMiddle and set it to true/false.

Related

Progressively scrolling child scrollView

I have 2 scrollviews, the smaller scrollview needs to scroll a little bit slower (and stop on the next "page) than the larger scrollview. So basically, scrolling the larger scrollview scrolls the smaller scrollview, but at a slower pace than the larger scrollview. (confusing I know).
So scrollView1 (the larger) and scrollView2, the smaller: As you swipe scrollView1, scrollView2 is also scrolling but slower. Both having Paging enabled and their contentSizes have already been set based on scrollView2's content.
I am just having trouble calculating the offset between the 2 so they scroll perfectly.
- (void)scrollViewDidScroll:(UIScrollView *)scrollView
{
if ( scrollView == scrollView1 )
{
CGFloat xOffset = (scrollView2.contentSize.width * scrollView1.contentSize.width); // the issue
[scrollView2 scrollRectToVisible:CGRectMake(xOffset, 0, scrollView2.frame.size.width, scrollView2.frame.size.height) animated:YES];
}
}
Try replacing those two lines with:
float xOffset = scrollView1.contentOffset.x * (scrollView2.frame.size.width / scrollView1.frame.size.width);
[scrollView2 setContentOffSet:CGPointMake(xOffset,0) animated:YES];
This will take the offset of scrollView1, divide it by the difference in frame sizes between the two views, and set scrollView2's contentOffset to that value (which is better than scrolling rect to visible).
this worked for me try it..
CGPoint offset = CGPointMake(scroll1.contentOffset.x, scroll1.contentOffset.y);
offset.x /= 3;
offset.y /= 3;
// Scroll the background scroll view by some smaller offset
scroll2.contentOffset = offset;

UIImageView stops resizing when fast scrolling a UIScrollView

So i got an imageView inside a ScrollView that should resize, which works the way i want (see a small video here: https://dl.dropbox.com/u/80699/scroll.m4v)
what i did is setting up a UIScrollViewDelegate and using the scrollViewDidScroll method to resize my image based on the scrolling offset
- (void)scrollViewDidScroll:(UIScrollView *)aScrollView
{
CGFloat scrollViewOffset = aScrollView.contentOffset.y;
if(scrollViewOffset < 0.0f) {
// postition top
CGRect imageViewRect = self.imageView.frame;
imageViewRect.origin.y = scrollViewOffset;
if(scrollViewOffset < 0.0f && scrollViewOffset >= -50.0f) {
CGFloat newBackdropHeight = kImageHeight - scrollViewOffset;
imageViewRect.size.height = newBackdropHeight;
}
self.imageView.frame = imageViewRect;
}
}
whats basically happening here is, that if the user is scrolling upwards when he is on the top (bounces enabled) the imageView expands with the scroll until a certain amount of offset(here 60px).
the problem with this is, that if i scroll very fast, the image stops resizing, but the rest of the scrollview scrolls fast down like it would normally do. then, when the scrollview snaps back, the image expands immediately and then scales down like it should (see video here: https://dl.dropbox.com/u/80699/scroll2.m4v).
with this behavior, the user-expierience is not very nice and the user sees a jumping image.
does anybody know how i could fix this?
here is a small sample project if you want to see the behavior yourself: https://dl.dropbox.com/u/80699/scroll.zip
thanks for your help!
if anything is unclear, PLEASE leave a comment
I had a quick look at your test project, and I believe the issue is that when you scroll quickly, by the time the callback is called the Y offset is greater than -50, so the image view is not resized.
I solved this by removing the inner if condition and giving the backdrop a maximum height:
if(scrollViewOffset < 0.0f) {
// postition top
CGRect imageViewRect = self.imageView.frame;
imageViewRect.origin.y = scrollViewOffset;
CGFloat newBackdropHeight = kImageHeight - MAX(scrollViewOffset,-50.0);
imageViewRect.size.height = newBackdropHeight;
self.imageView.frame = imageViewRect;
}
Hope that helps

iOS Oblique TextView scrolling in Cocos2D or native

How to make UITextView scrolling when text is not vertical?
Like
+--------------+
/ Text /
/ Here /
/ Is /
/ Not /
/ Vertical /
+--------------+
Where starts of lines are in the same angle as border (background) image.
Or we can use another element than UITextView if it can solve the problem.
Scrolling only in vertical direction,
Background image is fixed,
No, visible is only part which fits to shape, other is hidden
Screen is covered by private license, I can't publish it.
You can skew the textfield by using this code:
float angle = -20.0/180*M_PI;
CATransform3D skew = CATransform3DIdentity;
skew.m21 = tanf(angle);
textField.layer.transform = skew;
EDIT: perhaps I've misunderstood your question- you want straight text, but oblique scrolling? If that's the case, you can put your UITextField (or UITextView) into a UIScrollView, but give the scrollView the opposite transform to your textField, like so
float angle = -20.0/180*M_PI;
CATransform3D skew = CATransform3DIdentity;
skew.m21 = tanf(-angle);
scrollView.layer.transform = skew;
skew.m21 = tanf(angle);
textField.layer.transform = skew;
Do you mean that you want the text view to scroll along a diagonal? It's not the most elegant solution but something like this perhaps:
Implement the scrollViewDidScroll: delegate method
Get the existing contentOffset at each delegate callback
Modify the x-value of the offset to an amount that corresponds to the amount of "diagonal-ness" you want to go in
[scrollView setContentOffset:newOffset animated:NO];
Also set the scroll view's directionalLockEnabled to NO.

How can I redraw zoomed text on a transformed UIView?

I'm currently implementing an expanding timeline. When I pinch zoom into the timeline, I need my drawn text to stay at the same relative locations on the UIView they're drawn on inside the UIScrollView that handles the zooming. (Essentially like pins on GoogleMaps) However, I don't want to zoom vertically, so I apply a transform by overriding:
- (void)setTransform:(CGAffineTransform)newValue;
{
newValue.d = 1.0;
[super setTransform:newValue];
}
This works great in keeping the timeline fixed vertically and allowing it to expand horizontally. However, I am drawing my text labels as such in a method called during setNeedsDisplay:
for (int i = 1; i < 11; i++)
{
CGRect newFrame = CGRectMake(i * (512.0/11.0) - (512.0/11.0/2.0), self.frame.size.height - 16.0, 512.0/11.0, 32.0);
NSString *label = [NSString stringWithFormat:#"%d", i+1];
[label drawInRect:newFrame withFont:[UIFont systemFontOfSize:14.0]];
}
This draws my text at the correct position in the scrollview, and nearly works perfectly. However, because of my transform to keep the zooming view static vertically, the text expands horizontally and not vertically, and so stretches out horribly. I can't seem to get the text to redraw at the correct aspect ratio. Using UILabels works, however I am going to be rendering and manipulating upwards of 1,000 such labels, so I'd preferably like to draw static images in drawRect or something similar.
I've tried changing the CGRect I'm drawing the text in (was worth a shot), and applying CGAffineTransformIdentity isn't possible because I'm already transforming the view to keep it from zooming vertically. I've also tried drawing the text in various Views to no avail, and again, I'd rather not populate an obscene amount of objects if I can avoid it.
Thanks for any help!
Instead of applying a transform inside the 'setTransform:' method, I intercepts the scale at which it is being transformed, and resize the frame of the view being transformed. The code (roughly) follows:
- (void)setTransform:(CGAffineTransform)newValue;
{
// The 'a' value of the transform is the transform's new scale of the view, which is reset after the zooming action completes
// newZoomScale should therefore be kept while zooming, and then zoomScale should be updated upon completion
_newZoomScale = _zoomScale * newValue.a;
if (_newZoomScale < 1.0)
_newZoomScale = 1.0;
// Resize self
self.frame = CGRectMake(self.frame.origin.x, self.frame.origin.y, _originalFrame.size.width * _newZoomScale, self.frame.size.height);
}
As mentioned in the comments, the transform value of the CGAffineTransform is reset each time a new zooming action occurs (however, it is kept for the duration of the zooming action). So, I keep two instance variables in my UIView subclass (not sure if it's incredibly elegant, but it's not insanely terrible): the original frame the the view was instantiated with, and the "current" zoom scale of the view (prior to the current zooming action).
The _originalFrame is what is referenced in order to determine the proper sizing of the now zoomed frame, and the _zoomScale(the scale of the view prior to the current zooming action) is set to the value of _newZoomScale when the didFinishZooming callback is called in the UIScrollView containing this UIView.
All of this allows for the coordinate system of the UIView to not be transformed during zooming, so text, etc. may be drawn on the view without any distortion. Looking back at this solution, I'd wager a guess that you could also account for the transform and draw based on a stretched coordinate system. Not sure which is more effective. I had a slight concern by not calling super in setTransform:, but I haven't noticed any ill effects after about 6 months of use and development.

How do I stop a UIScrollView from bouncing horizontally?

I have a UIScrollView that shows vertical data, but where the horizontal component is no wider than the screen of the iPhone. The problem is that the user is still able to drag horizontally, and basically expose blank sections of the UI. I have tried setting:
scrollView.alwaysBounceHorizontal = NO;
scrollView.directionalLockEnabled = YES;
Which helps a little, but still doesn't stop the user from being able to drag horizontally. Surely there is a way to fix this easily?
scrollView.bounces = NO;
Worked for me.
That's strange, because whenever I create a scroll view with frame and content size within the bounds of the screen on either dimension, the scroll view does not scroll (or bounce) in that direction.
// Should scroll vertically but not horizontally
UIScrollView *scrollView = [[UIScrollView alloc] initWithFrame:CGRectMake(0, 0, 320, 480)];
scrollView.contentSize = CGSizeMake(320, 1000);
Are you sure the frame fits completely within the screen and contentSize's width is not greater than the scroll view's width?
The checkbox for bounce vertically in storyboard-scrollview can simply help...
That works for me in Swift:
scrollView.alwaysBounceHorizontal = false
scrollView.bounces = false
Try setting scrollView.bounces to NO and scrollView.alwaysBounceVertical to YES.
Whether or not a view scrolls (and bounces) horizontally depends on three things:
The content size
The left and right content insets
The width of the scroll view -
If the scroll view can fit the content size plus the insets then it doesn't scroll or bounce.
Avoid horizontal bouncing like so:
scrollView.contentSize = CGSizeMake(scrollView.frame.size.width - scrollView.contentInset.left - scrollView.contentInset.right, height);
I am adding this answer because the previous ones did not take contentInset into account.
Make sure the UIScrollView's contentSize is not wider than the UIScrollView itself. In my own apps this was enough to avoid horizontal scrolling, except in cases where I got really crazy swiping in random directions (e.g., starting a scroll while the view was still decelerating).
If anyone developing for OS X is looking here, as of OS X 10.7, the solution is to set the horizontalScrollElasticity property to false/NO on the scroll view, like this:
Swift:
scrollView.horizontalScrollElasticity = false
Objective-C:
scrollView.horizontalScrollElasticity = NO
Something to keep in mind: You know there's nothing extra to see horizontally, but will your users know that? You may want a little horizontal bounce, even if there's no extra content to show horizontally. This let's the user know that their attempts to scroll horizontally are not being ignored, there's just nothing there for them to see. But, yeah, often you really don't want the bounce.
My version for webViews, a common solution:
- (void)webViewDidFinishLoad:(UIWebView *)webView {
[webView.scrollView setContentSize: CGSizeMake(webView.frame.size.width, webView.scrollView.contentSize.height)];
}
You can disable horizontal bounces like this:
- (void)scrollViewDidScroll:(UIScrollView *)scrollView {
if (scrollView.contentOffset.x < 0) {
scrollView.contentOffset = CGPointMake(0, scrollView.contentOffset.y);
} else if (scrollView.contentOffset.x > scrollView.contentSize.width) {
scrollView.contentOffset = CGPointMake(scrollView.contentSize.width, scrollView.contentOffset.y);
}
}
It resets the contentOffset.x manually and won't affect the vertical bounces. It works...
In my case, i just need to set this line:
collectionView.bounces = false