custom uiscrollview doesn't scroll (using coretext) - iphone

I am using CoreText to draw text in multiple columns (depending on the orientation of the iPad).
To test, I've created an NSMutableString composed of the numbers 100 - 999. This text spans 5 columns, 1 or 2 of which are onscreen (depending on the orientation).
To my main ViewController I've added a custom UIScrollView to hold this text, and I want it to be scrollable.
I've noticed that the scrollview doesn't scroll until I set:
[myScrollView setContentMode:UIViewContentModeRedraw];
I do want the scrollView to call drawRect when the iPad is rotated (to adjust the number of columns)!
My issue with this though is that it seems to call drawRect over and over and over ... while scrolling (and thus allocates more and more memory, also causing some lag).
I add the UIScrollView to my main viewController like so:
myScrollView = [[CoreTextTestUIView alloc] init];
myScrollView.parentView = self;
if(FACING == #"PU" || FACING == #"PD")
{
myScrollView.frame = CGRectMake(0,50,768,974);
}
else
{
myScrollView.frame = CGRectMake(0,50,1024,718);
}
[myScrollView setContentMode:UIViewContentModeRedraw];
[container addSubview:myScrollView];
Again, I want drawRect to be called when the iPad is rotated, so the number of columns can change ... BUT I do not want it to call drawRect when I simply try to scroll the UIScrollView.
Can someone help me please?
...
below is the .m for my UIScrollView:
#import "CoreTextTestUIView.h"
#import <CoreText/CoreText.h>
#implementation CoreTextTestUIView
#synthesize parentView;
NSMutableString *testText;
-(id)initWithFrame:(CGRect)frame
{
self = [super initWithFrame:frame];
if(self)
{
// Initialization code
//set BG color
self.backgroundColor = [[UIColor alloc] initWithRed:134 green:166 blue:228 alpha:1.0];
//UIScrollView Stuff
//self.delegate = self;
self.scrollEnabled = YES;
self.pagingEnabled = YES;
self.userInteractionEnabled = YES;
[self becomeFirstResponder];
self.showsVerticalScrollIndicator = NO;
self.showsHorizontalScrollIndicator = NO;
self.bounces = NO;
self.alwaysBounceHorizontal = YES;
self.alwaysBounceVertical = NO;
//generate long text
testText = [[NSMutableString alloc] initWithString:#""];
for(int i = 100; i < 1000; i++)
{
[testText appendString:[NSString stringWithFormat:#"%i ",i]];
}
self.alpha = 0.0;
[self fadeIn];
}
return self;
}
-(void)fadeIn
{
[UIView beginAnimations:nil context:nil];
[UIView setAnimationDuration:1.0];
[UIView setAnimationDelegate:self];
//[UIView setAnimationDidStopSelector:#selector(animationFinished:finished:context:)];
self.alpha = 1.0;
[UIView commitAnimations];
}
// Only override drawRect: if you perform custom drawing.
// An empty implementation adversely affects performance during animation.
-(void)drawRect:(CGRect)rect
{
NSMutableAttributedString *string = [[NSMutableAttributedString alloc] initWithString:[NSString stringWithFormat:#"%#",testText]];
//set font
CTFontRef helvetica = CTFontCreateWithName(CFSTR("Helvetica"), 40.0, NULL);
[string addAttribute:(id)kCTFontAttributeName
value:(id)helvetica
range:NSMakeRange(0, [string length])];
//layout master
CTFramesetterRef framesetter = CTFramesetterCreateWithAttributedString((CFAttributedStringRef)string);
//flip the coordinate system
CGContextRef context = UIGraphicsGetCurrentContext();
CGContextSetTextMatrix(context, CGAffineTransformIdentity);
CGContextTranslateCTM(context, 0, self.bounds.size.height);
CGContextScaleCTM(context, 1.0, -1.0);
int textPos = 0;
int columnIndex = 0;
//how many columns? (orientation dependent)
float howManyColumns;
if(parentView.FACING == #"PU" || parentView.FACING == #"PD")
{
howManyColumns = 1.0;
}
else
{
howManyColumns = 2.0;
}
//create columns in loop
while(textPos < [string length])
{
NSLog(#"column started");
//column form
CGMutablePathRef columnPath = CGPathCreateMutable();
CGPathAddRect(columnPath, NULL,
CGRectMake((self.bounds.size.width/howManyColumns*columnIndex), 0,
(self.bounds.size.width/howManyColumns),
self.bounds.size.height));
//column frame
CTFrameRef columnFrame = CTFramesetterCreateFrame(framesetter,
CFRangeMake(textPos, 0),
columnPath,
NULL);
//use the column path
CTFrameRef frame = CTFramesetterCreateFrame(framesetter, CFRangeMake(textPos, 0), columnPath, NULL);
CFRange frameRange = CTFrameGetVisibleStringRange(frame);
//draw
CTFrameDraw(columnFrame, context);
//cleanup
CFRelease(columnFrame);
CGPathRelease(columnPath);
textPos += frameRange.length;
columnIndex++;
}
//set scrollView content size
int totalPages = (columnIndex+1)/howManyColumns;
self.contentSize = CGSizeMake(totalPages*self.bounds.size.width, self.frame.size.height);
//release
CFRelease(framesetter);
[string release];
}
-(void)dealloc
{
[super dealloc];
[parentView release];
[testText release];
}
#end

Looking at this, I can't see where you are setting the contentSize of your scrollView. If you do not set the contentSize of your scrollView, scrolling will not be enabled, and you will only see what fits within the current area of the scrollView. Also, if your text is static in a configuration, consider optimizing out some of the redrawing that is occurring and add it to a subview of the scrollView.

That is how drawRect works. It is called every single time that the view moves or changes or has something overlapping it. If you are managing memory correctly this shouldn't be a problem.

Related

textview cursor position changed after horizontal line

I want to change the cursor position in TextView...
// NoteView objective _c class its super class is TextView...
#import "NoteView.h"
#implementation NoteView
- (id)initWithFrame:(CGRect)frame
{
self = [super initWithFrame:frame];
if (self) {
// Initialization code
self.backgroundColor =[UIColor whiteColor];
self.contentMode = UIViewContentModeRedraw;
self.font = [UIFont fontWithName:#"Helvetica Neue" size:14];
}
return self;
}
// Only override drawRect: if you perform custom drawing.
// An empty implementation adversely affects performance during animation.
- (void)drawRect:(CGRect)rect
{
//Get the current drawing context
CGContextRef context = UIGraphicsGetCurrentContext();
//Set the line color and width
// CGContextSetStrokeColorWithColor(context, [UIColor colorWithRed:0.0f green:0.0f blue:0.0f alpha:0.2f].CGColor);
CGContextSetStrokeColorWithColor(context,[UIColor colorWithRed:0.29804f green:0.12157f blue:0.9f alpha:0.1].CGColor);
//Start a new Path
CGContextBeginPath(context);
//Find the number of lines in our textView + add a bit more height to draw lines in the empty part of the view
NSUInteger numberOfLines = (self.contentSize.height + self.bounds.size.height) / self.font.leading;
//Set the line offset from the baseline. (I'm sure there's a concrete way to calculate this.)
CGFloat baselineOffset = 6.0f;
//iterate over numberOfLines and draw each line
for (int x = 0; x < numberOfLines; x++) {
//0.5f offset lines up line with pixel boundary
CGContextMoveToPoint(context, self.bounds.origin.x, self.font.leading*x + 0.5f + baselineOffset);
CGContextAddLineToPoint(context, self.bounds.size.width, self.font.leading*x + 0.5f + baselineOffset);
}
//Close our Path and Stroke (draw) it
CGContextClosePath(context);
CGContextStrokePath(context);
}
//its a view controller class and here i imported NotesView here
#import "NotesViewController.h"
#interface NotesViewController ()
#end
#implementation NotesViewController
// i load the textView frame whatever i created class above
- (void)loadView {
[super loadView];
CGSize result = [[UIScreen mainScreen] bounds].size;
CGFloat scale = [UIScreen mainScreen].scale;
result = CGSizeMake(result.width*scale, result.height * scale);
if (result.height==1136)
{
_TextView = [[NoteView alloc] initWithFrame:CGRectMake(29,50,266,430)];
backgroundView.frame=CGRectMake(10,32,300,450);
}
else
{
_TextView = [[NoteView alloc] initWithFrame:CGRectMake(29,50,266,340)];
backgroundView.frame=CGRectMake(10,32,300,360);
}
[self.view addSubview:_TextView];
_TextView.delegate = self;
UIView *lineView = [[UIView alloc]initWithFrame:CGRectMake(30,40,1,backgroundView.frame.size.height-5)];
lineView.backgroundColor = [UIColor brownColor];
lineView.alpha=0.3;
[self.view addSubview:lineView];
UIView *lineView1 = [[UIView alloc]initWithFrame:CGRectMake(32,40,1,backgroundView.frame.size.height-5)];
lineView1.backgroundColor = [UIColor brownColor];
lineView1.alpha=0.3;
[self.view addSubview:lineView1];
}
}
}
// in view did load i set the delegate and code for cursor position
- (void)viewDidLoad
{
[super viewDidLoad];
// setting delegate here
_TextView.delegate=self;
_TextView.editable = YES;
[_TextView setSelectedRange:NSMakeRange(10, 0)];
}
I write all the delegate methods for Textview and ScrollView of Textview I the cursor positon is starts the vertical line after.... I'm not expressed well please understand based on images... I want cursor position... I want to set my Textview with real note application in iPhone.. I add Textview to ViewController all works well but cursor stats starting position... I want to cursor position always horizontal line........ Try to give solution based on the images..
Do it like this image.
Here you have to set the position of your textview in your VC so it will come after the horizontal line.

Pinch Zoom in and Zoom Out in Objective c

How to integrate the pinch zoom and zoom out in our apps, i am using imageview on scrollView
and my code is:
- (IBAction)handlePinchGesture:(UIGestureRecognizer *) recognizer {
if(zoomEnable == TRUE)
{
CGFloat factor = [(UIPinchGestureRecognizer *) recognizer scale];
CGFloat lastScaleFactor = 1;
//if the current factor is greater 1 --> zoom in
if (factor > 1) {
scrollView.transform = CGAffineTransformMakeScale(lastScaleFactor + (factor-1),lastScaleFactor + (factor-1));
scrollView.scrollEnabled = YES;
} else {
[UIView beginAnimations:#"animation" context:nil];
[UIView setAnimationDuration:0.5];
[UIView setAnimationTransition:UIViewAnimationTransitionNone forView:scrollView cache:NO];
scrollView.transform = CGAffineTransformMakeScale(1,1);
[UIView commitAnimations];
}
isScrollable = TRUE;
}
}
Its start zooming every time from start i want if i zoom some then again it start when i stop zoom. Any help is highly Appreciated
Thanks;
You don't need to use UIGestureRecognizers, if you're using UIScrollView already. UIScrollView supports pinch to zoom.
For zooming and panning to work, the delegate must implement both viewForZoomingInScrollView: and scrollViewDidEndZooming:withView:atScale:; in addition, the maximum (maximumZoomScale) and minimum (minimumZoomScale) zoom scale must be different.
-(void)zoomingImages{
self.FullSizeScrollView.pagingEnabled =YES;
NSMutableArray *_scrollArray =[[NSMutableArray alloc]init];
// add images to scroll array
[_scrollArray addObject:self.image1];
[_scrollArray addObject:self.image2];
//now call init with frame function given below to set frame for each image in scroll view
for(int i =0 ;i<[_scrollArray count];i++){
ZoomingImageView *_imageScrollView = [[ZoomingImageView alloc]initWithFrame:CGRectMake(i*320, 0, 320, 460)];
_imageScrollView.captureView=self;
[self.checkFullSizeScrollView addSubview:_imageScrollView];
[_imageScrollView release];
self.checkFullSizeScrollView.contentSize = CGSizeMake((i*320)+320, 460);
}
[_scrollArray release];
}
#implementation ZoomingImageView
- (id)initWithFrame:(CGRect)frame{
self = [super initWithFrame:frame];
if (self) {
self.maximumZoomScale = 4;
self.minimumZoomScale = 1;
self.userInteractionEnabled = YES;
self.multipleTouchEnabled = YES;
self.delegate = self;
self.bouncesZoom = NO;
self.currentImageView.clipsToBounds=NO;
self.contentMode =UIViewContentModeScaleAspectFit;
UIImageView *zoomImageView_ =[[UIImageView alloc]initWithFrame:CGRectMake(0, 0, frame.size.width, frame.size.height)];
self.currentImageView = zoomImageView_;
[zoomImageView_ release];
self.currentImageView.contentMode =UIViewContentModeScaleAspectFit;
self.currentImageView.userInteractionEnabled = YES;
self.currentImageView.multipleTouchEnabled = YES;
[self addSubview:self.currentImageView];}
return self;}

How to customize paging in UIScrollView?

I have a question in scroll view.
Right now I wrote a sample about image gallery with scroll view. I have plenty of images added into a scroll view. Each time, it display 3 images, the question is how can measure the scrolling properly. For example: the minimum each scroll is moving 1 image. Right now, I think each time I scroll, the minimum images moving are 3. That make me can't stop at the right image I want to see.
Below is the code.
- (void)layoutScrollImages
{
UIImageView *view = nil;
NSArray *subviews = [scroll subviews];
// reposition all image subviews in a horizontal serial fashion
CGFloat curXLoc = 0;
for (view in subviews)
{
if ([view isKindOfClass:[UIImageView class]] && view.tag > 0)
{
CGRect frame = view.frame;
frame.origin = CGPointMake(curXLoc, 0);
view.frame = frame;
curXLoc += (kScrollObjWidth);
}
}
// set the content size so it can be scrollable
[scroll setContentSize:CGSizeMake((kNumImages * kScrollObjWidth), [scroll bounds].size.height)];
}
#pragma mark - View lifecycle
- (void)viewDidLoad
{
[super viewDidLoad];
// 1. setup the scrollview for multiple images and add it to the view controller
//
// note: the following can be done in Interface Builder, but we show this in code for clarity
[scroll setBackgroundColor:[UIColor blackColor]];
[scroll setCanCancelContentTouches:NO];
scroll.indicatorStyle = UIScrollViewIndicatorStyleWhite;
scroll.clipsToBounds = YES; // default is NO, we want to restrict drawing within our scrollview
scroll.scrollEnabled = YES;
// pagingEnabled property default is NO, if set the scroller will stop or snap at each photo
// if you want free-flowing scroll, don't set this property.
scroll.pagingEnabled = YES;
// load all the images from our bundle and add them to the scroll view
NSUInteger i;
for (i = 1; i <= kNumImages; i++)
{
NSString *imageName = [NSString stringWithFormat:#"image%d.jpg", i];
UIImage *image = [UIImage imageNamed:imageName];
UIImageView *imageView = [[UIImageView alloc] initWithImage:image];
// setup each frame to a default height and width, it will be properly placed when we call "updateScrollList"
CGRect rect = imageView.frame;
rect.size.height = kScrollObjHeight;
rect.size.width = kScrollObjWidth;
imageView.frame = rect;
imageView.tag = i; // tag our images for later use when we place them in serial fashion
[scroll addSubview:imageView];
[imageView release];
}
[self layoutScrollImages];
}
Use this code......
-(void)scrollViewDidScroll:(UIScrollView *)scrollView
{
if(scroll.contentOffset.y> 320)
{
int y = scrollView.contentOffset.y;
y = y/3;
[scrollView setContentOffset:CGPointMake(0, y)];
}
}
Hope, this will help you...Chill
Subclass the content view and overwrite this function:
- (UIView *)hitTest:(CGPoint)point withEvent:(UIEvent *)event {
if ([self pointInside:point withEvent:event]) {
if ([[self subviews] count] > 0) {
//force return of first child, if exists
return [[self subviews] objectAtIndex:0];
} else {
return self;
}
}
return nil; }
See detail at https://github.com/taufikobet/ScrollViewCustomPaging.

How do I get UITextView to scroll properly when the keyboard is visible

I have a UITextView sitting on top of a UIView, and if I tap on it to open it for editing, then the keyboard is blocking the bottom of the view and I can not see it even though I can write in this area. Can I tell the UITextView to have a different scroll area or what is the solution?
A better solution, specially for iOS 7, would be to adjust the content inset property of the textview instead of its frame, this way, the keyboard will blur the text that falls behinds it like in any other iOS 7 app. You'll also have to adjust the scroll indicators to match.
Expanding Lindemann's answer,
- (void)keyboardWasShown:(NSNotification*)notification {
NSDictionary* info = [notification userInfo];
CGSize keyboardSize = [[info objectForKey:UIKeyboardFrameEndUserInfoKey] CGRectValue].size;
self.textView.contentInset = UIEdgeInsetsMake(0, 0, keyboardSize.height, 0);
self.textView.scrollIndicatorInsets = self.textView.contentInset;
}
- (void)keyboardWillBeHidden:(NSNotification*)notification {
self.textView.contentInset = UIEdgeInsetsZero;
self.textView.scrollIndicatorInsets = UIEdgeInsetsZero;
}
An easy solution is to implement the UITextViewDelegate Methods
- (void)textViewDidBeginEditing:(UITextView *)textView
and
- (void)textViewDidEndEditing:(UITextView *)textView
You can make the UITextView Frame smaller when the keyboard appears and make it full size again when the keyboard disappears...like this:
- (void)textViewDidBeginEditing:(UITextView *)textView {
self.textView.frame = CGRectMake(0, 0, self.view.frame.size.width, self.view.frame.size.height/1.8);
}
- (void)textViewDidEndEditing:(UITextView *)textView {
self.textView.frame = CGRectMake(0, 0, self.view.frame.size.width, self.view.frame.size.height);
}
EDIT
The solution above is bad...don't use it!!!
Now I think it's a better idea to resize the UITextView in proportion to the keyboard size and not with a fixed value...because the size of the keyboard can change when an other language become chosen or the device become rotated...of course -.-
At first you must register your UIViewController which displays your UITextView for receiving Keyboard Notifications:
- (void)viewDidLoad {
[super viewDidLoad];
[[NSNotificationCenter defaultCenter] addObserver:self
selector:#selector(keyboardWasShown:)
name:UIKeyboardDidShowNotification object:nil];
[[NSNotificationCenter defaultCenter] addObserver:self
selector:#selector(keyboardWillBeHidden:)
name:UIKeyboardWillHideNotification object:nil];
}
Then you have to implement the two methods -keyboardWasShown: and
-keyboardWillBeHidden:.
The size of the actual keyboard is contained in the NSNotification object.
- (void)keyboardWasShown:(NSNotification*)notification {
NSDictionary* info = [notification userInfo];
CGSize keyboardSize = [[info objectForKey:UIKeyboardFrameEndUserInfoKey] CGRectValue].size;
self.textView.frame = CGRectMake(0, 0, self.view.frame.size.width, self.view.frame.size.height - keyboardSize.height);
}
- (void)keyboardWillBeHidden:(NSNotification*)notification {
self.textView.frame = CGRectMake(0, 0, self.view.frame.size.width, self.view.frame.size.height);
}
If you want a Messages App style input, you can use a nested UITextView (allows for multiple lines of text). It will look like this in the end:
You start by laying out a view to hold all the child views. Here the background colour of the bottomView is set to match UIKeyboardAppearanceDark. It rests at the bottom of the screen.
bottomView = [UIView new];
bottomView.frame = CGRectMake(0, h-45, w, 45);
bottomView.backgroundColor = [UIColor colorWithRed:0.078 green:0.078 blue:0.078 alpha:1];
[self.view addSubview:bottomView];
Then, add in a simple background view styled like a typical UITextField, and add the UITextView as a subview to that. The inputTV (UITextView) takes its height based upon the size of the font. Also, all the padding is removed from inputTV using the textContainer variables.
inputTVBG = [UIImageView new];
inputTVBG.frame = CGRectMake(10, 8, w-90, 29);
inputTVBG.backgroundColor = [[UIColor whiteColor] colorWithAlphaComponent:0.1f];
inputTVBG.layer.cornerRadius = 4.0f;
inputTVBG.userInteractionEnabled = true;
inputTVBG.clipsToBounds = true;
[bottomView addSubview:inputTVBG];
inputTV = [UITextView new];
inputTV.font = [UIFont systemFontOfSize:14.0f];
inputTV.frame = CGRectMake(5, 6, w-100, inputTV.font.lineHeight);
inputTV.backgroundColor = [UIColor clearColor];
inputTV.keyboardAppearance = UIKeyboardAppearanceDark;
inputTV.delegate = self;
inputTV.autocorrectionType = UITextAutocorrectionTypeNo;
inputTV.tintColor = [UIColor whiteColor];
inputTV.textColor = [UIColor whiteColor];
inputTV.textContainer.lineFragmentPadding = 0;
inputTV.textContainerInset = UIEdgeInsetsZero;
[inputTVBG addSubview:inputTV];
In the example above, I've included a label indicating how many letters are left (max / min characters) and a submit button.
lettersLeftLabel = [UILabel new];
lettersLeftLabel.frame = CGRectMake(w-70, 8, 60, 16);
lettersLeftLabel.font = [UIFont systemFontOfSize:12.0f];
lettersLeftLabel.textColor = [[UIColor whiteColor] colorWithAlphaComponent:0.5f];
lettersLeftLabel.alpha = 0.0f;
[bottomView addSubview:lettersLeftLabel];
submitButton = [UIButton new];
submitButton.frame = CGRectMake(w-70, 0, 60, 45);
[submitButton setTitle:#"SUBMIT" forState:UIControlStateNormal];
[submitButton setTitleColor:[_peacock.applePink colorWithAlphaComponent:0.5f] forState:UIControlStateNormal];
[submitButton addTarget:self action:#selector(submit) forControlEvents:UIControlEventTouchUpInside];
[submitButton.titleLabel setFont:[UIFont boldSystemFontOfSize:14.0f]];
[bottomView addSubview:submitButton];
Add this line early on in your code, so you get keyboard change updates:
[[NSNotificationCenter defaultCenter] addObserver:self selector:#selector(keyboardWillShow:) name:UIKeyboardWillShowNotification object:nil];
It calls the method below when a user clicks on the inputTV. Here it sets the variable 'keyboardHeight' used later on.
-(void)keyboardWillShow:(NSNotification *)n {
CGRect rect = [n.userInfo[UIKeyboardFrameEndUserInfoKey] CGRectValue];
CGRect keyboardFrame = [self.view convertRect:rect fromView:nil];
keyboardHeight = keyboardFrame.size.height;
[self textViewDidChange:inputTV];
}
This is the main bit of code that takes care of all the movement and resizing of the inputTV.
-(void)textViewDidChange:(UITextView *)textView {
//1. letters and submit button vars
int numberOfCharacters = (int)textView.text.length;
int minCharacters = 50;
int maxCharacters = 400;
int remainingCharacters = maxCharacters-numberOfCharacters;
//2. if entered letters exceeds maximum, reset text and return
if (remainingCharacters <= 0){
textView.text = [textView.text substringToIndex:maxCharacters];
numberOfCharacters = maxCharacters;
}
//3. set height vars
inputTV.scrollEnabled = true;
float textHeight = textView.contentSize.height;
float lineHeight = roundf(textView.font.lineHeight);
float additionalHeight = textHeight - lineHeight;
float moveUpHeight = keyboardHeight + additionalHeight;
//4. default letter colour is weak white
UIColor * letterColour = [[UIColor whiteColor] colorWithAlphaComponent:0.5f];
if (numberOfCharacters < minCharacters){ //minimum threshold not met
lettersLeftLabel.text = [NSString stringWithFormat:#"%i", minCharacters-numberOfCharacters];
letterColour = [_peacock.applePink colorWithAlphaComponent:0.5f];
} else { //within range
lettersLeftLabel.text = [NSString stringWithFormat:#"%i/%i", numberOfCharacters, maxCharacters];
if (remainingCharacters<5){ //increase alpha towards the end of range
letterColour = [[UIColor whiteColor] colorWithAlphaComponent:1.0f - ((float)remainingCharacters/10)];
}
}
//5. hide/show letter label based on textView height
float letterAlpha = 0.0f; //default hide
if (additionalHeight > 0){ letterAlpha = 1.0f; } //if multiline, show
[UIView animateWithDuration:0.3f
delay:0.0f
options:UIViewAnimationOptionCurveEaseOut
animations:^{
lettersLeftLabel.alpha = letterAlpha;
lettersLeftLabel.textColor = letterColour;
}
completion:^(BOOL finished){
}];
//6. update submit colour based on minimum threshold
UIColor * submitColour = [_peacock.applePink colorWithAlphaComponent:0.5f];
bool enableSubmit = false;
if (numberOfCharacters >= minCharacters){
submitColour = _peacock.applePink;
enableSubmit = true;
}
[submitButton setEnabled:enableSubmit];
[UIView animateWithDuration:0.3f
delay:0.0f
options:UIViewAnimationOptionCurveEaseOut
animations:^{
[submitButton setTitleColor:submitColour forState:UIControlStateNormal];
}
completion:^(BOOL finished){
}];
//7. special case if you want to limit the frame size of the input TV to a specific number of lines
bool shouldEnableScroll = false;
int maxNumberOfLines = 5; //anything above this triggers the input TV to stay stationary and update its scroll
int actualNumberOfLines = textHeight / textView.font.lineHeight;
if (actualNumberOfLines >= maxNumberOfLines){ //recalculate vars for frames
textHeight = maxNumberOfLines * lineHeight;
additionalHeight = textHeight - lineHeight;
moveUpHeight = keyboardHeight + additionalHeight;
shouldEnableScroll = true;
}
//8. adjust frames of views
inputTV.frame = CGRectMake(5, 6, w-100, textHeight); //update immediately (parent view clips to bounds)
[UIView animateWithDuration:0.3f
delay:0.0f
options:UIViewAnimationOptionCurveEaseOut
animations:^{
bottomView.frame = CGRectMake(0, h-45-moveUpHeight, w, 45+additionalHeight);
inputTVBG.frame = CGRectMake(10, 8, w-90, lineHeight+additionalHeight+13);
submitButton.frame = CGRectMake(w-70, additionalHeight, 60, 45);
}
completion:^(BOOL finished){
inputTV.scrollEnabled = shouldEnableScroll; //default disable scroll here to avoid bouncing
}];
}
In the above method, this is what's happening:
If you want to set a minimum or maximum number of characters, you can do so here. You pull the the number of characters and store as an integer, and calculate how many characters are left.
If the user has reached the maximum number of characters, reset the textView text by stripping back to your max.
These vars are used to calculate how much you need to move your bottomView up and also for the resizing its subviews.
This method is just to change the colour / text of some UI elements. It's not strictly necessary.
This method brings the lettersLeftLabel onto view if you're using that. It's not necessary either.
This enables the submit button only if the minimum number of characters has been reached. It changes the colour as an indicator to the user.
If you want to limit the growth of the inputTV and surrounding elements, you can include this bit of code. It requires you to set the maximum number of lines you want to show. If the user exceeds the max, scroll is reenabled for the inputTV, otherwise it defaults to false (important to stop it bouncing).
This is the main resizing logic, moving the bottomView up and resizing its child views. The submit button needs to stay in the same position, so move it down as the bottomView grows.
NOTE: If you just want the barebones code, you only need to implement steps 3 and 8.
Apple has some code samples that deal with this exact situation.
I finally got it working. Here is my solution, can you guys spot any errors in my design?
#synthesize textView = _textView;
#synthesize callbackViewController = _callbackViewController;
-(void)keyboardWasShown:(NSNotification*)aNotification {
if(keyboardShown) {
return;
}
NSDictionary *info = [aNotification userInfo];
// Get the size of the keyboard.
NSValue *aValue = [info objectForKey:UIKeyboardFrameBeginUserInfoKey];
keyboardSize = [aValue CGRectValue].size;
// Resize the scroll view (which is the root view of the window)
CGRect viewFrame = [self.textView frame];
orientationAtShown = orientation;
if(orientation == UIInterfaceOrientationPortrait || orientation == UIInterfaceOrientationPortraitUpsideDown) {
viewFrame.size.height -= keyboardSize.height;
} else {
viewFrame.size.height -= keyboardSize.width;
}
self.textView.frame = viewFrame;
// Scroll the active text field into view.
//CGRect textFieldRect = [activeField frame];
[self.textView scrollRectToVisible:viewFrame animated:YES];
keyboardShown = YES;
}
-(void)keyboardWasHidden:(NSNotification*)aNotification {
if(!keyboardShown) {
return;
}
// Reset the height of the scroll view to its original value
CGRect viewFrame = [self.textView frame];
if(orientationAtShown == UIInterfaceOrientationPortrait || orientationAtShown == UIInterfaceOrientationPortraitUpsideDown) {
viewFrame.size.height += keyboardSize.height;
} else {
viewFrame.size.height += keyboardSize.width;
}
self.textView.frame = viewFrame;
keyboardShown = NO;
}
-(void)registerForKeyboardNotifications {
[[NSNotificationCenter defaultCenter] addObserver:self
selector:#selector(keyboardWasShown:)
name:UIKeyboardDidShowNotification object:nil];
[[NSNotificationCenter defaultCenter] addObserver:self
selector:#selector(keyboardWasHidden:)
name:UIKeyboardDidHideNotification object:nil];
}
-(void)viewWillAppear:(BOOL)animated {
keyboardShown = NO;
[self registerForKeyboardNotifications];
}
-(void)viewWillDisappear:(BOOL)animated {
[[NSNotificationCenter defaultCenter] removeObserver:self name:UIKeyboardWillShowNotification object:nil];
}
// Override to allow orientations other than the default portrait orientation.
- (BOOL)shouldAutorotateToInterfaceOrientation:(UIInterfaceOrientation)interfaceOrientation {
if(keyboardShown) {
[self keyboardWasHidden:nil];
}
orientation = interfaceOrientation;
CGRect viewFrame = [self.textView frame];
if(orientation == UIInterfaceOrientationPortrait || orientation == UIInterfaceOrientationPortraitUpsideDown) {
if(viewFrame.size.width > viewFrame.size.height) {
CGRect viewFrameFixed = CGRectMake(viewFrame.origin.x, viewFrame.origin.y, viewFrame.size.height, viewFrame.size.width);
self.textView.frame = viewFrameFixed;
}
} else {
if(viewFrame.size.width < viewFrame.size.height) {
CGRect viewFrameFixed = CGRectMake(viewFrame.origin.x, viewFrame.origin.y, viewFrame.size.height, viewFrame.size.width);
self.textView.frame = viewFrameFixed;
}
}
// Return YES for supported orientations
return YES;
}
#Alejandro above has the right idea, but his code does not work in landscape mode. I have amended his keyboardWasShown: method to work correctly in all orientations:
- (void)keyboardWasShown:(NSNotification *)notification {
if (self.textView != nil) {
NSDictionary* info = [notification userInfo];
CGRect keyboardRect = [self.textView convertRect:[[info objectForKey:UIKeyboardFrameEndUserInfoKey] CGRectValue] fromView:nil];
CGSize keyboardSize = keyboardRect.size;
self.textView.contentInset = UIEdgeInsetsMake(0, 0, keyboardSize.height, 0);
self.textView.scrollIndicatorInsets = self.textView.contentInset;
}
}
Add Observer first in viewDidLoad.
- (void)viewDidLoad {
[super viewDidLoad];
[[NSNotificationCenter defaultCenter] addObserver:self
selector:#selector(keyboardWasShown:)
name:UIKeyboardDidShowNotification object:nil];
[[NSNotificationCenter defaultCenter] addObserver:self
selector:#selector(keyboardWasHidden:)
name:UIKeyboardWillHideNotification object:nil];
}
Call the methods
- (void)keyboardWasShown:(NSNotification*)aNotification
{
NSDictionary* info = [aNotification userInfo];
CGSize kbSize = [[info objectForKey:UIKeyboardFrameBeginUserInfoKey] CGRectValue].size;
UIEdgeInsets contentInsets = UIEdgeInsetsMake(0.0, 0.0, kbSize.height, 0.0);
self.textView.contentInset = contentInsets;
self.textView.scrollIndicatorInsets = contentInsets;
// If active text field is hidden by keyboard, scroll it so it's visible
// Your app might not need or want this behavior.
CGRect aRect = self.view.frame;
aRect.size.height -= kbSize.height;
if (!CGRectContainsPoint(aRect, self.textView.frame.origin) ) {
[self.textView scrollRectToVisible:self.textView.frame animated:YES];
}
}
// Called when the UIKeyboardWillHideNotification is sent
- (void)keyboardWasHidden:(NSNotification*)aNotification
{
UIEdgeInsets contentInsets = UIEdgeInsetsZero;
self.textView.contentInset = contentInsets;
self.textView.scrollIndicatorInsets = contentInsets;
}
if you have more then 1 textfield or you want to reduce your code then try this code
- (void)textFieldDidBeginEditing:(UITextField *)textField{
[UIView beginAnimations:nil context:NULL];
[UIView setAnimationDuration:0.35f];
CGRect frame = self.view.frame;
frame.origin.y = (self.view.frame.size.height - textField.frame.origin.y) - self.view.frame.size.height+60;
if (frame.origin.y<-162) {
frame.origin.y = -162;
}
[self.view setFrame:frame];
[UIView commitAnimations];
}
-(BOOL)textFieldShouldEndEditing:(UITextField *)textField{
[UIView beginAnimations:nil context:NULL];
[UIView setAnimationDuration:0.35f];
CGRect frame = self.view.frame;
frame.origin.y = 0;
[self.view setFrame:frame];
[UIView commitAnimations];
return YES;
}
Extending #alejandro & #Mani :
Th final answer:
- (void)keyboardWasShown:(NSNotification *)notification {
if (self.textView != nil) {
NSDictionary* info = [notification userInfo];
CGRect keyboardRect = [self.textNote convertRect:[[info objectForKey:UIKeyboardFrameEndUserInfoKey] CGRectValue] fromView:nil];
CGSize keyboardSize = keyboardRect.size;
self.textView.contentInset = UIEdgeInsetsMake(0, 0, keyboardSize.height, 0);
self.textView.scrollIndicatorInsets = self.textView.contentInset;
}
}
- (void)keyboardWillBeHidden:(NSNotification*)notification {
self.textView.scrollIndicatorInsets = UIEdgeInsetsZero;
self.textView.scrollIndicatorInsets = UIEdgeInsetsZero;
}

How would I add a dissolve transition to my code? (comic book)

How would I add a dissolve transition to my code?
I tried looking at Apple's code but to no avail. Any ideas?
#import "ApotheosisViewController.h"
#implementation ApotheosisViewController
#synthesize scrollView1;
- (BOOL)shouldAutorotateToInterfaceOrientation: (UIInterfaceOrientation)interfaceOrientation {
return (interfaceOrientation == UIInterfaceOrientationLandscapeRight);
}
const CGFloat kScrollObjHeight = 320.0;
const CGFloat kScrollObjWidth = 480.0;
const NSUInteger kNumImages = 40;
- (void)layoutScrollImages
{
UIImageView *view = nil;
NSArray *subviews = [scrollView1 subviews];
// reposition all image subviews in a horizontal serial fashion
CGFloat curXLoc = 0;
for (view in subviews)
{
if ([view isKindOfClass:[UIImageView class]] && view.tag > 0)
{
CGRect frame = view.frame;
frame.origin = CGPointMake(curXLoc, 0);
view.frame = frame;
curXLoc += (kScrollObjWidth);
}
}
// set the content size so it can be scrollable
[scrollView1 setContentSize:CGSizeMake((kNumImages * kScrollObjWidth), [scrollView1 bounds].size.height)];
}
- (void)viewDidLoad
{
self.view.backgroundColor = [UIColor viewFlipsideBackgroundColor];
// 1. setup the scrollview for multiple images and add it to the view controller
//
// note: the following can be done in Interface Builder, but we show this in code for clarity
[scrollView1 setBackgroundColor:[UIColor blackColor]];
[scrollView1 setCanCancelContentTouches:NO];
scrollView1.indicatorStyle = UIScrollViewIndicatorStyleBlack;
scrollView1.clipsToBounds = NO; // default is NO, we want to restrict drawing within our scrollview
scrollView1.scrollEnabled = YES;
// pagingEnabled property default is NO, if set the scroller will stop or snap at each photo
// if you want free-flowing scroll, don't set this property.
scrollView1.pagingEnabled = YES;
// load all the images from our bundle and add them to the scroll view
NSUInteger i;
for (i = 1; i <= kNumImages; i++)
{
NSString *imageName = [NSString stringWithFormat:#"image%d.jpg", i];
UIImage *image = [UIImage imageNamed:imageName];
UIImageView *imageView = [[UIImageView alloc] initWithImage:image];
// setup each frame to a default height and width, it will be properly placed when we call "updateScrollList"
CGRect rect = imageView.frame;
rect.size.height = kScrollObjHeight;
rect.size.width = kScrollObjWidth;
imageView.frame = rect;
imageView.tag = i; // tag our images for later use when we place them in serial fashion
[scrollView1 addSubview:imageView];
[imageView release];
}
[self layoutScrollImages]; // now place the photos in serial layout within the scrollview
}
- (void)dealloc
{
[scrollView1 release];
[super dealloc];
}
- (void)didReceiveMemoryWarning
{
// invoke super's implementation to do the Right Thing, but also release the input controller since we can do that
// In practice this is unlikely to be used in this application, and it would be of little benefit,
// but the principle is the important thing.
//
[super didReceiveMemoryWarning];
}
#end
I can't immediately tell what the code you posted has to do with a dissolve transition.
If you are trying to go from one view to another, then you could put this in your code:
In
- (id)initWithNibName:(NSString *)nibNameOrNil bundle:(NSBundle *)nibBundleOrNil
for one viewController:
self.modalTransitionStyle = UIModalTransitionStyleCrossDissolve;
and when switching from one view to the other:
[self presentModalViewController:otherViewController animated:YES];