Keep subviews not transformed during UIScrollView zooming - objective-c

I have UIScrollView with content view that has a lot of different subviews (including some labels) on it. During zooming of content view all these different subviews are zoomed as anticipated. However I would like text of UILabel subviews not changed.
I tried next:
-(void)scrollViewDidZoom:(UIScrollView *)scrollView {
// ...
UILabel* label = (UILabel*)[scrollView viewWithTag:labelTag];
[label setTransform:CGAffineTransformMakeScale(1/scrollView.zoomScale, 1/scrollView.zoomScale)];
}
Though the resulted text looks ugly (especially when scale factor quite big), even if I call [label setContentScaleFactor:scaleFactor] during scrollViewDidEndZooming:.
What are possibilities to solve that?

Put the uilabel outside the scroll view.
That would solve your problem. Everything would zoom apart from the label.

Related

UIView animations - When does it animate certain properties like scale and position?

I'm currently working with a UITableViewController which contains some UITableViewCells subclasses.
When layoutSubviews is called on these UITableViewCells, I change some of the cells' subviews' scales and positions depending on the width and height of the contentView. (The UITableViewCells have some subviews, and I change their scales and positions)
A good example is toggling edit mode, since it shortens the contentView by a bit.
When I do this, the scales and positions of my UITableViewCell's subview do animate
func toggleEdit() {
UIView.beginAnimations(nil, context: nil)
UIView.setAnimationDuration(0.35)
self.tableView.beginUpdates()
self.tableView.editing = !self.tableView.editing
self.tableView.endUpdates()
UIView.commitAnimations()
}
When I do this, ONLY the positions animate, the scales change immediately which looks really ugly:
func toggleEdit() {
UIView.beginAnimations(nil, context: nil)
UIView.setAnimationDuration(0.35)
self.tableView.editing = !self.tableView.editing
UIView.commitAnimations()
}
I kind of found this out by accident, so I'm wondering now what kind of magic begin/end tableViewUpdate does, and how I can control myself in any scenario which properties should animate and which shouldn't.
The docs state
When you call endUpdates, UITableView animates the operations simultaneously
You could try changing things that you don't want animated in a performWithoutAnimation(_:) block
UIView.performWithoutAnimation {
// things you don't want to animate
}

iCarousel and UITextView -- blank text view

