I would like to imitate the grouped table of the standard Contacts app (left). Each section has gray line dividers above and below. In my grouped table (right), there is no line above each section. And even stranger, the middle section has no lines at all.
#import "GroupViewController.h"
#import "UserCollectionViewCell.h"
#import "UIView+position.h"
#import "UIColor+style.h"
#import "UserPublicViewController.h"
#import "RecipientsGroupsModel.h"
static NSString* AVATAR_CELL_ID = #"groupUserCollectionUserView";
static const CGFloat AVATAR_ITEM_SPACING = 16.0;
static const CGFloat AVATAR_LINE_SPACING = 9.0;
static const CGFloat AVATAR_MARGIN = 15.5;
static const CGFloat AVATAR_CELL_WIDTH = 45.0;
static const CGFloat AVATAR_CELL_HEIGHT = 58.0;
typedef enum {
GroupViewControllerTableSectionTitle,
GroupViewControllerTableSectionUsers,
GroupViewControllerTableSectionDelete
} GroupViewControllerTableSection;
#interface GroupViewController ()
#property(nonatomic, strong) Group* group;
#property(nonatomic, strong) UICollectionView* avatarCollectionView;
#property(nonatomic, readonly) CGFloat usersHeight;
- (void)didLongTapAvatars:(UILongPressGestureRecognizer*)gesture;
#end
#implementation GroupViewController
#pragma mark UIViewController
- (NSString*)title
{
return #"Group";
}
- (void)loadView
{
[super loadView];
self.view.backgroundColor = [UIColor backgroundColor];
}
- (void)viewDidLoad
{
[super viewDidLoad];
self.navigationItem.rightBarButtonItem = self.editButtonItem;
}
- (void)setEditing:(BOOL)editing animated:(BOOL)animated
{
[super setEditing:editing animated:animated];
[self.tableView reloadData];
[self.avatarCollectionView reloadData];
}
#pragma mark GroupViewController ()
- (void)didLongTapAvatars:(UILongPressGestureRecognizer *)gesture
{
if (gesture.state == UIGestureRecognizerStateBegan) {
[self setEditing:!self.isEditing animated:YES];
}
}
- (CGFloat)usersHeight
{
return ceilf(
self.group.users.count
/ floorf(
(
self.view.width
- 2 * AVATAR_MARGIN
+ AVATAR_ITEM_SPACING
)
/ (
AVATAR_ITEM_SPACING
+ AVATAR_CELL_WIDTH
)
)
)
* (AVATAR_CELL_HEIGHT + AVATAR_LINE_SPACING)
+ AVATAR_LINE_SPACING;
}
#pragma mark GroupViewController
- (instancetype)initWithGroup:(Group *)group
{
if (self = [super init]) {
self.group = group;
}
return self;
}
#pragma mark UITableViewDelegate
- (CGFloat)tableView:(UITableView *)tableView heightForRowAtIndexPath:(NSIndexPath *)indexPath
{
switch (indexPath.section) {
case GroupViewControllerTableSectionTitle:
case GroupViewControllerTableSectionDelete:
return 44.0f;
break;
case GroupViewControllerTableSectionUsers:
return self.usersHeight;
break;
default:
return 0.0f;
}
}
- (CGFloat)tableView:(UITableView *)tableView heightForHeaderInSection:(NSInteger)section
{
return 22.0f;
}
- (CGFloat)tableView:(UITableView *)tableView heightForFooterInSection:(NSInteger)section
{
switch (section) {
case GroupViewControllerTableSectionDelete:
return 22.0f;
break;
default:
return 0.0f;
}
}
- (UIView*)tableView:(UITableView *)tableView viewForHeaderInSection:(NSInteger)section
{
// iOS 7 applies a transclucent view if you don't return your own view
return [[UIView alloc] init];
}
- (UIView*)tableView:(UITableView *)tableView viewForFooterInSection:(NSInteger)section
{
return [[UIView alloc] init];
}
#pragma mark UITableViewDataSource
- (NSInteger)numberOfSectionsInTableView:(UITableView *)tableView
{
if (self.isEditing) {
return GroupViewControllerTableSectionDelete + 1;
} else {
return GroupViewControllerTableSectionUsers + 1;
}
}
- (NSInteger)tableView:(UITableView *)tableView numberOfRowsInSection:(NSInteger)section
{
return 1;
}
- (UITableViewCell*)tableView:(UITableView *)tableView cellForRowAtIndexPath:(NSIndexPath *)indexPath
{
NSString* identifier = [NSNumber numberWithInteger:indexPath.section].stringValue;
UITableViewCell* cell = [tableView dequeueReusableCellWithIdentifier:identifier];
if (cell == nil) {
cell = [[UITableViewCell alloc] initWithStyle:UITableViewCellStyleDefault reuseIdentifier:identifier];
switch (indexPath.section) {
case GroupViewControllerTableSectionTitle:
cell.textLabel.text = self.group.title;
break;
case GroupViewControllerTableSectionUsers: {
if (self.avatarCollectionView == nil) {
UICollectionViewFlowLayout* layout = [[UICollectionViewFlowLayout alloc] init];
layout.scrollDirection = UICollectionViewScrollDirectionVertical;
layout.sectionInset = UIEdgeInsetsMake(
AVATAR_LINE_SPACING,
AVATAR_MARGIN,
AVATAR_LINE_SPACING,
AVATAR_MARGIN
);
layout.itemSize = CGSizeMake(AVATAR_CELL_WIDTH, AVATAR_CELL_HEIGHT);
layout.minimumInteritemSpacing = AVATAR_ITEM_SPACING;
layout.minimumLineSpacing = AVATAR_LINE_SPACING;
self.avatarCollectionView = [[UICollectionView alloc]
initWithFrame:CGRectMake(
0.0,
0.0,
self.view.width,
self.usersHeight
)
collectionViewLayout:layout
];
self.avatarCollectionView.backgroundColor = [UIColor clearColor];
self.avatarCollectionView.dataSource = self;
self.avatarCollectionView.delegate = self;
[self.avatarCollectionView registerClass:[UserCollectionViewCell class] forCellWithReuseIdentifier:AVATAR_CELL_ID];
[self.avatarCollectionView addGestureRecognizer:[[UILongPressGestureRecognizer alloc] initWithTarget:self action:#selector(didLongTapAvatars:)]];
}
[cell.contentView addSubview:self.avatarCollectionView];
break;
}
case GroupViewControllerTableSectionDelete:
cell.textLabel.text = #"Delete Group";
cell.textLabel.textColor = [UIColor redColor];
break;
}
}
return cell;
}
- (BOOL)tableView:(UITableView *)tableView canEditRowAtIndexPath:(NSIndexPath *)indexPath
{
return NO;
}
#pragma mark UICollectionViewDataSource
- (UICollectionViewCell*)collectionView:(UICollectionView *)collectionView cellForItemAtIndexPath:(NSIndexPath *)indexPath
{
UserCollectionViewCell* cell;
cell = [self.avatarCollectionView dequeueReusableCellWithReuseIdentifier:AVATAR_CELL_ID forIndexPath:indexPath];
cell.user = [self.group.users objectAtIndex:indexPath.row];
cell.isEditing = self.isEditing;
return cell;
}
- (NSInteger)collectionView:(UICollectionView *)collectionView numberOfItemsInSection:(NSInteger)section
{
return self.group.users.count;
}
- (NSInteger)numberOfSectionsInCollectionView:(UICollectionView *)collectionView
{
return 1;
}
#pragma mark UICollectionViewDelegate
- (void)collectionView:(UICollectionView *)collectionView didSelectItemAtIndexPath:(NSIndexPath *)indexPath
{
User* user = [self.group.users objectAtIndex:indexPath.row];
if (self.isEditing) {
if (self.group.users.count <= 1) {
[RecipientsGroupsModel removeGroup:self.group];
[self.navigationController popViewControllerAnimated:YES];
} else {
[self.group.users removeObject:user];
[RecipientsGroupsModel updateGroup:self.group];
[self.avatarCollectionView deleteItemsAtIndexPaths:#[indexPath]];
}
} else {
[self.navigationController pushViewController:[[UserPublicViewController alloc] initWithUser:user] animated:YES];
}
}
#end
You can use the UITableViewDelegate methods:
- (CGFloat)tableView:(UITableView *)tableView heightForHeaderInSection:(NSInteger)section;
- (CGFloat)tableView:(UITableView *)tableView heightForFooterInSection:(NSInteger)section;
where you can specify any height you want for header and footer of any section. Return 0 in case you do not need a header or footer.
Then use the other two methods:
- (UIView *)tableView:(UITableView *)tableView viewForHeaderInSection:(NSInteger)section;
- (UIView *)tableView:(UITableView *)tableView viewForFooterInSection:(NSInteger)section;
Inside each of them, you can write the custom code to make them look as you want:
UIView *view = [[UIView alloc] initWithFrame:CGRectMake(0, 0, 320, 40)];
view.backgroundColor = [UIColor grayColor];
// ...
// Other customizations, like adding the gray line, etc.
// ...
return view;
Related
In my project I need to implement the UITableview with some of the tableView cells are expandable and some of them are independent. If it is expandable cell need to indicate the '+' symbol.enter image description here. Can any one please help me out
I have created a small demo,
https://github.com/haripalwagh/ExpandableTableviewCell
Screenshot 1 : Before expanding a cell
Screenshot 2 : After expanding a cell
#interface ViewController ()
<UITableViewDataSource,
UITableViewDelegate>
{
UITableView *tblView;
NSArray *cell0SubMenuItemsArray;
BOOL isSection0Cell0Expanded;
}
#end
#implementation ViewController
# pragma mark - View Life Cycle
- (void)viewDidLoad
{
[super viewDidLoad];
tblView = [[UITableView alloc] initWithFrame:CGRectZero style:UITableViewStyleGrouped];
tblView.backgroundColor = [UIColor clearColor];
tblView.delegate = self;
tblView.dataSource = self;
tblView.allowsSelection = YES;
tblView.scrollEnabled = YES;
tblView.alwaysBounceVertical = YES;
[self.view addSubview:tblView];
cell0SubMenuItemsArray = #[#"First Static Menu Item", #"Second Static Menu Item", #"Third Static Menu Item"];
}
- (void)viewDidAppear:(BOOL)animated
{
[super viewDidAppear:animated];
[self.view setNeedsLayout];
}
- (void)viewDidLayoutSubviews
{
[super viewDidLayoutSubviews];
[self updateViewDimensions];
}
- (void)updateViewDimensions
{
tblView.frame = CGRectMake(0, 40, 320, 550);
}
- (void)didReceiveMemoryWarning
{
[super didReceiveMemoryWarning];
}
# pragma mark - UITableView Delegate and Datasource
- (NSInteger)tableView:(UITableView *)tableView numberOfRowsInSection:(NSInteger)section
{
if (section == 0)
{
int cellCount = 2; // Default count - if not a single cell is expanded
if (isSection0Cell0Expanded)
{
cellCount += [cell0SubMenuItemsArray count];
}
return cellCount;
}
return 0;
}
- (UITableViewCell *)tableView:(UITableView *)tableView cellForRowAtIndexPath:(NSIndexPath *)indexPath
{
static NSString *strCellId = #"CellId";
UITableViewCell *cell = [[UITableViewCell alloc] initWithStyle:UITableViewCellStyleSubtitle reuseIdentifier:strCellId];
cell.selectionStyle = UITableViewCellSelectionStyleNone;
if (indexPath.section == 0)
{
if (indexPath.row == 0)
{
cell.textLabel.text = #"Expandable Cell";
UIImageView *accessoryImageView = [[UIImageView alloc] initWithFrame:CGRectMake(0, 0, 30, 30)];
if (isSection0Cell0Expanded) // Set accessory view according to cell state - EXPANDED / NOT EXPANDED
{
accessoryImageView.image = [UIImage imageNamed:#"Minus.png"];
cell.detailTextLabel.text = #"Status : Expanded";
}
else
{
accessoryImageView.image = [UIImage imageNamed:#"Plus.png"];
cell.detailTextLabel.text = #"Status : Not Expanded";
}
cell.accessoryView = accessoryImageView;
}
else
{
if (isSection0Cell0Expanded && [cell0SubMenuItemsArray count] >= indexPath.row) // Check Expanded status and do the necessary changes
{
cell.textLabel.text = [NSString stringWithFormat:#"%#", [cell0SubMenuItemsArray objectAtIndex:indexPath.row - 1]];
}
else
{
cell.textLabel.text = #"Static Cell";
}
}
}
return cell;
}
- (NSInteger)numberOfSectionsInTableView:(UITableView *)tableView
{
return 1;
}
- (void)tableView:(UITableView *)tableView didSelectRowAtIndexPath:(NSIndexPath *)indexPath
{
if (indexPath.row == 0)
{
// Change status of a cell reload table
isSection0Cell0Expanded = !isSection0Cell0Expanded;
[tblView reloadData];
}
}
You have to manage like this for every expandable cell.
Hope this will help you..
Try this control: https://github.com/jonasman/JNExpandableTableView
It supports what you say. Tapping on a cell expands it.
I create one UICollectionView sticky header section with this : sticky header section but when my UICollectionViewCell is 0 number header section in hide like this picture :
in my picture show me one header section (index:2) and other header section is hidden. please guide me !!! I want other show like index 2.
this is my code:
- (void)viewDidLoad {
[super viewDidLoad];
self.view.backgroundColor = [UIColor whiteColor];
Flow *layout=[[Flow alloc] init];
//layout.sectionInset = UIEdgeInsetsMake(20,0,40,0);
//layout.itemSize = CGSizeMake(100,100);
_collect=[[UICollectionView alloc] initWithFrame:self.view.frame collectionViewLayout:layout];
_collect.backgroundColor = [UIColor clearColor];
[_collect setDataSource:self];
[_collect setDelegate:self];
[_collect registerClass:[HeaderView class] forSupplementaryViewOfKind:UICollectionElementKindSectionHeader withReuseIdentifier:#"HeaderView"];
[_collect registerClass:[CollectionViewCell class] forCellWithReuseIdentifier:#"cellIdentifier"];
[self.view addSubview:_collect];
//NSLog(#"%#",self.array);
}
- (NSMutableArray*)array {
if (!_array) {
_array = [NSMutableArray array];
for (NSInteger i=0; i<SectionNum; i++) {
//NSMutableArray *inner = [NSMutableArray arrayWithObject:#"0"];
[_array addObject:#"0"];
}
}
return _array;
}
- (void)didReceiveMemoryWarning {
[super didReceiveMemoryWarning];
// Dispose of any resources that can be recreated.
}
- (NSInteger)numberOfSectionsInCollectionView:(UICollectionView *)collectionView {
return SectionNum;
}
- (NSInteger)collectionView:(UICollectionView *)collectionView numberOfItemsInSection:(NSInteger)section{
if (section == 2) {
return 10;
} else
return 0;
}
- (UICollectionViewCell *)collectionView:(UICollectionView *)collectionView cellForItemAtIndexPath:(NSIndexPath *)indexPath{
static NSString *identifier = #"cellIdentifier";
CollectionViewCell *cell = [collectionView dequeueReusableCellWithReuseIdentifier:identifier forIndexPath:indexPath];
return cell;
}
- (UICollectionReusableView *)collectionView:(UICollectionView *)collectionView viewForSupplementaryElementOfKind:(NSString *)kind atIndexPath:(NSIndexPath *)indexPath
{
UICollectionReusableView *reusableview = nil;
if (kind == UICollectionElementKindSectionHeader) {
HeaderView *header = [_collect dequeueReusableSupplementaryViewOfKind:UICollectionElementKindSectionHeader withReuseIdentifier:#"HeaderView" forIndexPath:indexPath];
header.backgroundColor = [UIColor colorWithWhite:0.75 alpha:.9];
header.titleLabel.font = [UIFont systemFontOfSize:24];
header.titleLabel.textAlignment = NSTextAlignmentCenter;
header.titleLabel.text = [NSString stringWithFormat:#"%ld",indexPath.section];
reusableview = header;
}
if (kind == UICollectionElementKindSectionFooter) {
UICollectionReusableView *footerview = [collectionView dequeueReusableSupplementaryViewOfKind:UICollectionElementKindSectionFooter withReuseIdentifier:#"FooterView" forIndexPath:indexPath];
reusableview = footerview;
}
return reusableview;
}
- (CGSize)collectionView:(UICollectionView *)collectionView layout:(UICollectionViewLayout*)collectionViewLayout sizeForItemAtIndexPath:(NSIndexPath *)indexPath {
return CGSizeMake(100,100);
}
- (CGSize)collectionView:(UICollectionView *)collectionView layout:(UICollectionViewLayout*)collectionViewLayout referenceSizeForHeaderInSection:(NSInteger)section {
CGSize headerSize = CGSizeMake(320, 50);
return headerSize;
}
I am getting an error which I don't understand because I have declared the property/ies. Have commented out the error in the AllListViewController.m file in the cellForRowAtIndexPath: method.
Here are the files:
Checklist.h
#import <Foundation/Foundation.h>
#interface Checklist : NSObject <NSCoding>
#property (nonatomic, copy) NSString *name;
#property (nonatomic, strong) NSMutableArray *items;
#property (nonatomic, copy) NSString *iconName;
-(int)countUncheckedItems;
#end
Checklist.m
#import "Checklist.h"
#import "ChecklistItem.h"
#implementation Checklist
-(id)initWithCoder:(NSCoder *)aDecoder
{
if ((self = [super init])) {
self.name = [aDecoder decodeObjectForKey:#"Name"];
self.items = [aDecoder decodeObjectForKey:#"Items"];
self.iconName = [aDecoder decodeObjectForKey:#"IconName"];
}
return self;
}
-(void)encodeWithCoder:(NSCoder *)aCoder
{
[aCoder encodeObject:self.name forKey:#"Name"];
[aCoder encodeObject:self.items forKey:#"Items"];
[aCoder encodeObject:self.iconName forKey:#"IconName"];
}
-(id)init
{
if ((self = [super init])) {
self.items = [[NSMutableArray alloc] initWithCapacity:20];
self.iconName = #"Appointments";
}
return self;
}
-(int)countUncheckedItems
{
int count = 0;
for (ChecklistItem *item in self.items) {
if (!item.checked) {
count += 1;
}
}
return count;
}
-(NSComparisonResult)compare:(Checklist *)otherChecklist
{
return [self.name localizedStandardCompare:otherChecklist.name];
}
#end
AllListsViewController.h
#import <UIKit/UIKit.h>
#import "ListDetailViewController.h"
#class DataModel;
#interface AllListsViewController : UITableViewController <ListDetailViewControllerDelegate, UINavigationControllerDelegate>
#property (nonatomic, strong) DataModel *dataModel;
#end
AllListsViewController.m
#import "AllListsViewController.h"
#import "Checklist.h"
#import "ChecklistViewController.h"
#import "ChecklistItem.h"
#import "DataModel.h"
#interface AllListsViewController ()
#end
#implementation AllListsViewController
- (id)initWithStyle:(UITableViewStyle)style
{
self = [super initWithStyle:style];
if (self) {
// Custom initialization
}
return self;
}
- (void)viewDidLoad
{
[super viewDidLoad];
// Uncomment the following line to preserve selection between presentations.
// self.clearsSelectionOnViewWillAppear = NO;
// Uncomment the following line to display an Edit button in the navigation bar for this view controller.
// self.navigationItem.rightBarButtonItem = self.editButtonItem;
}
- (void)didReceiveMemoryWarning
{
[super didReceiveMemoryWarning];
// Dispose of any resources that can be recreated.
}
-(void)tableView:(UITableView *)tableView didSelectRowAtIndexPath:(NSIndexPath *)indexPath
{
[self.dataModel setIndexOfSelectedChecklist:indexPath.row];
Checklist *checklist = self.dataModel.lists[indexPath.row];
[self performSegueWithIdentifier:#"ShowChecklist" sender:checklist];
}
-(void)prepareForSegue:(UIStoryboardSegue *)segue sender:(id)sender
{
if ([segue.identifier isEqualToString:#"ShowChecklist"]) {
ChecklistViewController *controller = segue.destinationViewController;
controller.checklist = sender;
}
else if ([segue.identifier isEqualToString:#"AddChecklist"]) {
UINavigationController *navigationController = segue.destinationViewController;
ListDetailViewController *controller = (ListDetailViewController *)navigationController.topViewController;
controller.delegate = self;
controller.checklistToEdit = nil;
}
}
-(void)tableView:(UITableView *)tableView accessoryButtonTappedForRowWithIndexPath:(NSIndexPath *)indexPath
{
UINavigationController *navigationController = [self.storyboard instantiateViewControllerWithIdentifier:#"ListNavigationController"];
ListDetailViewController *controller = (ListDetailViewController *)navigationController.topViewController;
controller.delegate = self;
Checklist *checklist = self.dataModel.lists[indexPath.row];
controller.checklistToEdit = checklist;
[self presentViewController:navigationController animated:YES completion:nil];
}
#pragma mark - Table view data source
- (NSInteger)tableView:(UITableView *)tableView numberOfRowsInSection:(NSInteger)section
{
// Return the number of rows in the section.
return [self.dataModel.lists count];
}
-(void)tableView:(UITableView *)tableView commitEditingStyle:(UITableViewCellEditingStyle)editingStyle forRowAtIndexPath:(NSIndexPath *)indexPath
{
[self.dataModel.lists removeObjectAtIndex:indexPath.row];
NSArray *indexPaths = #[indexPath];
[tableView deleteRowsAtIndexPaths:indexPaths withRowAnimation:UITableViewRowAnimationAutomatic];
}
- (UITableViewCell *)tableView:(UITableView *)tableView cellForRowAtIndexPath:(NSIndexPath *)indexPath
{
static NSString *CellIdentifier = #"Cell";
UITableViewCell *cell = [tableView dequeueReusableCellWithIdentifier:CellIdentifier];
if (cell == nil) {
cell = [[UITableViewCell alloc]
initWithStyle:UITableViewCellStyleSubtitle
reuseIdentifier:CellIdentifier];
cell.imageView.image = [UIImage imageNamed:Checklist.iconName]; /* Use of undeclared identifier; did you mean 'Checklist'? or Property 'iconName' not found on object of type 'Checklist'*/
return cell;
}
Checklist *checklist = self.dataModel.lists[indexPath.row];
cell.textLabel.text = checklist.name;
cell.accessoryType = UITableViewCellAccessoryDetailDisclosureButton;
cell.detailTextLabel.text = [NSString stringWithFormat:#"%d Remaining", [checklist countUncheckedItems]];
int count = [checklist countUncheckedItems];
if ([checklist.items count] == 0) {
cell.detailTextLabel.text = #"(No Items)";
} else if (count == 0) {
cell.detailTextLabel.text = #"All Done";
} else {
cell.detailTextLabel.text = [NSString stringWithFormat:#"%d Remaining", count];
}
return cell;
}
/*
// Override to support conditional editing of the table view.
- (BOOL)tableView:(UITableView *)tableView canEditRowAtIndexPath:(NSIndexPath *)indexPath
{
// Return NO if you do not want the specified item to be editable.
return YES;
}
*/
/*
// Override to support editing the table view.
- (void)tableView:(UITableView *)tableView commitEditingStyle:(UITableViewCellEditingStyle)editingStyle forRowAtIndexPath:(NSIndexPath *)indexPath
{
if (editingStyle == UITableViewCellEditingStyleDelete) {
// Delete the row from the data source
[tableView deleteRowsAtIndexPaths:#[indexPath] withRowAnimation:UITableViewRowAnimationFade];
}
else if (editingStyle == UITableViewCellEditingStyleInsert) {
// Create a new instance of the appropriate class, insert it into the array, and add a new row to the table view
}
}
*/
/*
// Override to support rearranging the table view.
- (void)tableView:(UITableView *)tableView moveRowAtIndexPath:(NSIndexPath *)fromIndexPath toIndexPath:(NSIndexPath *)toIndexPath
{
}
*/
/*
// Override to support conditional rearranging of the table view.
- (BOOL)tableView:(UITableView *)tableView canMoveRowAtIndexPath:(NSIndexPath *)indexPath
{
// Return NO if you do not want the item to be re-orderable.
return YES;
}
*/
/*
#pragma mark - Navigation
// In a story board-based application, you will often want to do a little preparation before navigation
- (void)prepareForSegue:(UIStoryboardSegue *)segue sender:(id)sender
{
// Get the new view controller using [segue destinationViewController].
// Pass the selected object to the new view controller.
}
*/
-(void)listDetailViewControllerDidCancel:(ListDetailViewController *)controller
{
[self dismissViewControllerAnimated:YES completion:nil];
}
-(void)listDetailViewController:(ListDetailViewController *)controller didFinishAddingChecklist:(Checklist *)checklist
{
[self.dataModel.lists addObject:checklist];
[self.dataModel sortChecklists];
[self.tableView reloadData];
[self dismissViewControllerAnimated:YES completion:nil];
}
-(void)listDetailViewController:(ListDetailViewController *)controller didFinishEditingChecklist:(Checklist *)checklist
{
[self.dataModel sortChecklists];
[self.tableView reloadData];
[self dismissViewControllerAnimated:YES completion:nil];
}
-(void)navigationController:(UINavigationController *)navigationController willShowViewController:(UIViewController *)viewController animated:(BOOL)animated
{
if(viewController == self) {
[self.dataModel setIndexOfSelectedChecklist:-1];
}
}
-(void)viewWillAppear:(BOOL)animated
{
[super viewWillAppear:animated];
[self.tableView reloadData];
}
-(void)viewDidAppear:(BOOL)animated
{
[super viewDidAppear:animated];
self.navigationController.delegate = self;
NSInteger index = [self.dataModel indexOfSelectedChecklist];
if(index >= 0 && index < [self.dataModel.lists count]) {
Checklist *checklist = self.dataModel.lists[index];
[self performSegueWithIdentifier:#"ShowChecklist" sender:checklist];
}
}
#end
You have not declared the variable "Checklist" & trying to access the "iconName". Actually you are trying to access it directly via class name.
I can see you have created an instance if "Checklist" few lines down. So better create that instance before using Checklist.iconName
May be in the beginning of function after CellIdentifier creation.
Checklist *checklist = self.dataModel.lists[indexPath.row];
cell.imageView.image = [UIImage imageNamed:checklist.iconName]; /* Use of undeclared identifier; did you mean 'Checklist'? or Property 'iconName' not found on object of type 'Checklist'*/
return cell;
}
As per your code, "Checklist" is your class name, whereas the instance starts with small "c" as "checklist". So you also might have got confused.
Hope that helps.
I am trying to add Search to Todo demo application. I have below code so far with Search working. The issue with below code is that the Pagination doesn't work anymore. There is simlilar question about pagination but when "number of rows in section + 1" returned, the app crashes with [__NSArrayM objectAtIndex:] error. How do I get the Pagination working?
// MyTableController.h
#import <Parse/Parse.h>
#interface MyTableController : PFQueryTableViewController
#end
// MyTableController.m
#import "MyTableController.h"
#interface MyTableController() <UISearchDisplayDelegate> {
}
#property (nonatomic, strong) UISearchBar *searchBar;
#property (nonatomic, strong) UISearchDisplayController *searchController;
#property (nonatomic, strong) NSMutableArray *searchResults;
#end
#implementation MyTableController
- (id)initWithStyle:(UITableViewStyle)style
{
self = [super initWithStyle:style];
if (self) {
self.className = #"Todo";
self.keyToDisplay = #"text";
self.pullToRefreshEnabled = YES;
self.paginationEnabled = YES;
self.objectsPerPage = 5;
}
return self;
}
#pragma mark - View lifecycle
- (void)viewDidLoad
{
[super viewDidLoad];
self.searchBar = [[UISearchBar alloc] initWithFrame:CGRectMake(0, 0, self.view.frame.size.width, 44)];
self.tableView.tableHeaderView = self.searchBar;
self.searchController = [[UISearchDisplayController alloc] initWithSearchBar:self.searchBar
contentsController:self];
self.searchController.searchResultsDataSource = self;
self.searchController.searchResultsDelegate = self;
self.searchController.delegate = self;
CGPoint offset = CGPointMake(0, self.searchBar.frame.size.height);
self.tableView.contentOffset = offset;
self.searchResults = [NSMutableArray array];
}
- (void)viewDidUnload
{
[super viewDidUnload];
}
- (BOOL)shouldAutorotateToInterfaceOrientation:(UIInterfaceOrientation)interfaceOrientation
{
return (interfaceOrientation == UIInterfaceOrientationPortrait);
}
- (void)didReceiveMemoryWarning
{
[super didReceiveMemoryWarning];
}
- (void)filterResults:(NSString *)searchTerm {
[self.searchResults removeAllObjects];
PFQuery *query = [PFQuery queryWithClassName: self.className];
[query whereKey:#"text" containsString:searchTerm];
NSArray *results = [query findObjects];
[self.searchResults addObjectsFromArray:results];
}
- (BOOL)searchDisplayController:(UISearchDisplayController *)controller shouldReloadTableForSearchString:(NSString *)searchString {
[self filterResults:searchString];
return YES;
}
- (NSInteger)tableView:(UITableView *)tableView numberOfRowsInSection:(NSInteger)section {
if (tableView == self.tableView) {
return self.objects.count;
} else {
return self.searchResults.count ;
}
}
#pragma mark - Parse
- (void)objectsDidLoad:(NSError *)error {
[super objectsDidLoad:error];
}
- (void)objectsWillLoad {
[super objectsWillLoad];
}
- (PFQuery *)queryForTable {
PFQuery *query = [PFQuery queryWithClassName:self.className];
if ([self.objects count] == 0) {
query.cachePolicy = kPFCachePolicyCacheThenNetwork;
}
[query orderByAscending:#"priority"];
return query;
}
- (UITableViewCell *)tableView:(UITableView *)tableView cellForRowAtIndexPath:(NSIndexPath *)indexPath object:(PFObject *)object {
static NSString *CellIdentifier = #"Cell";
UITableViewCell *cell = [tableView dequeueReusableCellWithIdentifier:CellIdentifier];
if (cell == nil) {
cell = [[UITableViewCell alloc] initWithStyle:UITableViewCellStyleSubtitle reuseIdentifier:CellIdentifier];
}
cell.textLabel.text = [object objectForKey:#"text"];
cell.detailTextLabel.text = [NSString stringWithFormat:#"Priority: %#", [object objectForKey:#"priority"]];
return cell;
}
#pragma mark - Table view delegate
- (void)tableView:(UITableView *)tableView didSelectRowAtIndexPath:(NSIndexPath *)indexPath
{
[super tableView:tableView didSelectRowAtIndexPath:indexPath];
}
#end
In your own implementation of numberOfRowsInSection you must return numberOfRows + 1. But then you must write your code considering you have more cells than query returning. Check out your heightForRowAtIndexPath and others methods: there can be calls to [self.objects objectAtIndex:self.objects.count]. I mean, if indexPath.row == self.objects.count, its a "Load More" cell.
If you overriding willSelectRowAtIndexPath or didSelectRowAtIndexPath, you must do this in the top of method
[super tableView:tableView didSelectRowAtIndexPath:indexPath];
or add this (previous case is prefered)
if (indexPath.row == self.objects.count)
{
[self loadNextPage];
}
Customization of Load More cell placed in -(PFTableViewCell *)tableView:(UITableView *)tableView cellForNextPageAtIndexPath:(NSIndexPath *)indexPath
And im using
-(PFTableViewCell *)tableView:(UITableView *)tableView cellForRowAtIndexPath
instead of
- (UITableViewCell *)tableView:(UITableView *)tableView cellForRowAtIndexPath:
I have written the following code for a FirstLevelController implementation file, but the Disclosure Buttons, icons don't display in the view. Have checked the code, but can't figure out what's wrong.
FirstLevelController.m:
#import "BiDFirstLevelController.h"
#import "BidSecondLevelController.h"
#import "BiDDisclosureButtonController.h"
#implementation BiDFirstLevelController
#synthesize controllers;
- (void)viewDidLoad
{
[super viewDidLoad];
self.title = #"First Level";
NSMutableArray *array = [[NSMutableArray alloc]init];
// Disclosure button
BiDDisclosureButtonController *disclosureButtonController = [[BiDDisclosureButtonController alloc]initWithStyle:UITableViewStylePlain];
disclosureButtonController.title = #"Disclosure Buttons";
disclosureButtonController.rowImage = [UIImage imageNamed:#"disclosureButtonControllerIcon.png"];
[array addObject:disclosureButtonController];
}
- (id)initWithStyle:(UITableViewStyle)style
{
self = [super initWithStyle:style];
if (self) {
// Custom initialization
}
return self;
}
- (void)viewDidUnload
{
[super viewDidUnload];
self.controllers = nil;
}
- (BOOL)shouldAutorotateToInterfaceOrientation:(UIInterfaceOrientation)interfaceOrientation
{
return (interfaceOrientation == UIInterfaceOrientationPortrait);
}
#pragma mark - Table view data source
- (NSInteger)numberOfSectionsInTableView:(UITableView *)tableView
{
// Return the number of sections.
return 0;
}
- (NSInteger)tableView:(UITableView *)tableView numberOfRowsInSection:(NSInteger)section
{
// Return the number of rows in the section.
return [self.controllers count];
}
- (UITableViewCell *)tableView:(UITableView *)tableView cellForRowAtIndexPath:(NSIndexPath *)indexPath
{
static NSString *FirstLevelCell = #"FirstLevelCell";
UITableViewCell *cell = [tableView dequeueReusableCellWithIdentifier:FirstLevelCell];
if (cell == nil) {
cell = [[UITableViewCell alloc]initWithStyle:UITableViewCellStyleDefault reuseIdentifier:FirstLevelCell];
}
// Configure the cell...
NSUInteger row = [indexPath row];
BiDSecondLevelController *controller = [controllers objectAtIndex:row];
cell.textLabel.text = controller.title;
cell.imageView.image = controller.rowImage;
cell.accessoryType = UITableViewCellAccessoryDisclosureIndicator;
return cell;
}
#pragma mark - Table view delegate
- (void)tableView:(UITableView *)tableView didSelectRowAtIndexPath:(NSIndexPath *)indexPath
{
NSUInteger row = [indexPath row];
BiDSecondLevelController *nextController = [self.controllers objectAtIndex:row];
[self.navigationController pushViewController:nextController animated:YES];
}
#end
Your implementation of numberOfSectionsInTableView: returns 0, which means the table view should always be empty. Since returning 0 from this method doesn't make sense, I guess it's a typo.