tableview not scrolling smoothly iOS xcode - tableview

Every time i scroll on the tableview and a new cell appears, it get's stuck for like a milli second, that happens every time a new cell appears,.. i tried so many options..
THIS IS WHERE I QUERY MY ARRAY
- (void) retrieveStrings {
PFQuery *retrieveAllPictures = [PFQuery queryWithClassName:#"String_Pictures"];
[retrieveAllPictures includeKey:#"string_owner"];
[retrieveAllPictures whereKey:#"string_boss" equalTo:[PFObject objectWithoutDataWithClassName:#"String" objectId:original_string_objectID]];
retrieveAllPictures.limit = [loadingNumber intValue];
[retrieveAllPictures orderByDescending:#"createdAt"];
[retrieveAllPictures findObjectsInBackgroundWithBlock:^(NSArray *objects, NSError *error) {
if (!error) {
originalString = [[NSArray alloc]initWithArray:objects];
[self.StringTable reloadData];
}
}];
}
THIS IS MY CELL FOR ROW AT INDEX PATH
- (UITableViewCell *)tableView:(UITableView *)tableView cellForRowAtIndexPath:(NSIndexPath *)indexPath
{
static NSString *CellIdentifier = #"originalStringCell";
OriginalStringTableViewCell *originalCell = [StringTable dequeueReusableCellWithIdentifier:CellIdentifier];
tempObject = [originalString objectAtIndex:indexPath.row];
userObject = [tempObject objectForKey:#"string_owner"];
originalTempString = [tempObject objectForKey:#"string_image"];
[originalTempString getDataInBackgroundWithBlock:^(NSData *data, NSError *error) {
if (!error) {
originalCell.original_string_image.image = [UIImage imageWithData:data];
CGFloat ImageWidth = ceil(originalCell.original_string_image.image.size.width);
CGFloat ImageHeight = ceil(originalCell.original_string_image.image.size.height);
CGFloat NewWidth = ceil ((ImageWidth / ImageWidth) * StringTable.frame.size.width);
CGFloat NewHeightImageRow = ceil ((ImageHeight / ImageWidth) * StringTable.frame.size.width);
originalCell.original_string_image.frame = CGRectMake(0, 53, NewWidth, NewHeightImageRow);
NSLog(#"%f",NewWidth);
[originalCell.stringIndicator stopAnimating];
originalCell.stringIndicator.hidden = YES;
[SVProgressHUD dismiss];
}
}];
return originalCell;
}

I have found solution using SDWEBIMAGE.
SDWebImageManager *StringPicturemanager = [SDWebImageManager sharedManager];
[StringPicturemanager downloadImageWithURL:[NSURL URLWithString:originalTempString.
options:0
progress:^(NSInteger receivedSize, NSInteger expectedSize) {
// progression tracking code
}
completed:^(UIImage *SDWStringImage, NSError *error, SDImageCacheType cacheType, BOOL finished, NSURL *imageURL) {
if (SDWStringImage) {
NSLog(#"JAAAAAA %#", SDWStringImage);
originalCell.original_string_image.image = SDWStringImage;
CGFloat ImageWidth = ceil(originalCell.original_string_image.image.size.width);
CGFloat ImageHeight = ceil(originalCell.original_string_image.image.size.height);
CGFloat NewWidth = ceil ((ImageWidth / ImageWidth) * StringTable.frame.size.width);
CGFloat NewHeightImageRow = ceil ((ImageHeight / ImageWidth) * StringTable.frame.size.width);
originalCell.original_string_image.frame = CGRectMake(0, 53, NewWidth, NewHeightImageRow);
NSLog(#"%f",NewWidth);
[originalCell.stringIndicator stopAnimating];
originalCell.stringIndicator.hidden = YES;
[SVProgressHUD dismiss];
}
}];

Related

NSMutableArray causing crash

I am sorry for the long post but I am at my wits end and have been stumped for days over this. Here's the scenario. My app loads a response from core data, converts the values to NSStrings so that I can add them to an NSDictionary. Then the NSDictionary is converted to NSData so I can attach it as a file to email. The purpose of this is so I can create a database of information including images, videos, etc. I was able to get everything to work except I am having an issue with an NSMutableArray. Here's the process:
I create an event and then load the data for exporting with this code.
EventDB *per = [[EventDB alloc]init];
per.customLayoutArray = [record.customLayoutArray description] ?
[record.customLayoutArray description] : #"";
NSDictionary *dict = [per dictionaryWithValuesForKeys:#[#"customLayoutArray"];
NSData *data = [NSJSONSerialization dataWithJSONObject:dict options:0 error:NULL];
Then I email the data using MFMailComposer. Then I have a custom UTI that allows me the open the url from the email and then I import the data and load it into my coredata entity with this
if([[url pathExtension] isEqualToString:#"ipix"]) {
NSData *data = [NSData dataWithContentsOfURL:url];
NSError *error;
NSDictionary *jsonData = [NSJSONSerialization JSONObjectWithData:data
options:kNilOptions
error:&error];
NSEntityDescription *entity = [NSEntityDescription entityForName:#"TSPItem"
inManagedObjectContext:self.managedObjectContext];
TSPItem *record = (TSPItem *)[[NSManagedObject alloc] initWithEntity:entity
insertIntoManagedObjectContext:self.managedObjectContext];
if (record) {
NSString *datetime = [jsonData objectForKey:#"customLayoutArray"];
record.customLayoutArray = [[datetime propertyList] mutableCopy];
}
That works fine. It does import the way I want but when I launch the event I get this crash message
** Terminating app due to uncaught exception 'NSInvalidArgumentException', reason:
'-[__NSCFString apply]: unrecognized selector sent to instance 0x1c81a5f60
Now here's the code where it crashes.
NSMutableArray *archiveArray = self.record.customLayoutArray;
NSString *mycustom = [NSString stringWithFormat:#"%#_customlayout",
self.record.eventname];
NSData *data = [NSKeyedArchiver archivedDataWithRootObject:archiveArray];
[[NSUserDefaults standardUserDefaults] setObject:data forKey:mycustom];
self.customLayoutArray = [NSKeyedUnarchiver unarchiveObjectWithData:data];
NSLog(#"BOOTH EVENT ID %#", self.customLayoutArray);
[self.customLayoutArray makeObjectsPerformSelector:#selector(apply)];
This is the log from BOOTH EVENT ID
BOOTH EVENT ID (
"<Rectangle:0x102d38cb0self.scaleValue=1.842393\n, self.rotateValue=0.000000\n, self.width=368.478516\n, self.height=368.478516\n, self.radius=0\n, self.frame={{104, 113.5}, {200, 200}}\n, self.isApplied=NO\n>",
"<Rectangle:0x102d393c0self.scaleValue=1.000000\n, self.rotateValue=0.000000\n, self.width=200.000000\n, self.height=200.000000\n, self.radius=0\n, self.frame={{253, 273.5}, {200, 200}}\n, self.isApplied=NO\n>"
)
The app crashes here. Now if I load the original event on my iPad (the one that I didn't export) the app works perfect and the NSLog response for BOOTH EVENT ID is identical.
The "apply" section refers to this file.
#import "Rectangle.h"
#import "DeviceSize.h"
#implementation Rectangle
- (id)initWithFrame:(CGRect)frame
{
self = [super initWithFrame:frame];
if (self) {
// Initialization code
self.clipsToBounds = YES;
self.userInteractionEnabled = YES;
}
return self;
}
- (void)encodeWithCoder:(NSCoder *)coder {
[coder encodeObject:[NSNumber numberWithFloat:self.scaleValue] forKey:#"ScaleValue"];
[coder encodeObject:[NSNumber numberWithFloat:self.rotateValue] forKey:#"RotateValue"];
[coder encodeObject:[NSNumber numberWithFloat:self.width] forKey:#"Width"];
[coder encodeObject:[NSNumber numberWithFloat:self.height] forKey:#"Height"];
[coder encodeObject:[NSNumber numberWithInteger:self.radius] forKey:#"Radius"];
[coder encodeObject:[NSNumber numberWithBool:self.isApplied] forKey:#"isApplied"];
[coder encodeObject:self.image forKey:#"Image"];
[coder encodeObject:self.backgroundColor forKey:#"BackgroundColor"];
[coder encodeObject:[NSValue valueWithCGPoint:self.center] forKey:#"CenterPoint"];
}
- (id)initWithCoder:(NSCoder *)coder {
self = [super init];
if (self) {
self.scaleValue = [[coder decodeObjectForKey:#"ScaleValue"] floatValue];
self.rotateValue = [[coder decodeObjectForKey:#"RotateValue"] floatValue];
self.width = [[coder decodeObjectForKey:#"Width"] floatValue];
self.height = [[coder decodeObjectForKey:#"Height"] floatValue];
self.radius = [[coder decodeObjectForKey:#"Radius"] integerValue];
self.isApplied = [[coder decodeObjectForKey:#"isApplied"] boolValue];
[self.layer setCornerRadius:self.radius];
self.image = [coder decodeObjectForKey:#"Image"];
[self setBackgroundColor:[coder decodeObjectForKey:#"BackgroundColor"]];
//
if (self.width == self.height)
{
CGRect rect = CGRectMake(0, 0,200, 200);
self.frame = rect;
}
if (self.width > self.height)
{
CGRect rect = CGRectMake(0, 0,200, 150);
self.frame = rect;
}
if (self.width < self.height)
{
CGRect rect = CGRectMake(0, 0,150, 200);
self.frame = rect;
}
self.center = [[coder decodeObjectForKey:#"CenterPoint"] CGPointValue];
}
return self;
}
- (void)drawRect:(CGRect)rect
{
/* Set UIView Border */
// Get the contextRef
CGContextRef contextRef = UIGraphicsGetCurrentContext();
// Set the border width
CGContextSetLineWidth(contextRef, 5.0);
// Set the border color to RED
CGContextSetRGBStrokeColor(contextRef, 255.0, 0.0, 0.0, 1.0);
// Draw the border along the view edge
CGContextStrokeRect(contextRef, rect);
}
- (BOOL)canBecomeFirstResponder {
return YES;
}
- (NSString *)description {
NSMutableString *description = [NSMutableString stringWithFormat:#"<%#:%p", NSStringFromClass([self class]), self];
[description appendFormat:#"self.scaleValue=%f\n", self.scaleValue];
[description appendFormat:#", self.rotateValue=%f\n", self.rotateValue];
[description appendFormat:#", self.width=%f\n", self.width];
[description appendFormat:#", self.height=%f\n", self.height];
[description appendFormat:#", self.radius=%li\n", (long)self.radius];
[description appendFormat:#", self.frame=%#\n", NSStringFromCGRect(self.frame)];
[description appendFormat:#", self.isApplied=%#\n", self.isApplied ? #"YES" : #"NO"];
[description appendString:#">"];
return description;
}
- (id)copyWithZone:(NSZone *)zone {
Rectangle *copy = [[[self class] allocWithZone:zone] init];
if (copy != nil) {
copy.scaleValue = self.scaleValue;
copy.rotateValue = self.rotateValue;
copy.width = self.width;
copy.height = self.height;
copy.radius = self.radius;
copy.frame = self.frame;
copy.isApplied = self.isApplied;
}
return copy;
}
#end
#implementation Rectangle(ApplyRotate)
#pragma mark -
- (Rectangle *)apply {
if (self.isApplied) {
return self;
}
Rectangle *rectangle = self;
CGPoint centerPoint = rectangle.center;
CGAffineTransform rotate = CGAffineTransformMakeRotation(DEGREES_TO_RADIANS(rectangle.rotateValue));
CGAffineTransform scale = CGAffineTransformMakeScale(rectangle.scaleValue, rectangle.scaleValue);
CGAffineTransform scaleAndRotate = CGAffineTransformConcat(rotate, scale);
rectangle.transform = scaleAndRotate;
rectangle.center = centerPoint;
rectangle.isApplied = YES;
return rectangle;
}
#end

UIButton Randomize Title With Single Characters

The code below takes a string, adds each letter to an array and shuffles that array and shows the end result in a label. That works well. But I'd like for each character to contain a single character of the shuffled string. Right now it almost works, but it always repeats the characters. Like instead of having a series of 6 buttons with their titles: L e a g u e, the code generates repeated characters like: Leaauu.
My code is this:
- (IBAction)shuffleButttonTitles:(id)sender {
// The mutable array must be created here to create a new instance each time the button is tapped
letters = [[NSMutableArray alloc] init];
str = #"League";
length = str.length;
NSString *letter;
UIButton *button;
// First loop through the string and add each letter to an array
for (int i = 0; i < length; i++) {
letter = [NSString stringWithFormat:#"%c", [str characterAtIndex:i]];
[letters addObject:letter];
}
// Shuffle the string for the label/buttons
for (int i = 0; i < length; i++) {
int value = arc4random() % (length - 1);
[letters exchangeObjectAtIndex:i withObjectAtIndex:value];
//Create the button and shuffle the letters for their titles
button = [[UIButton alloc] initWithFrame:CGRectMake(50 * i, 350, 44, 44)];
// HERE THE CODE REPEATS THE CHARACTERS
[button setTitle:[letters objectAtIndex:i] forState:UIControlStateNormal];
//Store the button in our array
[myButtons addObject:button];
NSLog(#"Letters in Array: %lu", letters.count);
}
for (UIButton *button in myButtons){
[button setBackgroundColor:[UIColor redColor]];
[self.view addSubview:button];
}
// Now we set the randomized title to the label
NSString *results = [letters componentsJoinedByString:#""];
string.text = results;
}
After some searching on the web I've figured it out. I post the complete code for others. This code takes a random string from the Characters.txt file and shuffles that string. Then it rotates the tiles slighty. You can enter the correct word when you have figured out the anagram, which then shows an alert view if you got it or didn't get it.
#define kTileSpacing 20
#define randomf(minX,maxX) ((float)(arc4random() % (maxX - minX + 1)) + (float)minX)
#interface ViewController ()
#end
#implementation ViewController
{
}
#synthesize progressView;
- (void)viewDidLoad {
[super viewDidLoad];
NSString *path = [[NSBundle mainBundle] pathForResource:#"Anagrams" ofType:#"plist"];
dictionary = [[NSMutableArray alloc] initWithContentsOfFile:path];
NSString *quotesFile = [[NSBundle mainBundle] pathForResource:#"Characters" ofType:#"txt"];
fileContents = [NSString stringWithContentsOfFile:quotesFile encoding:NSUTF8StringEncoding error:NULL];
// [txtField becomeFirstResponder];
//[[NSNotificationCenter defaultCenter] addObserver:self selector:#selector(checkWord:) name:nil object:nil];
}
- (IBAction)clear:(id)sender {
quoteArray = [fileContents componentsSeparatedByString:#"\n"];
NSString *quoteToDisplay;
currentQuestion = arc4random() % quoteArray.count;
quoteToDisplay = [quoteArray objectAtIndex: currentQuestion];
welldone.text = quoteToDisplay;
txtField.text = nil;
[txtField becomeFirstResponder];
for (UILabel *lbl in myButtons) {
[lbl removeFromSuperview];
}
}
- (IBAction)ShuffleString:(id)sender {
[self clear:nil];
// The mutable array must be created here to create a new instance each time the button is tapped
charactersArray = [[NSMutableArray alloc] init];
indexArray = [[NSMutableArray alloc] init];
myButtons = [[NSMutableArray alloc] init];
// 1. Shuffle the plist with the words to form anagrams from
currentQuestion = arc4random() % quoteArray.count;
str = [quoteArray objectAtIndex: currentQuestion]; //[[dictionary objectAtIndex:currentQuestion] objectForKey:#"Anagram"];
length = str.length;
NSString *letter;
// 2. Loop throught the chosen word and break it down into its letters and add them to an array
for (int i = 0; i < str.length; i++) {
// [charactersArray removeObjectAtIndex:i];
letter = [NSString stringWithFormat:#"%c", [str characterAtIndex:i]];
[charactersArray addObject:letter];
// NSLog(#"Number of letters: %#", charactersArray);
}
while ([charactersArray count]) {
int randomizing = arc4random() % [charactersArray count];
[indexArray addObject:[charactersArray objectAtIndex:randomizing]];
[charactersArray removeObjectAtIndex:randomizing];
// NSLog(#"NO REPEAT SHUFFLE: %lu", (unsigned long)indexArray.count);
}
/***************/
CGFloat staticY = self.view.bounds.size.height / 9 * 1; // Static X for all buttons.
CGFloat staticWidth = 46; // Static Width for all Buttons.
CGFloat staticHeight = 46; // Static Height for all buttons.
CGFloat staticPadding = 10; // Padding to add between each button.
float tileSize = ceilf( self.view.bounds.size.width / str.length );
NSLog(#"size %f", tileSize);
CGFloat xOffset = (self.view.bounds.size.width - str.length * (44+staticPadding));
NSLog(#"xOffset %f", tileSize);
xOffset = tileSize/ 2;
for (int i = 0; i < str.length; i++) {
singleCharacterLabel = [[UILabel alloc] init];
singleCharacterLabel.textAlignment = NSTextAlignmentCenter;
singleCharacterLabel.font = [UIFont fontWithName:#"Verdana-Bold" size:21];
singleCharacterLabel.frame = CGRectMake((staticPadding + (i * (staticHeight + staticPadding))), staticY, staticWidth, staticHeight);
// NSLog(#"X: %f", (staticPadding + (i * (staticHeight + staticPadding))));
//singleCharacterLabel.center = CGPointMake(i * 50 + self.view.bounds.origin.x + self.view.bounds.size.width /3, 80); // i * int +self... int = space between labels. Here it is '50'
// singleCharacterLabel.center = CGPointMake(self.view.bounds.size.width * i, self.view.bounds.size.height / 5 * 1); // 1/4th down from the top
singleCharacterLabel.layer.backgroundColor = [UIColor colorWithPatternImage:[UIImage imageNamed:#"Tile.png"]].CGColor;
NSString *anagramString = [indexArray objectAtIndex:i];
singleCharacterLabel.text = anagramString;
[myButtons addObject:singleCharacterLabel];
//1
//set random rotation of the tile
//anywhere between -0.2 and 0.3 radians
float rotation = randomf(0,50) / (float)100 - 0.2;
singleCharacterLabel.transform = CGAffineTransformMakeRotation( rotation );
//2
//move randomly upwards
int yOffset = (arc4random() % 10) - 10;
singleCharacterLabel.center = CGPointMake(singleCharacterLabel.center.x, singleCharacterLabel.center.y + yOffset);
[self.view addSubview:singleCharacterLabel];
//NSLog(#"LOOP: %#", anagramString);
}
}
- (IBAction)checkWord:(id)sender {
if (([txtField.text isEqual:str])) {
alertCorrect = [[UIAlertView alloc] initWithTitle:#"" message:#"Well done!" delegate:self cancelButtonTitle:nil otherButtonTitles:#"Next", nil];
[alertCorrect show];
} else {
alertWrong = [[UIAlertView alloc] initWithTitle:#"" message:#"Sorry, try again." delegate:self cancelButtonTitle:nil otherButtonTitles:#"OK", nil];
[alertWrong show];
}
// NSLog(#"String is: %lu", str.length);
}
- (void)alertView:(UIAlertView *)alertView clickedButtonAtIndex:(NSInteger)buttonIndex {
if (alertView == alertCorrect) {
if (buttonIndex == 0) {
[self ShuffleString:nil];
NSLog(#"next");
}
}
if (alertView == alertWrong) {
if (buttonIndex == 1) {
// Wrong answer. Close view and let user try again
}
}
}
- (BOOL)textField:(UITextField *)textField shouldChangeCharactersInRange:(NSRange)range replacementString:(NSString *)string {
if (txtField.text.length == length) {
[self checkWord:nil];
NSLog(#"You entered %lu characters", length);
}
return YES;
}

Getting a "Missing Context For Method Declaration" implementing a map search bar in xcode

im getting an error that says "Missing Context For Method Declaration" when i implement this code into my viewcontroller.m:
- (void)searchBarSearchButtonClicked:(UISearchBar *)theSearchBar {
[theSearchBar resignFirstResponder];
CLGeocoder *geocoder = [[CLGeocoder alloc] init];
[geocoder geocodeAddressString:theSearchBar.text completionHandler:^(NSArray *placemarks, NSError *error) {
//Error checking
CLPlacemark *placemark = [placemarks objectAtIndex:0];
MKCoordinateRegion region;
region.center.latitude = placemark.region.center.latitude;
region.center.longitude = placemark.region.center.longitude;
MKCoordinateSpan span;
double radius = placemark.region.radius / 1000; // convert to km
NSLog(#"[searchBarSearchButtonClicked] Radius is %f", radius);
span.latitudeDelta = radius / 112.0;
region.span = span;
[theMapView setRegion:region animated:YES];
}];
}

Why is my UIpageControl is not displayed?

I downloaded a dome about UIScorllView and UIPageControl. Why UIPageControl is not display?
Here is the code ,I am new in Iphone .Any help will be appreciated!
ScrollView.M I put the ResultViewController into ScrollView. I want scroll the resultViewController with PageController.
- (void)loadScrollViewWithPage:(int)page
{
if (page < 0)
return;
if (page >= pageNumber)
return;
ResultViewController *controller = [viewControllers objectAtIndex:page];
if ((NSNull *)controller == [NSNull null])
{
controller = [[ResultViewController alloc] initWithPageNumber:page locations:existLocations];
[viewControllers replaceObjectAtIndex:page withObject:controller];
[controller release];
}
if (controller.view.superview == nil)
{
CGRect frame = scrollView.frame;
frame.origin.x = frame.size.width * page;
frame.origin.y = 0;
controller.view.frame = frame;
[scrollView addSubview:controller.view];
}
}
- (void)viewDidLoad
{
[super viewDidLoad];
existLocations = [FileManagerUtil readPlistFileForDictionary:#"Locations" fileName:#"CloudCheckLocations.plist"];
pageNumber = [existLocations count];
NSMutableArray *controllers = [[NSMutableArray alloc] init];
for (unsigned i = 0; i < pageNumber; i++)
{
[controllers addObject:[NSNull null]];
}
self.viewControllers = controllers;
[controllers release];
scrollView = [[UIScrollView alloc] initWithFrame:CGRectMake(0, 0, 320, 480)];
[self.navigationItem setTitle:#"NetWork condition"];
scrollView.pagingEnabled = YES;
scrollView.contentSize = CGSizeMake(scrollView.frame.size.width * pageNumber, scrollView.frame.size.height);
scrollView.showsHorizontalScrollIndicator = NO;
scrollView.showsVerticalScrollIndicator = NO;
scrollView.scrollsToTop = NO;
scrollView.delegate = self;
pageContronl.numberOfPages = pageNumber;
pageContronl.currentPage = 0;
[pageContronl addTarget:self action:#selector(changePage:) forControlEvents:UIControlEventValueChanged];
[pageContronl setBackgroundColor:[UIColor blackColor]];
[self loadScrollViewWithPage:0];
[self loadScrollViewWithPage:1];
[scrollView addSubview:pageContronl];
[self.view addSubview:scrollView];
}
- (void)scrollViewDidScroll:(UIScrollView *)sender
{
if (pageControlUsed)
{
return;
}
CGFloat pageWidth = scrollView.frame.size.width;
int page = floor((scrollView.contentOffset.x - pageWidth / 2) / pageWidth) + 1;
pageContronl.currentPage = page;
[self loadScrollViewWithPage:page - 1];
[self loadScrollViewWithPage:page];
[self loadScrollViewWithPage:page + 1];
}
- (void)scrollViewWillBeginDragging:(UIScrollView *)scrollView
{
pageControlUsed = NO;
}
- (void)scrollViewDidEndDecelerating:(UIScrollView *)scrollView
{
pageControlUsed = NO;
}
- (IBAction)changePage:(id)sender
{
int page = pageContronl.currentPage;
[self loadScrollViewWithPage:page - 1];
[self loadScrollViewWithPage:page];
[self loadScrollViewWithPage:page + 1];
CGRect frame = scrollView.frame;
frame.origin.x = frame.size.width * page;
frame.origin.y = 0;
[scrollView scrollRectToVisible:frame animated:YES];
pageControlUsed = YES;
}
ScrollView.h
#interface ScrollViewController : UIViewController<UIScrollViewDelegate>
{
NSMutableArray *viewControllers;
NSString *currectNetWork;
NSString *flag;
NSString *locationName;
IBOutlet UIScrollView *scrollView;
IBOutlet UIPageControl *pageContronl;
BOOL pageControlUsed;
int pageNumber;
NSMutableDictionary *existLocations;
}
#property (nonatomic,retain) NSString *currectNetWork;
#property (nonatomic,retain) NSString *flag;
#property (nonatomic,retain) NSString *locationName;
#property (nonatomic,retain) UIPageControl * pageContronl;
#property (nonatomic,retain) UIScrollView * scrollView;
#property (nonatomic,retain) NSMutableArray *viewControllers;
#property (nonatomic,retain) NSMutableDictionary *existLocations;
(IBAction)changePage:(id)sender;
ResultViewControl.M
This method will call by ScrollView.M
- (id)initWithPageNumber:(int)page locations :(NSMutableDictionary *) locations
{
titilArray = [[NSArray alloc] initWithObjects:#"Today", #"Past 7 Day",#"Past 30 Day",nil];
if (self = [super initWithNibName:#"ResultViewController" bundle:nil])
{
pageNumber = page;
existLocations = locations;
}
return self;
}
Check the background colour of pageControl and parent view. If both have same colour (default white) page control will not display.
In IOS6, you have new methods pageIndicatorTintColor and currentPageIndicatorTintColor.
Hope this will help.
Check your top and bottom constraints of container view/ tableView(if present). Both must not be attached with Top/Bottom Layout Guide. Attach them with container Margins.

Get UITableView to scroll to the selected UITextField and Avoid Being Hidden by Keyboard

I have a UITextField in a table view on a UIViewController (not a UITableViewController).
If the table view is on a UITableViewController, the table will automatically scroll to the textField being edited to prevent it from being hidden by the keyboard. But on a UIViewController it does not.
I have tried for a couple of days reading through multiple ways to try to accomplish this and I cannot get it to work. The closest thing that actually scrolls is:
-(void) textFieldDidBeginEditing:(UITextField *)textField {
// SUPPOSEDLY Scroll to the current text field
CGRect textFieldRect = [textField frame];
[self.wordsTableView scrollRectToVisible:textFieldRect animated:YES];
}
However this only scrolls the table to the topmost row.
What seems like an easy task has been a couple of days of frustration.
I am using the following to construct the tableView cells:
- (UITableViewCell *)tableView:(UITableView *)aTableView
cellForRowAtIndexPath:(NSIndexPath *)indexPath {
NSString *identifier = [NSString stringWithFormat: #"%d:%d", [indexPath indexAtPosition: 0], [indexPath indexAtPosition:1]];
UITableViewCell *cell = [aTableView dequeueReusableCellWithIdentifier:identifier];
if (cell == nil) {
cell = [[[UITableViewCell alloc]
initWithStyle:UITableViewCellStyleDefault
reuseIdentifier:identifier] autorelease];
cell.accessoryType = UITableViewCellAccessoryNone;
UITextField *theTextField = [[UITextField alloc] initWithFrame:CGRectMake(180, 10, 130, 25)];
theTextField.adjustsFontSizeToFitWidth = YES;
theTextField.textColor = [UIColor redColor];
theTextField.text = [textFieldArray objectAtIndex:indexPath.row];
theTextField.keyboardType = UIKeyboardTypeDefault;
theTextField.returnKeyType = UIReturnKeyDone;
theTextField.font = [UIFont boldSystemFontOfSize:14];
theTextField.backgroundColor = [UIColor whiteColor];
theTextField.autocorrectionType = UITextAutocorrectionTypeNo;
theTextField.autocapitalizationType = UITextAutocapitalizationTypeNone;
theTextField.clearsOnBeginEditing = NO;
theTextField.textAlignment = UITextAlignmentLeft;
//theTextField.tag = 0;
theTextField.tag=indexPath.row;
theTextField.delegate = self;
theTextField.clearButtonMode = UITextFieldViewModeWhileEditing;
[theTextField setEnabled: YES];
[cell addSubview:theTextField];
[theTextField release];
}
return cell;
}
I suspect I can get the tableView to scroll properly if I can somehow pass the indexPath.row in the textFieldDidBeginEditing method?
Any help is appreciated.
In my app, I have successfully used a combination of contentInset and scrollToRowAtIndexPath like this:
When you want to display the keyboard, just add a contentInset at the bottom with your table with desired height:
tableView.contentInset = UIEdgeInsetsMake(0, 0, height, 0);
Then, you can safely use
[tableView scrollToRowAtIndexPath:[NSIndexPath indexPathForRow:cell_index inSection:cell_section] animated:YES];
By adding the contentInset, even if you are focusing on the last cell the tableView will still be able to scroll. Just make sure that when you are dismissing the keyboard, you reset the contentInset.
EDIT:
If you have only one section (you can replace cell_section with 0) and the use the textView tag to inform the cell row.
Swift
#objc private func keyboardWillShow(_ notification: Notification) {
guard let userinfo = notification.userInfo else {
return
}
guard
let duration = (userinfo[UIResponder.keyboardAnimationDurationUserInfoKey] as? NSNumber)?.doubleValue,
let endFrame = (userinfo[UIResponder.keyboardFrameEndUserInfoKey] as? NSValue)?.cgRectValue,
let curveOption = userinfo[UIResponder.keyboardAnimationCurveUserInfoKey] as? UInt else {
return
}
UIView.animate(withDuration: duration, delay: 0, options: [.beginFromCurrentState, .init(rawValue: curveOption)], animations: {
let edgeInsets = UIEdgeInsets(top: 0, left: 0, bottom: endFrame.height, right: 0)
self.scrollView.contentInset = edgeInsets
self.scrollView.scrollIndicatorInsets = edgeInsets
})
}
#objc private func keyboardWillHide(_ notification: Notification) {
guard let userinfo = notification.userInfo else {
return
}
guard
let duration = (userinfo[UIResponder.keyboardAnimationDurationUserInfoKey] as? NSNumber)?.doubleValue,
let curveOption = userinfo[UIResponder.keyboardAnimationCurveUserInfoKey] as? UInt else {
return
}
UIView.animate(withDuration: duration, delay: 0, options: [.beginFromCurrentState, .init(rawValue: curveOption)], animations: {
let edgeInsets = UIEdgeInsets.zero
self.scrollView.contentInset = edgeInsets
self.scrollView.scrollIndicatorInsets = edgeInsets
})
}
override func viewDidLoad() {
super.viewDidLoad()
// ...
subscribeToKeyboardNotifications()
}
deinit {
unsubscribeFromKeyboardNotifications()
}
private func subscribeToKeyboardNotifications() {
NotificationCenter.default.addObserver(self, selector: #selector(keyboardWillShow), name: UIWindow.keyboardWillShowNotification, object: nil)
NotificationCenter.default.addObserver(self, selector: #selector(keyboardWillHide), name: UIWindow.keyboardWillHideNotification, object: nil)
}
private func unsubscribeFromKeyboardNotifications() {
NotificationCenter.default.removeObserver(self, name: UIWindow.keyboardWillShowNotification, object: nil)
NotificationCenter.default.removeObserver(self, name: UIWindow.keyboardWillHideNotification, object: nil)
}
Objective C
- (void)keyboardWillShow:(NSNotification *)sender
{
CGFloat height = [[sender.userInfo objectForKey:UIKeyboardFrameEndUserInfoKey] CGRectValue].size.height;
NSTimeInterval duration = [[sender.userInfo objectForKey:UIKeyboardAnimationDurationUserInfoKey] doubleValue];
UIViewAnimationOptions curveOption = [[sender.userInfo objectForKey:UIKeyboardAnimationCurveUserInfoKey] unsignedIntegerValue] << 16;
[UIView animateWithDuration:duration delay:0 options:UIViewAnimationOptionBeginFromCurrentState|curveOption animations:^{
UIEdgeInsets edgeInsets = UIEdgeInsetsMake(0, 0, height, 0);
tableView.contentInset = edgeInsets;
tableView.scrollIndicatorInsets = edgeInsets;
} completion:nil];
}
- (void)keyboardWillHide:(NSNotification *)sender
{
NSTimeInterval duration = [[sender.userInfo objectForKey:UIKeyboardAnimationDurationUserInfoKey] doubleValue];
UIViewAnimationOptions curveOption = [[sender.userInfo objectForKey:UIKeyboardAnimationCurveUserInfoKey] unsignedIntegerValue] << 16;
[UIView animateWithDuration:duration delay:0 options:UIViewAnimationOptionBeginFromCurrentState|curveOption animations:^{
UIEdgeInsets edgeInsets = UIEdgeInsetsZero;
tableView.contentInset = edgeInsets;
tableView.scrollIndicatorInsets = edgeInsets;
} completion:nil];
}
And in - (void)viewDidLoad
[[NSNotificationCenter defaultCenter] addObserver:self selector:#selector(keyboardWillShow:) name:UIKeyboardWillShowNotification object:nil];
[[NSNotificationCenter defaultCenter] addObserver:self selector:#selector(keyboardWillHide:) name:UIKeyboardWillHideNotification object:nil];
Then
- (void)dealloc
{
[[NSNotificationCenter defaultCenter] removeObserver:self];
}
This is a tweak to FunkyKat's answer (big thank you FunkyKat!). It would probably be beneficial to not hardcode UIEdgeInsetsZero for future iOS compatibility.
Instead, I ask for the current inset value and tweak the bottom value as needed.
- (void)keyboardWillShow:(NSNotification *)sender {
CGSize kbSize = [[[sender userInfo] objectForKey:UIKeyboardFrameEndUserInfoKey] CGRectValue].size;
NSTimeInterval duration = [[[sender userInfo] objectForKey:UIKeyboardAnimationDurationUserInfoKey] doubleValue];
CGFloat height = UIDeviceOrientationIsPortrait([[UIDevice currentDevice] orientation]) ? kbSize.height : kbSize.width;
if (isIOS8()) height = kbSize.height;
[UIView animateWithDuration:duration animations:^{
UIEdgeInsets edgeInsets = [[self tableView] contentInset];
edgeInsets.bottom = height;
[[self tableView] setContentInset:edgeInsets];
edgeInsets = [[self tableView] scrollIndicatorInsets];
edgeInsets.bottom = height;
[[self tableView] setScrollIndicatorInsets:edgeInsets];
}];
}
- (void)keyboardWillHide:(NSNotification *)sender {
NSTimeInterval duration = [[[sender userInfo] objectForKey:UIKeyboardAnimationDurationUserInfoKey] doubleValue];
[UIView animateWithDuration:duration animations:^{
UIEdgeInsets edgeInsets = [[self tableView] contentInset];
edgeInsets.bottom = 0;
[[self tableView] setContentInset:edgeInsets];
edgeInsets = [[self tableView] scrollIndicatorInsets];
edgeInsets.bottom = 0;
[[self tableView] setScrollIndicatorInsets:edgeInsets];
}];
}
For the sake of anyone else running into this issue, I'm posting the necessary methods here:
- (UITableViewCell *)tableView:(UITableView *)aTableView cellForRowAtIndexPath:(NSIndexPath *)indexPath {
NSString *identifier = [NSString stringWithFormat: #"%d:%d", [indexPath indexAtPosition: 0], [indexPath indexAtPosition:1]];
UITableViewCell *cell = [aTableView dequeueReusableCellWithIdentifier:identifier];
if (cell == nil) {
cell = [[[UITableViewCell alloc] initWithStyle:UITableViewCellStyleDefault reuseIdentifier:identifier] autorelease];
UITextField *theTextField = [[UITextField alloc] initWithFrame:CGRectMake(180, 10, 130, 25)];
theTextField.keyboardType = UIKeyboardTypeDefault;
theTextField.returnKeyType = UIReturnKeyDone;
theTextField.clearsOnBeginEditing = NO;
theTextField.textAlignment = UITextAlignmentLeft;
// (The tag by indexPath.row is the critical part to identifying the appropriate
// row in textFieldDidBeginEditing and textFieldShouldEndEditing below:)
theTextField.tag=indexPath.row;
theTextField.delegate = self;
theTextField.clearButtonMode = UITextFieldViewModeWhileEditing;
[theTextField setEnabled: YES];
[cell addSubview:theTextField];
[theTextField release];
}
return cell;
}
-(void) textFieldDidBeginEditing:(UITextField *)textField {
int z = textField.tag;
if (z > 4) {
// Only deal with the table row if the row index is 5
// or greater since the first five rows are already
// visible above the keyboard
// resize the UITableView to fit above the keyboard
self.wordsTableView.frame = CGRectMake(0.0,44.0,320.0,200.0);
// adjust the contentInset
wordsTableView.contentInset = UIEdgeInsetsMake(0, 0, 0, 10);
// Scroll to the current text field
[wordsTableView scrollToRowAtIndexPath:[NSIndexPath indexPathForRow:z inSection:0] atScrollPosition:UITableViewScrollPositionBottom animated:YES];
}
}
- (BOOL)textFieldShouldEndEditing:(UITextField *)textField {
// Determine which row is being edited
int z = textField.tag;
if (z > 4) {
// resize the UITableView to the original size
self.wordsTableView.frame = CGRectMake(0.0,44.0,320.0,416.0);
// Undo the contentInset
wordsTableView.contentInset = UIEdgeInsetsMake(0, 0, 0, 0);
}
return YES;
}
- (BOOL)textFieldShouldReturn:(UITextField *)textField {
// Dismisses the keyboard when the "Done" button is clicked
[textField resignFirstResponder];
return YES;
}
I needed a simple solution so for me helped:
func textFieldShouldBeginEditing(_ textField: UITextField) -> Bool {
let pointInTable = textField.superview!.convert(textField.frame.origin, to: tableView)
var tableVContentOffset = tableView.contentOffset
tableVContentOffset.y = pointInTable.y
if let accessoryView = textField.inputAccessoryView {
tableVContentOffset.y -= accessoryView.frame.size.height
}
tableView.setContentOffset(tableVContentOffset, animated: true)
return true;
}
Try my coding, this will help for ypu
tabelview.contentInset = UIEdgeInsetsMake(0, 0, 210, 0);
[tableview scrollToRowAtIndexPath:[NSIndexPath indexPathForRow:your_indexnumber inSection:Your_section]
atScrollPosition:UITableViewScrollPositionMiddle animated:NO];
Apple has an official post explaining how to do this naturally as they do in the UITableViewController. My Stackoverflow answer has this explained along with a swift version.
https://stackoverflow.com/a/31869898/1032179
You need to resize the tableView itself so that it does not go under the keyboard.
-(void) textFieldDidBeginEditing:(UITextField *)textField {
// SUPPOSEDLY Scroll to the current text field
self.worldsTableView.frame = CGRectMake(//make the tableView smaller; to only be in the area above the keyboard);
CGRect textFieldRect = [textField frame];
[self.wordsTableView scrollRectToVisible:textFieldRect animated:YES];
}
Alternatively, you can use a keyboard notification; this works slightly better because you have more information, and is more consistent in terms of knowing when the keyboard is coming up:
//ViewDidLoad
[[NSNotificationCenter defaultCenter] addObserver:self selector:#selector(keyboardWillShow:) name:UIKeyboardWillShowNotification object:nil];
[[NSNotificationCenter defaultCenter] addObserver:self selector:#selector(keyboardWillHide:) name:UIKeyboardWillHideNotification object:nil];
And then implement:
- (void)keyboardWillShow:(NSNotification *)notification {
}
- (void)keyboardWillHide:(NSNotification *)notification {
}
My code. Maybe someone will be useful:
Custom textField cell in tableView
.m
#property (nonatomic, strong) UITextField *currentCellTextField;
CustomCell * cell = [tableView dequeueReusableCellWithIdentifier:CellIdentifier2];
if (cell == nil) {
NSArray * nib = [[NSBundle mainBundle] loadNibNamed:#"CustomCell" owner:self options:nil];
cell = (CustomCell *)[nib objectAtIndex:0];
cell.textfield.delegate = self;
}
- (void) textFieldDidBeginEditing:(UITextField *)textField
{
self.currentCellTextField = textField;
CGPoint pnt = [self.organisationTableView convertPoint:textField.bounds.origin fromView:textField];
NSIndexPath* path = [self.organisationTableView indexPathForRowAtPoint:pnt];
if (path.section >= 2) {
[UIView beginAnimations:nil context:NULL];
[UIView setAnimationDuration:0.3];
self.organisationTableView.contentInset = UIEdgeInsetsMake(0, 0, kOFFSET_FOR_KEYBOARD, 0);
CGPoint siize = self.organisationTableView.contentOffset;
siize.y =(pnt.y-170);
self.organisationTableView.contentOffset = CGPointMake(0, siize.y);
[UIView commitAnimations];
}
}
-(BOOL)textFieldShouldReturn:(UITextField *)textField
{
[textField resignFirstResponder];
CGPoint pnt = [self.organisationTableView convertPoint:textField.bounds.origin fromView:textField];
NSIndexPath* path = [self.organisationTableView indexPathForRowAtPoint:pnt];
if (path.section >= 2) {
[UIView beginAnimations:nil context:NULL];
[UIView setAnimationDuration:0.3];
self.organisationTableView.contentInset = UIEdgeInsetsZero;
self.organisationTableView.contentOffset = CGPointMake(0, self.organisationTableView.contentOffset.y);
[UIView commitAnimations];
}
return YES;
}
In my case my UITableview was inside another UIView and that UIvie was in the main UIScrollview. So I used more general solution for those kind of problems.
I simply found the Y coordinate of my cell in the specific UIScrollView and then scrolled to correct point:
-(void)textFieldDidBeginEditing:(UITextField *)textField{
float kbHeight = 216;//Hard Coded and will not support lanscape mode
UITableViewCell *cell = (UITableViewCell *)[textField superview];
float scrollToHeight = [self FindCordinate:cell];
[(UIScrollView *)self.view setContentOffset:CGPointMake(0, scrollToHeight - kbHeight + cell.frame.size.height) animated:YES];
}
-(float)FindCordinate:(UIView *)cell{
float Ycordinate = 0.0;
while ([cell superview] != self.view) {
Ycordinate += cell.frame.origin.y;
cell = [cell superview];
}
Ycordinate += cell.frame.origin.y;
return Ycordinate;
}
Another simple solution is adding an additional space for the footer of the last table section:
- (float)tableView:(UITableView *)tableView heightForFooterInSection:(NSInteger)section {
if (section == lastSection) {
return keyboard height;
}
return 0;
}
We can add our icon into this area as well. :)
You can try adding a UITableViewController to the UIViewController instead of just a table view. This way you can call UITableViewController's viewWillAppear and everything will appear to work.
Example:
- (void)viewWillAppear:(BOOL)animated {
[super viewWillAppear:animated];
[tableViewController viewWillAppear:animated];
}
I have add a little feature to #FunkyKat and #bmauter answers (great answer by the way, it should be the one accepted)
The regular Table View edge insets is preserved, before/after the keyboard apparition.
- (void)keyboardWillShow:(NSNotification *)sender
{
CGSize kbSize = [[[sender userInfo] objectForKey:UIKeyboardFrameEndUserInfoKey] CGRectValue].size;
NSTimeInterval duration = [[[sender userInfo] objectForKey:UIKeyboardAnimationDurationUserInfoKey] doubleValue];
CGFloat height = UIDeviceOrientationIsPortrait([[UIDevice currentDevice] orientation]) ? kbSize.width : kbSize.height;
[UIView animateWithDuration:duration animations:^{
UIEdgeInsets edgeInsets = self.tableView.contentInset;
edgeInsets.bottom += height;
self.tableView.contentInset = edgeInsets;
edgeInsets = self.tableView.scrollIndicatorInsets;
edgeInsets.bottom += height;
self.tableView.scrollIndicatorInsets = edgeInsets;
}];
}
- (void)keyboardWillHide:(NSNotification *)sender
{
CGSize kbSize = [[[sender userInfo] objectForKey:UIKeyboardFrameEndUserInfoKey] CGRectValue].size;
NSTimeInterval duration = [[[sender userInfo] objectForKey:UIKeyboardAnimationDurationUserInfoKey] doubleValue];
CGFloat height = UIDeviceOrientationIsPortrait([[UIDevice currentDevice] orientation]) ? kbSize.width : kbSize.height;
[UIView animateWithDuration:duration animations:^{
UIEdgeInsets edgeInsets = self.tableView.contentInset;
edgeInsets.bottom -= height;
self.tableView.contentInset = edgeInsets;
edgeInsets = self.tableView.scrollIndicatorInsets;
edgeInsets.bottom -= height;
self.tableView.scrollIndicatorInsets = edgeInsets;
}];
}

Resources