I'm using iCarousel to display editable question cards. The cards contain a UITextView for entering the question (or already contain text as you swipe through filled cards). However, when the carousel is presented and scrolled, sometimes text views appear empty.
This is due to a UITextView optimization of not drawing text offscreen. But text views in a UITableView will not suffer from this.
As many know, using setNeedsDisplay will NOT work due to the optimization, so it doesn't redraw the text.
I currently change the text view's frame by adding and then removing 1px. This forces a redraw. However, I can only do this when the item changes. iCarousel does not have a willDisplayCell delegate method. (Nick, can you add one easily? The code baffles me)
Because iCarousel is preloading many views for smoothness (which is necessary, setting iCarouselOptionVisibleItems doesn't fix anything) there doesn't seem to be anything else I can do but know when the view is about to come on screen. Suggestions?
- (UIView *)carousel:(iCarousel *)carousel viewForItemAtIndex:(NSUInteger)index reusingView:(UIView *)view
{
MIQuestionView *questionView = (MIQuestionView *)view;
if (questionView == nil)
{
MIQuestionType type = [self.testSection.questionType integerValue];
questionView = [[MIQuestionView alloc] initWithFrame:CGRectNull questionType:type];
questionView.delegate = self;
}
questionView.question = [self.testSection.questions objectAtIndex:index];
return questionView;
}
The text view is embedded in the MIQuestionView. The text is set in the question setter. There's no way for me to know when it's coming onto the screen. To be clear, I don't want to resize. The text is not drawn offscreen and appear blank when coming on-screen.
Sorry, I didn't look for ambiguous code above:
- (id)initWithFrame:(CGRect)frame questionType:(MIQuestionType)type
{
if (CGRectEqualToRect(frame, CGRectNull))
frame = CGRectMake(0, 0, 650, 244);
self = [super initWithFrame:frame];
...
It's an odd bug. I'm not sure if it's an issue with iCarousel or just a quirk of iOS that you need to deal with when dynamically adding and removing UITextViews from the view hierarchy.
I have a solution that's maybe a bit cleaner than the ones you've found though; Just add this to your MICardView:
- (void)didMoveToSuperview
{
if (self.superview)
{
_textView.frame = self.bounds;
}
}
This basically forces the textView to re-layout every time the cardView is recycled, and it avoids you having to do anything special in your view controller to work around the issue.

Releasing invisible buttons with images in UIScrollView

I have main UIScrollView with lots off buttons which i create like this:
UIButton *myButton = [UIButton buttonWithType:UIButtonTypeCustom]
every button have an image:
UIImage *fileImage = [UIImage imageNamed:#"sun.png"];
[myButton setBackgroundImage:fileImage forState:UIControlStateNormal];
Buttons count could be more than 500. So i need to remove from UIscrollView invisible buttons with images to save memory ?
I believe in this method i need to calculate when UIscrollview is stopped scrolling and for example 20 images are invisible, then i need to remove them and reduce scroller contentOffset.
-(void)scrollViewDidEndDecelerating:(UIScrollView *)scrollView {
float bottomEdge = scrollView.contentOffset.y + scrollView.frame.size.height;
}
Maybe some one could give me tips on this. Or even have a good bookmarked tutorial.
I created a similar thing to this using UIViews in a UIScrollView. When the UIScrollView loads, I set the contentView size of the scrollView to be the size of all the views but only loaded the views that can be seen, then when the user scrolls i added the previous/next views and removed the hidden views.
This question helped me: How to implement UIScrollView with 1000+ subviews? especially akosma's answer

How to create a "stretchable" UIView

I have a UIView that contains another UIView. The outer UIView draws a border around the inner UIView via drawRect. (The border is too complicated to be drawn via CALayer properties.)
At present, when I animate the resizing of the outer UIView, its drawRect method is called once at the beginning of the animation and the result is stretched or shrunk. This does not look good.
I am looking for a way to either redraw the content at every step of the animation, or find a way to achieve the same visual effect. (The result should be similar to the resizing of a stretchable UIImage.)
You should change view's content type to:
your_view.contentMode = UIViewContentModeRedraw;
And it will redraw each time its frame changes.
I ended up adding subviews with autoresizing masks that kept them positioned correctly during the animation.
You need to send a [UIView setNeedsToDisplay] to the view for every time the frame size is changed, you could try overriding the setFrame: method like
- (void)setFrame:(CGRect)r
{
[super setFrame:r];
[self setNeedsToDisplay];
}

Resizable UILabel which scrolls across the screen

Right, I'm trying to get a label with text in it (done already obviously), which scrolls across the screen.
The text that is input into the label is done by a UITextField and a UIButton. This updates fine.
But I'm trying to get the UILabel to resize accordingly to the amount of text input, so that the WHOLE lot of text scrolls across the screen.
This is the code I have at the moment for the scrolling label:
[lblMessage setText: txtEnter.text];
CABasicAnimation *scrollText;
scrollText=[CABasicAnimation animationWithKeyPath:#"position.x"];
scrollText.duration = 3.0;
scrollText.repeatCount = 10000;
scrollText.autoreverses = NO;
scrollText.fromValue = [NSNumber numberWithFloat:500];
scrollText.toValue = [NSNumber numberWithFloat:-120.0];
[[lblMessage layer] addAnimation:scrollText forKey:#"scrollTextKey"];
The problem is, sometimes is starts scrolling in the middle of the screen, and sometimes vanishes before it has fully gone acrosss.
It also cuts of text due to the label being one size.. I don't know how to change this.
Thanks in advance.
Dom
I believe something similar to the solution for this question would work for this case.
You could embed the UILabel in a UIScrollView, with the UIScrollView set to the max size of the label that you want to display on the screen at one time. The UIScrollView would need to have its scroll indicators turned off using its showsHorizontalScrollIndicator and showsVerticalScrollIndicator properties. On a change of text, you could do the following:
[lblMessage setText: txtEnter.text];
[lblMessage sizeToFit];
scrollView.contentSize = lblMessage.frame.size;
followed by the panning animation code as described in the above-linked question, with the frame to be panned to being the far right of the UILabel. This would cause the text to scroll at a constant rate across the label. If you want the label to scroll back to the beginning, you could use the UIView setAnimationRepeatAutoreverses: and setAnimationRepeatCount: methods in the beginning of your animation block.
The label resize worked great thanks!
Now, i've put the label into the scrollview and i've got that showing up.. but I'm now not sure of the exact animations to add to that. I tried some of the ones on the link you gave me, but they're not working.
EDIT: Nevermind, I've got it all working now.
CGPointMake(x, x) is what i needed for the contentOffset.