Getting multiple table view instances to match - user-interface

I'm trying to get the cells returned within my searchResultsTableView to look just like those in the "regular", non-search table view. Here's my regular view.
The first time you search, the results are styled exactly like the "regular" table view. However, once you you cancel the searchDisplayController and tap the Search button again, you'll get this.
It looks to me like the background isn't being set after the first time the search display controller is loaded.
I'm instantiating cells in tableView:cellForRowAtIndexPath: using UITableViewCell, not a custom subclass. Here is the remainder of the method:
PersonInfo *info = nil;
if (tableView == self.searchDisplayController.searchResultsTableView) {
info = [self.filteredPeopleList objectAtIndex:indexPath.row];
} else {
info = [self.peopleList objectAtIndex:indexPath.row];
}
cell.backgroundView = [[UIImageView alloc] initWithImage:[UIImage imageNamed:#"cellBk.png"]];
cell.detailTextLabel.textColor = [UIColor whiteColor];
cell.backgroundColor = [UIColor clearColor];
cell.imageView.image = info.image;
cell.textLabel.text = info.name;
cell.detailTextLabel.text = info.title;
return cell;
The tableView (the "regular" one) and searchResultsTableView is being set as follows inside viewDidLoad:
//Set the default tableView style
self.tableView.backgroundColor = [UIColor clearColor];
self.tableView.opaque = NO;
self.tableView.backgroundView = [[UIImageView alloc] initWithImage:[UIImage imageNamed:#"background.png"]];
[self.tableView setSeparatorStyle:UITableViewCellSeparatorStyleNone];
//Set the self.searchDisplayController background stuff
self.searchDisplayController.searchResultsTableView.backgroundColor = [UIColor clearColor];
self.searchDisplayController.searchResultsTableView.opaque = NO;
self.searchDisplayController.searchResultsTableView.backgroundView = [[UIImageView alloc] initWithImage:[UIImage imageNamed:#"background.png"]];
[self.searchDisplayController.searchResultsTableView setSeparatorStyle:UITableViewCellSeparatorStyleNone];
[self.tableView reloadData];

Moving the code to style the searchResultsTableView into searchDisplayController:willShowSearchResultsTableView:, a method of UISearchDisplayDelegate, takes care of this.

Related

Change tint of SFSymbol in UITableView Cell Accessory tvOS

I am adding an accessory view to a cell with:
UIImageSymbolConfiguration* configuration = [UIImageSymbolConfiguration configurationWithPointSize:28 weight:UIImageSymbolWeightRegular];
UIImageView* accessoryView = [[[UIImageView alloc] initWithImage:[UIImage systemImageNamed:#"globe" withConfiguration:configuration]] autorelease];
[accessoryView setImage:[imageView.image imageWithRenderingMode:UIImageRenderingModeAlwaysTemplate]];
[accessoryView setTintColor:[UIColor labelColor]];
[cell setAccessoryView: accessoryView];
This works, but how can I configure it so that when the cell is highlighted, the globe icon changes from the labelColor tint to black (so it matches the text color)?
I have also tried making a highlighted image but it does not have any effect:
UIImageSymbolConfiguration* configuration = [UIImageSymbolConfiguration configurationWithPointSize:28 weight:UIImageSymbolWeightRegular];
UIImageView* accessoryView = [[[UIImageView alloc] initWithImage:[UIImage systemImageNamed:#"globe" withConfiguration:configuration]] autorelease];
UIImage* normalImage = [accessoryView.image imageWithTintColor:[UIColor labelColor]];
UIImage* highlightImage = [accessoryView.image imageWithTintColor:[UIColor blackColor]];
[accessoryView setImage:normalImage];
[accessoryView setHighlightedImage:highlightImage];
[cell setAccessoryView:accessoryView];
Furthermore, the highlighted image never seems to be used at all:
UIImage* image = [[UIImage systemImageNamed:#"checkmark" withConfiguration:configuration] imageWithRenderingMode:UIImageRenderingModeAlwaysTemplate];
UIImage* highlightedImage = [[UIImage systemImageNamed:#"globe" withConfiguration:configuration] imageWithRenderingMode:UIImageRenderingModeAlwaysTemplate];
UIImageView* accessoryView = [[[UIImageView alloc] initWithImage:image highlightedImage:highlightedImage] autorelease];
[cell setAccessoryView:accessoryView];
In the above code, the highlighted image is never shown.
This seems to work:
-(void)tableView:(UITableView *)tableView didUpdateFocusInContext:(UITableViewFocusUpdateContext *)context withAnimationCoordinator:(UIFocusAnimationCoordinator *)coordinator
{
NSIndexPath* nextPath = [context nextFocusedIndexPath];
if (nextPath)
{
UITableViewCell* cell = [tableView cellForRowAtIndexPath:nextPath];
UIImageView* accessoryView = (UIImageView *)[cell accessoryView];
[accessoryView setTintColor:[UIColor blackColor]];
}
NSIndexPath* prevPath = [context previouslyFocusedIndexPath];
if (prevPath)
{
UITableViewCell* cell = [tableView cellForRowAtIndexPath:prevPath];
UIImageView* accessoryView = (UIImageView *)[cell accessoryView];
[accessoryView setTintColor:[UIColor labelColor]];
}
}

Activity Indicator will not go away

I am using the following code to show an Activity Indicator while some data is loading. The problem is that when I try to hide it again. The Activity Indicator stays put. The screen lightens a bit but that is it.
To show it:
self.overlayView = [[UIView alloc] initWithFrame:[UIScreen mainScreen].bounds];
self.overlayView.backgroundColor = [UIColor colorWithRed:0 green:0 blue:0 alpha:0.3];
self.activityIndicator = [[UIActivityIndicatorView alloc] initWithActivityIndicatorStyle:UIActivityIndicatorViewStyleWhiteLarge];
self.activityIndicator.center = self.overlayView.center;
[self.overlayView addSubview:self.activityIndicator];
[self.activityIndicator startAnimating];
[self.tableView addSubview:self.overlayView];
To hide it:
[self.activityIndicator stopAnimating];
[self.overlayView removeFromSuperview];
Try to add your overlayView to the superview of your tableView :
[self.view.superview addSubview:self.overlayView];
I figured it out with a combination of stackoverflow questions. Here is my code to show the UIActivityIndicatorView
-(void)loadView {
[super loadView];
self.overlayView = [[UIView alloc] initWithFrame:[UIScreen mainScreen].bounds];
self.overlayView.backgroundColor = [UIColor colorWithRed:0 green:0 blue:0 alpha:0.3];
self.activityIndicator = [[UIActivityIndicatorView alloc] initWithActivityIndicatorStyle:UIActivityIndicatorViewStyleWhiteLarge];
self.activityIndicator.center = self.overlayView.center;
[self.overlayView addSubview:self.activityIndicator];
[self.tableView addSubview:self.overlayView];
[self.activityIndicator startAnimating];
}
Here is the code to hide it. It looks like putting the code in the loadView event made all the difference.
[overlayView removeFromSuperview];

UIPickerController - want to show specific selection upon loading

I have a custom UIPickerView that is embedded into an UIActionsheet that comes up half the screen when called. Works great. The problem is that I want to have the barrelPicker be showing the 'most probable' results as the selection when it first comes up (after all the data has been loaded into it).
Prior to having the custom picker embedded in the action sheet, I had it in a UIViewController and was just calling "showProbableResults" (a custom method of mine) in the viewDidLoad method of the ViewController, because I knew at that point, the UIPickerView would be loaded up and ready to go. Is there an equivalent place for me to call this method now or do I need to rethink my whole design? Essentially, what I need is a place to call this after the UIPickerView has been loaded.
- (void)startWithDelegate:(UIViewController <ImageProcessingDelegate> *)sender
{
self.delegate = sender;
self.showFirstBottle = YES;
[self start];
}
- (void) start {
self.actionSheet = [[UIActionSheet alloc] initWithTitle:#"Choose Something"
delegate:self
cancelButtonTitle:nil
destructiveButtonTitle:nil
otherButtonTitles:nil];
[self.actionSheet setActionSheetStyle:UIActionSheetStyleBlackTranslucent];
CGRect pickerFrame = CGRectMake(0, 40, 0, 0);
NSLog(#"1.) About to alloc the picker");
self.vintagePicker = [[UIPickerView alloc] initWithFrame:pickerFrame];
self.vintagePicker.showsSelectionIndicator = YES;
self.vintagePicker.dataSource = self;
self.vintagePicker.delegate = self;
[self.actionSheet addSubview:self.vintagePicker];
[self.vintagePicker release];
UISegmentedControl *nextButton = [[UISegmentedControl alloc] initWithItems:[NSArray arrayWithObject:#"Next"]];
nextButton.momentary = YES;
nextButton.frame = CGRectMake(260, 7.0f, 50.0f, 30.0f);
nextButton.segmentedControlStyle = UISegmentedControlStyleBar;
nextButton.tintColor = [UIColor blackColor];
[nextButton addTarget:self action:#selector(show:) forControlEvents:UIControlEventValueChanged];
[self.actionSheet addSubview:nextButton];
[nextButton release];
UISegmentedControl *backButton = [[UISegmentedControl alloc] initWithItems:[NSArray arrayWithObject:#"Back"]];
backButton.momentary = YES;
backButton.frame = CGRectMake(10, 7.0f, 50.0f, 30.0f);
backButton.segmentedControlStyle = UISegmentedControlStyleBar;
backButton.tintColor = [UIColor blackColor];
[backButton addTarget:self action:#selector(cancel:) forControlEvents:UIControlEventValueChanged];
[self.actionSheet addSubview:backButton];
[backButton release];
[self.actionSheet showInView:_delegate.parentViewController.tabBarController.view]; // show from our table view (pops up in the middle of the table)
[self.actionSheet setBounds:CGRectMake(0, 0, 320, 485)];
}
One option is to create a reusable picker view, as shown here, and then call the #optional
-(void)setInitialPickerValueToRow:(int)i inComponent:(int)j animated:(BOOL)k{
[pickerView selectRow:i inComponent:j animated:k];
}
from any view controller or NSObject (such as your UIActionSheetDelegate).
Your other option is to set a standard pre-chosen selection, as follows:
self.vintagePicker = [[UIPickerView alloc] initWithFrame:pickerFrame];
self.vintagePicker.showsSelectionIndicator = YES;
self.vintagePicker.dataSource = self;
self.vintagePicker.delegate = self;
[self.actionSheet addSubview:self.vintagePicker];
[self.vintagePicker selectRow:0 inComponent:0 animated:NO];
You could also have different variables that you set, and have selectRow:inComponent:animated: access those, instead of being preset.
[self.vintagePicker selectRow:myRow inComponent:0 animated:NO];
Hope this helps!

How can we put two line in UIBarButtonItem in Navigation Bar

"Now Playing" is in One line in UIBarButtonItem. I have to put it in two lines, like "Now" is ay top and "Playing" is at bottom.I have written the following line of code:-
UIBarButtonItem *flipButton = [[UIBarButtonItem alloc]
initWithTitle:#"Now Playing"
style:UIBarButtonItemStyleBordered
target:self
action:#selector(flipView)];
self.navigationItem.rightBarButtonItem = flipButton;
So i want to pu line break in between "Now Playing". So please help me out.
Yes you can. It is fairly simple to do. Create a multiline button and use that. The "trick" is to set the titleLabel numberOfLines property so that it likes multilines.
UIButton* button = [UIButton buttonWithType:UIButtonTypeCustom];
button.titleLabel.numberOfLines = 0;
[button setTitle:NSLocalizedString(#"Now\nPlaying", nil) forState:UIControlStateNormal];
[button sizeToFit];
self.navigationItem.rightBarButtonItem = [[UIBarButtonItem alloc] initWithCustomView:button];
When you specify a button type of custom it expects you to configure everything... selected state, etc. which is not shown here to keep the answer focused to the problem at hand.
- (void)createCustomRightBarButton_
{
UILabel * addCustomLabel = [[[UILabel alloc] initWithFrame:CGRectMake(0, 0, 64, 25)] autorelease];
addCustomLabel.text =#"Now\nPlaying";
addCustomLabel.textColor = [UIColor whiteColor];
addCustomLabel.font = [UIFont boldSystemFontOfSize:11];
addCustomLabel.numberOfLines = 2;
addCustomLabel.backgroundColor = [UIColor clearColor];
addCustomLabel.textAlignment = UITextAlignmentCenter;
CGSize size = addCustomLabel.bounds.size;
UIGraphicsBeginImageContext(size);
CGContextRef context = UIGraphicsGetCurrentContext();
[addCustomLabel.layer renderInContext: context];
CGImageRef imageRef = CGBitmapContextCreateImage(context);
UIImage * img = [UIImage imageWithCGImage: imageRef];
CGImageRelease(imageRef);
CGContextRelease(context);
self.navigationItem.rightBarButtonItem = [[[UIBarButtonItem alloc] initWithImage:img
style:UIBarButtonItemStyleBordered
target:self
action:#selector(flipView)]
autorelease];
}
You can host a UIButton as customView inside your bar button (either set the bar button item customView or you can drag one directly on top of your UIBarButtonItem), hook it up as an outlet, then do;
-(void) viewDidLoad
{
//...
self.customButton.titleLabel.numberOfLines = 2;
self.customButton.suggestionsButton.titleLabel.lineBreakMode = UILineBreakModeWordWrap;
self.customButton.suggestionsButton.titleLabel.textAlignment = UITextAlignmentCenter;
}
which in my case becomes
I create 2 PNG images by myself, and it looks good.
UIImage *img = [UIImage imageNamed:#"nowplaying.png"];
UIBarButtonItem *nowPlayingButtonItem = [[[UIBarButtonItem alloc] initWithImage:img style:UIBarButtonItemStyleBordered target:delegate action:#selector(presentNowPlayingMovie)] autorelease];

xcode iphone - jerky scroll UITableView CellForRowAtIndexPath

Almost sorted with my 1st app, just a simple news app but when I load it onto my iPhone the scroll seems jerky can someone have a look at my function and see if i'm doing something wrong.
I need the image on the right hand side thats why i'm using custom cells.
Thanks
For any help
#define DATELABEL_TAG 1 #define MAINLABEL_TAG 2 #define PHOTO_TAG 3
- (UITableViewCell *)tableView:(UITableView *)tableView cellForRowAtIndexPath:(NSIndexPath *)indexPath
{
static NSString *MainNewsCellIdentifier = #"MainNewsCellIdentifier";
UILabel *mainLabel, *dateLabel;
UIImageView *photo;
UITableViewCell *cell = [tableView dequeueReusableCellWithIdentifier: MainNewsCellIdentifier];
if (cell == nil)
{
cell = [[[UITableViewCell alloc] initWithStyle:UITableViewCellStyleSubtitle reuseIdentifier: MainNewsCellIdentifier] autorelease];
cell.accessoryType = UITableViewCellAccessoryDetailDisclosureButton;
dateLabel = [[[UILabel alloc] initWithFrame:CGRectMake(15.0,15.0,170.0,15.0)] autorelease];
dateLabel.tag = DATELABEL_TAG;
dateLabel.font = [UIFont systemFontOfSize:10.0];
dateLabel.textAlignment = UITextAlignmentLeft;
dateLabel.textColor = [UIColor darkGrayColor];
dateLabel.autoresizingMask = UIViewAutoresizingFlexibleRightMargin; //| UIViewAutoresizingFlexibleHeight;
[cell.contentView addSubview:dateLabel];
mainLabel = [[[UILabel alloc] initWithFrame:CGRectMake(15.0,28.0,170.0,60.0)] autorelease];
mainLabel.tag = MAINLABEL_TAG;
mainLabel.font = [UIFont boldSystemFontOfSize:14.0];
mainLabel.textColor = [UIColor blackColor];
mainLabel.autoresizingMask = UIViewAutoresizingFlexibleWidth | UIViewAutoresizingFlexibleRightMargin;
mainLabel.numberOfLines = 0;
//mainLabel.backgroundColor = [UIColor greenColor];
[cell.contentView addSubview:mainLabel];
photo = [[[UIImageView alloc] initWithFrame:CGRectMake(190.0,15.0,85.0,85.0)] autorelease];
photo.tag = PHOTO_TAG;
photo.contentMode = UIViewContentModeScaleAspectFit;//UIViewContentModeScaleAspectFit; //
[cell.contentView addSubview:photo];
}
else {
dateLabel = (UILabel *)[cell.contentView viewWithTag:DATELABEL_TAG];
mainLabel = (UILabel *)[cell.contentView viewWithTag:MAINLABEL_TAG];
photo = (UIImageView *)[cell.contentView viewWithTag:PHOTO_TAG];
}
NSUInteger row = [indexPath row];
NSDictionary *stream = (NSDictionary *) [dataList objectAtIndex:row];
NSString *title = [stream valueForKey:#"title"];
NSString *titleString = #"";
if( ! [title isKindOfClass:[NSString class]] )
{
titleString = #"";
}
else
{
titleString = title;
}
CGSize maximumSize = CGSizeMake(180, 9999);
UIFont *dateFont = [UIFont fontWithName:#"Helvetica" size:14];
CGSize dateStringSize = [titleString sizeWithFont:dateFont
constrainedToSize:maximumSize
lineBreakMode:mainLabel.lineBreakMode];
CGRect dateFrame = CGRectMake(15.0, 28.0, 170.0, dateStringSize.height);
mainLabel.frame = dateFrame;
mainLabel.text = titleString;
dateLabel.text = [stream valueForKey:#"created"];
NSString *i = [NSString stringWithFormat:#"http://www.website.co.uk/images/%#", [stream valueForKey:#"image"]];
NSData *imageURL = [[NSData alloc] initWithContentsOfURL:[NSURL URLWithString:i]];
UIImage *newsImage = [[UIImage alloc] initWithData:imageURL];
photo.image = newsImage;
[imageURL release];
[newsImage release];
return cell;
}
The problem is this:
NSString *i = [NSString stringWithFormat:#"http://www.website.co.uk/images/%#", [stream valueForKey:#"image"]];
NSData *imageURL = [[NSData alloc] initWithContentsOfURL:[NSURL URLWithString:i]];
UIImage *newsImage = [[UIImage alloc] initWithData:imageURL];
You effectively say here, that as soon as the cell needs to be displayed, the image must be fetched and presented. This will cost some time - too much for a good user experience.
You should fetch the images before or while you present the table view, and cache them, e.g. in an array. Or you must handle things asynchronously, meaning that you do the loading in the background, and not wait with return cell; until the image is actually downloaded. This will be a little harder to get right.
Even if you asynchronously download images, you'll still have a jerky scroll.
Why? It's lazy image decompression. ios performs decompression at the moment it will be displayed on the screen. You have to manually decompress the images in a background thread.
Decompression does not merely mean instantiating a UIImage object. It can be somewhat complicated. The best solution, is to download SDWebImage and use the image decompressor that's included. SDWebImage will asynchronously download and perform decompression for you.
To read more about the issue see: http://www.cocoanetics.com/2011/10/avoiding-image-decompression-sickness/

Resources