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.
Related
I have a bunch of questions:
How do I position a UIView so that it is on the bottom of the view I am adding it to?
How can I add a subview to a view so that it is positioned in the corner of the superview with a small gap (Like if I want a 'x' cross sign for closing something)
Is their a utility class for easy UIView positioning (and rotation)?
Any references, open source tutorials etc. will be more then welcome!
(a) How do I position a UIView so that it is on the bottom of the view I am adding it to?
OK, let's say you want to position button as a subview at the bottom of view form, you calculate the origin.y of the subview button by subtracting button's height from the height of the form
CGRect buttonFrame = button.frame;
buttonFrame.origin.y = form.bounds.size.height - buttonFrame.size.height;
button.frame = buttonFrame;
[form addSubview:button];
You can change origin horizontal position as well. You want it on the bottom left of form?
buttonFrame.origin.x = 0;
Or on the right edge of form?
buttonFrame.origin.x = form.bounds.size.width - buttonFrame.size.width;
Or in the middle (horizontally) of form?
buttonFrame.origin.x = (form.bounds.size.width - buttonFrame.size.width) / 2;
or another way using CGRectGetMidX (found in CGGeometry utility methods):
buttonFrame.origin.x = CGRectGetMidX(form.bounds) - buttonFrame.size.width/2;
Autoresizing handles adjusting the frame when the parent view's size changes. But you still have to position it first.
int xOffset = 20;
int yOffset = 20;
CGRect BottomRight_NewFrame = CGRectMake((superview.frame.size.width - subview.frame.size.width-xOffset), (superview.frame.size.height - subview.frame.size.height-yOffset), subview.frame.size.width, subview.frame.size.height);
subview.frame = BottomFrame;
You can use the new Autolayout feature of iOS 6 or the old Struts & Springs in the Interface Builder to achieve this.
This tutorial explains both:
http://msmvps.com/blogs/kevinmcneish/archive/2012/12/10/tutorial-ios-6-auto-layout-versus-springs-and-struts.aspx
Or you can set the autoresizing mask programatically. It is explained pretty well here:
UIView autoresizingMask - Interface Builder to Code - Programmatically create struts and springs - Swift or Objective-C
It's easy enough to just set the frame, e.g. (untested code )
subview.frame = CGRectMake((superview.frame.origin.x - subview.frame.origin.size.width/2)-20, (superview.view.frame.origin.y - subview.frame.origin.size.height/2)-20, subview.view.frame.size.width, subview.view.frame.size.height);
if you'll be doing a lot of this then create a utility class or method.
Autolayout will help you position the views and maintain those positions if the size of the superview changes. If the superview isn't going to change, you don't really need to mess with constraints -- you can just set the position of the subview appropra
If you're adding view viewB to view viewA:
a) To position viewB so that it's bottom edge corresponds to the bottom edge of viewA:
viewB.frame.origin.y = viewA.bounds.size.height - viewB.bounds.size.height;
b) You don't say which corner, but it's just a matter of doing the math. For example, the upper right corner of viewA is at {viewA.bounds.size.x, 0} in viewA's coordinate system. If you want to put viewB there, set it's origin to:
{viewA.bounds.size.x-viewB.bounds.size.x, 0}
If you want to add a margin, you can add that to the computation:
int margin = 10;
{viewA.bounds.size.x-viewB.bounds.size.x-margin, margin}
d) Use NSLayoutConstraint to access the autolayout system's constraints programmatically. There's a nice visual format language, so that for your question (a) you could set the constraint for viewA to:
V:|-[viewB]-0-|
The V means that you're working in the vertical direction, |'s represent the edges (top and bottom, thanks to the V) of the superview (that's viewA), and the 0 means that the distance between viewB and the bottom of its superview should be 0.
You can setup constraints in iOS6 but if you want to work on older os's you need to position them manually. Math.
I want to create a slide-down animation, like in the image in the link. When I press on "Previous", I want it to slide down to the center of the screen. I am not really sure how to implement that. Any suggestion would be really handy.
http://imageshack.us/photo/my-images/718/slideto.png/
This looks like a UITableView. You can place a custom cell with the button Previous, which will load the new data above and then call the scrollToRowAtIndexPath:atScrollPosition:animated: function to perform the animation.
The whole thing is pretty likely a UIScrollView of some sort (UITableViews are scroll views as well). When the buttons is pressed, either use setContentOffset:animated: or scrollRectToVisible:animated: to do the scrolling. The "magic" is just in calculating the correct offset or rect. I'd suggest going with setContentOffset:animated:. It should work roughly like this:
CGPoint p;
p.x = 0;
// Get middle of the view to be centered.
p.y = CGRectGetMidY(myViewThatShouldBeCentered.frame);
// Need to offset it by half the scroll view frame, otherwise
// you'd just see the lower half of the view peeking out at the
// top of the scroll view.
p.y -= CGRectGetHeight(myScrollView.frame) / 2;
[myScrollView setContentOffset:p animated:YES];
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.
My UIScrollView on the iPhone is 480x230 and the content is 972x230 when first displayed. I need to provide functionality where when the user double taps the UIScrollView the contents zoom to fit with the 480x230 UIScrollView proportionally. When the double tap it again it should zoom back out to it's original size.
What is the best way to do this? I have been fumbling for several hours with this and thought that this would work...
[bodyClockScrollView zoomToRect:bodyClockScrollView.frame animated:YES];
But nothing seems to happen.
Thanks, any help pointing me in the right direction would be appreciated.
You need to make sure the class you've set up as the scrollview's delegate implements this method:
-(UIView *) viewForZoomingInScrollView:(UIScrollView *)scrollView {
return someView;
}
Using CGAffineTransform I figured out a way to do what I want...
//bodyCleckScrollView contains a UIView name bodyClock
//get the scale factor required to fit bodyClock inside the iPhone window and resize it...
CGFloat scale = 480/bodyClockScrollView.contentSize.width;
bodyClock.transform = CGAffineTransformScale(bodyClock.transform, scale, scale);
//move bodyClock to the bottom of bodyScrollView.
bodyClock.transform = CGAffineTransformTranslate(bodyClock.transform, 0.0,bodyClockScrollView.frame.size.height-bodyClock.frame.size.height);
//scoll bodyScrollView so that bodyClock is centered in the window
CGPoint offsetPoint = CGPointMake(bodyClock.frame.origin.x, 0.0);
[bodyClockScrollView setContentOffset:offsetPoint animated:YES];
This works great and when I want to zoom it back out to the default size and position you simply call...
bodyClock.transform = CGAffineTransformIdentity;
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.