Blur view in TableViewCell - ios

I have created blur view in view controller and added sub view of custom table view cell. The problem is if I select 1st cell, it works perfectly. But if I select 2nd cell, blur view is shown in 3rd cell. If I select 3rd cell, blur view is shown in 5th cell.
- (void)viewDidLoad {
[super viewDidLoad];
[self.tableView registerNib:[UINib nibWithNibName:#"TableViewCell" bundle:[NSBundle mainBundle]] forCellReuseIdentifier:#"TableViewCell"];
cell = [TableViewCell new];
[self resetBoolArray];
}
- (UITableViewCell *)tableView:(UITableView *)tableView cellForRowAtIndexPath:(NSIndexPath *)indexPath {
self.effectView = [[UIVisualEffectView alloc] initWithEffect:[UIBlurEffect effectWithStyle:UIBlurEffectStyleDark]];
cell = (TableViewCell *) [self.tableView dequeueReusableCellWithIdentifier:#"TableViewCell"];
self.effectView.frame = cell.frame;
[self.effectView setHidden:[[self.boolAry objectAtIndex:indexPath.row] boolValue]];
[cell addSubview:self.effectView];
return cell;
}
- (void)tableView:(UITableView *)tableView didSelectRowAtIndexPath:(NSIndexPath *)indexPath {
[self resetBoolArray:indexPath.row];
[self.tableView reloadData];
NSLog(#"selected indexpath %ld",indexPath.row);
}
- (void)resetBoolArray {
self.boolAry = [NSMutableArray new];
for (int i = 0; i < 6; i++) {
[self.boolAry addObject:[NSNumber numberWithBool:YES]];
}
}
- (void)resetBoolArray: (NSInteger)indexpath {
self.boolAry = [NSMutableArray new];
for (int i = 0; i < 6; i++) {
if(i == indexpath) {
[self.boolAry addObject:[NSNumber numberWithBool:NO]];}
else{
[self.boolAry addObject:[NSNumber numberWithBool:YES]];}
}
}

Related

how to create custom cell with label & textfield in objective c

I have taken section with title let say
Monday,Tuesday,Wednesday......Sunday etc.also I have added "+" button after section title & added action on that button
Below is code and screenshot.
- (NSInteger)numberOfSectionsInTableView:(UITableView *)tableView
{
// Return the number of sections.
return [SectionArray count];
}
- (NSInteger)tableView:(UITableView *)tableView numberOfRowsInSection:(NSInteger)section{
if (section ==0) {
return 0;
}else{
return 3;
}
}
- (NSString *)tableView:(UITableView *)tableView titleForHeaderInSection:(NSInteger)section
{
return [SectionArray objectAtIndex:section];
}
- (UIView *)tableView:(UITableView *)tableView viewForHeaderInSection:(NSInteger)section {
CGRect frame = tableView.frame;
UIView *headerView;
if(section == 0 || section == 7) {
}else{
UIButton *addButton=[UIButton buttonWithType:UIButtonTypeContactAdd];
addButton.frame =CGRectMake(frame.size.width-60, 5, 50,30);
addButton.titleLabel.text = #"+";
addButton.tag =section;
// addButton.backgroundColor = [UIColor grayColor];
[addButton addTarget:self action:#selector(AddTimeSlot:) forControlEvents:UIControlEventTouchUpInside];
UILabel *title = [[UILabel alloc] initWithFrame:CGRectMake(30, 10, 100, 30)];
title.text = [SectionArray objectAtIndex:section];
headerView = [[UIView alloc] initWithFrame:CGRectMake(0, 0, frame.size.width, frame.size.height)];
[headerView addSubview:title];
[headerView addSubview:addButton];
}
return headerView;
}
- (UITableViewCell *)tableView:(UITableView *)tableView cellForRowAtIndexPath:(NSIndexPath *)indexPath{
NSString *cellIdent = #"cell";
UITableViewCell *cell = [tableView dequeueReusableCellWithIdentifier:cellIdent];
if(cell == nil){
cell = [[UITableViewCell alloc] initWithStyle:UITableViewCellStyleDefault reuseIdentifier:cellIdent];
}
return cell;
}
now i have to create cell when i click on "+" button,so please help me .
You can do that as below,
First you have to use an array for the data source that would be manipulated dynamically.
- (NSInteger)tableView:(UITableView *)tableView numberOfRowsInSection:(NSInteger)section{
if (section ==0) {
return 0;
}else{
return numberOfRowNeedToDisplay; //Take global int variable
}
}
In your button action AddTimeSlot:
-(void)addTimeSlot:(id)sender {
//If you want to add cell to section
NSMutableArray *arrayIndexPathsToBeAdded = [[NSMutableArray alloc] init];
for (int i = 0; i < <numberOfCellsYouWantToAdd>; i++) {
[arrayIndexPathsToBeAdded addObject:[NSIndexPath indexPathForRow:i inSection:view.tag]];
}
numberOfRowNeedToDisplay = <numberOfCellsYouWantToAdd>;
[self.tableView beginUpdates];
[self.tableView insertRowsAtIndexPaths:arrayIndexPathsToBeAdded withRowAnimation:UITableViewRowAnimationRight];
[self.tableView endUpdates];
//If you want to remove cells
NSMutableArray *arrayIndexPathsToBeRemoved = [[NSMutableArray alloc] init];
for (int i = 0; i < <numberOfCellsYouWantToRemove>; i++) {
[arrayIndexPathsToBeRemoved addObject:[NSIndexPath indexPathForRow:i inSection:sectionIndexToBeExpanded]];
}
numberOfRowNeedToDisplay = <numberOfCellsYouWantToRemove>;
[self.tableView beginUpdates];
[self.tableView deleteRowsAtIndexPaths:arrayIndexPathsToBeRemoved withRowAnimation:UITableViewRowAnimationLeft];
}
This is what i have had done:
Please read commented text.
- (NSInteger)tableView:(UITableView *)tableView numberOfRowsInSection:(NSInteger)section{
/** should be change in dynamically
maintain array for every section rows
return row count accordint to section
**/
}
#pragma mark - Private methods
- (void)AddTimeSlot:(UIButton *)sender {
int sectionNo = sender.tag;
// Get you section rowArray(DATASOURCE) and insert you detaisl
// then add UI
NSIndexPath *indexPath = [NSIndexPath indexPathForRow:0 inSection:0];
[tableView beginUpdates];
[tableView insertRowsAtIndexPaths:[NSArray arrayWithObject:indexPath] withRowAnimation:UITableViewRowAnimationNone];
[tableView endUpdates];
}

Tableview cell expandable with text field causes textfield to jump around

So i have been trying for a little while now to create a table view with expandable sections and one non expandable section. One of the expandable sections should have 3 text fields inside them in which you can edit the test inside the text field. I was able to get that working bt the moment you collapse the section and expand it again the textfield suddenly duplicates itself above and sometimes swaps itself out with the above cell. Ihavent been able to figure out why or how to make it not do that.
The idea is when the user enters text in the field and selects enter the text is stored into an array.
the code:
- (void)viewDidLoad{
[super viewDidLoad];
if (!expandedSections){
expandedSections = [[NSMutableIndexSet alloc] init];
}
manualSensorName = [[NSMutableArray alloc]initWithObjects: #"Sensor",#"",#"2",#"T", nil];
}
- (void)didReceiveMemoryWarning{
[super didReceiveMemoryWarning];
// Dispose of any resources that can be recreated.
}
#pragma mark - Expanding
- (BOOL)tableView:(UITableView *)tableView canCollapseSection:(NSInteger)section{
if (section>0) return YES;
return NO;
}
#pragma mark - Table view data source
- (NSInteger)numberOfSectionsInTableView:(UITableView *)tableView{
return 3;
}
- (NSInteger)tableView:(UITableView *)tableView numberOfRowsInSection:(NSInteger)section{
if ([self tableView:tableView canCollapseSection:section])
{
if ([expandedSections containsIndex:section])
{
return 5; // return rows when expanded
}
return 1; // only top row showing
}
// Return the number of rows in the section.
return 1;
}
- (UITableViewCell *)tableView:(UITableView *)tableView cellForRowAtIndexPath:(NSIndexPath *)indexPath{
static NSString *CellIdentifier = #"Cell";
UITableViewCell *cell = [tableView dequeueReusableCellWithIdentifier:CellIdentifier];
if (cell == nil) {
cell = [[UITableViewCell alloc] initWithStyle:UITableViewCellStyleDefault reuseIdentifier:CellIdentifier];
}
// Configure the cell...
if ([self tableView:tableView canCollapseSection:indexPath.section]){
if (!indexPath.row){
// first row
cell.textLabel.text = #"Expandable"; // only top row showing
if ([expandedSections containsIndex:indexPath.section])
{
UIImageView *arrow = [[UIImageView alloc] initWithImage:[UIImage imageNamed:#"arrowUP.png"]];
cell.accessoryView = arrow;
}
else
{
UIImageView *arrow = [[UIImageView alloc] initWithImage:[UIImage imageNamed:#"arrowDOWN.png"]];
cell.accessoryView = arrow;
}
}
else {
if (indexPath.row == 1){
NSString *flightNumText = [manualSensorName objectAtIndex:indexPath.row];
cell.textLabel.text = flightNumText;
}
else if (indexPath.row == 2){
txtManualSensor = [[UITextField alloc] initWithFrame:CGRectMake(180, 5, 120, 30)];
txtManualSensor.placeholder = #"Select";
txtManualSensor.delegate = self;
txtManualSensor.autocorrectionType = UITextAutocorrectionTypeNo;
txtManualSensor.backgroundColor = [UIColor whiteColor];
[txtManualSensor setBorderStyle:UITextBorderStyleBezel];
[txtManualSensor setTextAlignment:NSTextAlignmentCenter];
[txtManualSensor setReturnKeyType:UIReturnKeyDone];
// UITextField *playerTextField = [[UITextField alloc] initWithFrame:CGRectMake(180, 5, 120, 30)];
// playerTextField.adjustsFontSizeToFitWidth = YES;
// playerTextField.textColor = [UIColor blackColor];
// playerTextField.placeholder = #"SAMPLE";
// playerTextField.tag = 200;
// playerTextField.delegate = self;
// [cell.contentView addSubview:playerTextField];
cell.textLabel.text = #"Sensor Name";
[cell addSubview:txtManualSensor];
}
else if (indexPath.row == 3){
cell.textLabel.text = #"Some Detail";
cell.accessoryView = nil;
cell.accessoryType = UITableViewCellAccessoryDisclosureIndicator;
}
}
}
else {
cell.accessoryView = nil;
cell.textLabel.text = #"Normal Cell";
}
return cell;
}
- (BOOL)textFieldShouldEndEditing:(UITextField *)textField {
[manualSensorName replaceObjectAtIndex:2 withObject:textField.text];
return YES;
}
-(BOOL) textFieldShouldReturn:(UITextField *)textField{
[textField resignFirstResponder];
return YES;
}
// 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;
}
#pragma mark - Table view delegate
- (void)tableView:(UITableView *)tableView didSelectRowAtIndexPath:(NSIndexPath *)indexPath{
if ([self tableView:tableView canCollapseSection:indexPath.section]){
if (!indexPath.row){
[tableView beginUpdates];
// only first row toggles exapand/collapse
[tableView deselectRowAtIndexPath:indexPath animated:YES];
NSInteger section = indexPath.section;
BOOL currentlyExpanded = [expandedSections containsIndex:section];
NSInteger rows;
NSMutableArray *tmpArray = [NSMutableArray array];
if (currentlyExpanded) {
rows = [self tableView:tableView numberOfRowsInSection:section];
[expandedSections removeIndex:section];
}
else {
[expandedSections addIndex:section];
rows = [self tableView:tableView numberOfRowsInSection:section];
}
for (int i=1; i<rows; i++) {
NSIndexPath *tmpIndexPath = [NSIndexPath indexPathForRow:i inSection:section];
[tmpArray addObject:tmpIndexPath];
}
UITableViewCell *cell = [tableView cellForRowAtIndexPath:indexPath];
if (currentlyExpanded) {
UIImageView *arrow = [[UIImageView alloc] initWithImage:[UIImage imageNamed:#"arrowDOWN.png"]];
[tableView deleteRowsAtIndexPaths:tmpArray
withRowAnimation:UITableViewRowAnimationFade];
cell.accessoryView = arrow;
}
else {
UIImageView *arrow = [[UIImageView alloc] initWithImage:[UIImage imageNamed:#"arrowUP.png"]];
[tableView insertRowsAtIndexPaths:tmpArray
withRowAnimation:UITableViewRowAnimationFade];
cell.accessoryView = arrow;
}
NSLog(#"tableview row is %ld in section %ld",(long)indexPath.row,(long)indexPath.section);
[tableView endUpdates];
}
[tableView deselectRowAtIndexPath:indexPath animated:YES];
NSLog(#"selected row is %ld in section %ld",(long)indexPath.row,(long)indexPath.section);
if (indexPath.row == 1) {
// update text fields in cell table view
}
}
}
It may be as simple as replacing UITableViewRowAnimationTop by UITableViewRowAnimationFade:
When changing indexes in didSelectRowAtIndexPath, UITableViewCells change physical location (remember that the UITableView is a UIScrollView), and the scroller can't keep track of what your intent is.
UITableViewRowAnimationTop attempts to adjust the scrolling location, but fails.
Other design considerations:
Do not mix the model (the array of data to be displayed) with your view model (the UI displaying the model). In didSelectRowAtIndexPath, you should first re-order your model, then apply it to the cells
Consider not changing indexes on the fly: you may prefer a model that actually reflects the view structure, i.e. a tree.
Have you noticed you are not respecting - (void)tableView:(UITableView *)tableView and sometimes using self tableView:tableView or self.customTableView in the same method? You should use the tableView passed to you.

How to create dynamic cell in tableview?

I am facing issue regarding Dynamic cell in UITableView. I want to create dynamic rows while user clicked on button in tableview.
E.g.: in mytableview there are two rows as following :
Car :+
Bike :+
When user clicked add button then I have to show two more rows below car cell same thing as while user clicked on in front of bike add button then I have to show two more cells.
I think you need to have 2 sections, a bike and a car section with two data arrays to manage content of all cells. You may need to have two types of cell, an "add" cell and a "standard" cell.
Here is an example:
-In your viewDidiLoad:
self.bikeArray = [NSMutableArray arrayWithArray:#[#"Add bike"]]; // Aray to fill section 0
self.carArray = [NSMutableArray arrayWithArray:#[#"Add car"]]; // Aray to fill section 1
self.typeOfVehicleArray = #[#"Bike", #"Car"];
self.dataArray = #[self.bikeArray, self.carArray];
To create two types of cell, check indexPath.row:
- (UITableViewCell *)tableView:(UITableView *)tableView cellForRowAtIndexPath:(NSIndexPath *)indexPath {
UITableViewCell *cell;
switch (indexPath.row) {
case 0:{
NSString *addIdentifier = #"addIdentifier";
cell = [tableView dequeueReusableCellWithIdentifier:addIdentifier];
if (!cell){
// Add button...
CGFloat buttonWidth = 60.f;
cell = [[UITableViewCell alloc] initWithStyle:UITableViewCellStyleDefault reuseIdentifier:addIdentifier];
UIButton *b = [[UIButton alloc] initWithFrame:CGRectMake(cell.frame.size.width - buttonWidth - 10.f , 5.f, buttonWidth, cell.frame.size.height - 10.f)];
[b setTitle:#"ADD" forState:UIControlStateNormal];
// ...with a wonderful color
b.backgroundColor = [UIColor greenColor];
[b addTarget:self action:#selector(buttonPressed:) forControlEvents:UIControlEventTouchUpInside];
[cell addSubview:b];
[cell setSelectionStyle:UITableViewCellSelectionStyleNone];
}
break;
}
default:{
NSString *standardIdentifier = #"standardIdentifier";
cell = [tableView dequeueReusableCellWithIdentifier:standardIdentifier];
if (!cell){
cell = [[UITableViewCell alloc] initWithStyle:UITableViewCellStyleDefault reuseIdentifier:standardIdentifier];
[cell setSelectionStyle:UITableViewCellSelectionStyleNone];
}
break;
}
}
NSArray *vehicleArray = self.dataArray[indexPath.section];
cell.textLabel.text = [vehicleArray objectAtIndex:indexPath.row];
return cell;
}
Don't forget number of cells / sections:
- (NSInteger)numberOfSectionsInTableView:(UITableView *)tableView {
return [self.dataArray count];
}
- (NSInteger)tableView:(UITableView *)tableView numberOfRowsInSection:(NSInteger)section {
NSArray *vehicleArray = self.dataArray[section];
return [vehicleArray count];
}
Then you can implement buttonPressed:
- (void) buttonPressed: (id)sender{
// Find the section
UIButton *b = (UIButton *)sender;
UITableViewCell *cell = (UITableViewCell *)[b superview];
NSInteger section = [self.tableView indexPathForCell:cell].section;
// Get vehicle array (bikeArray or carArray)
NSMutableArray *vehicleArray = self.dataArray[section];
NSString *vehicleType = [self.typeOfVehicleArray objectAtIndex:section];
NSInteger nextVehicle = [vehicleArray count];
NSString *firstRowToAdd = [NSString stringWithFormat:#"%# %lu", vehicleType, (long)nextVehicle];
NSString *secondRowToAdd = [NSString stringWithFormat:#"%# %lu", vehicleType, (long)(nextVehicle + 1)];
// Add object in vehicle array
[vehicleArray addObject:firstRowToAdd];
[vehicleArray addObject:secondRowToAdd];
// Create array of corresponding indexPath and update tableview
NSArray *indexPathArray = #[[NSIndexPath indexPathForRow:nextVehicle inSection:section],
[NSIndexPath indexPathForRow:(nextVehicle + 1) inSection:section]];
[self.tableView beginUpdates];
[self.tableView insertRowsAtIndexPaths:indexPathArray withRowAnimation:UITableViewRowAnimationRight];
[self.tableView endUpdates];
}
You can control number rows in UITableView's tableView:numberOfRowsInSection: function that is defined in UITableViewDataSource Protocol. Just define an integer variable that holds the number rows user should see. On every Add button click increase the value of variable.
#implementation ViewController {
int numberOfRows;
}
- (void)viewDidLoad {
[super viewDidLoad];
numberOfRows = 3;
}
-(IBAction) addButtonClicked
{
numberOfRows++;
}
- (NSInteger)tableView:(UITableView *)tableView numberOfRowsInSection:(NSInteger)section
{
return numberOfRows;
}

Strange behavior - Row won't reselect until three taps

I'm currently facing a strange issue with a UITableView in iOS whereby deselected rows are no longer selectable immediately, you must tap three times before you can select again. I'm implementing something akin to a checklist, with a "clear" button to go through and deselect all the cells. This effect only occurs when the cell had been previously selected, but the "clear" button is pressed. If a cell had been untouched before and is touched after the clear button, it will be presented and toggle fine.
Here is what I have
I should mention that the VC this Table is in is stored inside a container, hence the reference to it.
The deselect
- (IBAction)btnClearTapped:(id)sender {
UITableView *locationList = self.locationsVc.tableView;
for (NSUInteger i = 0; i < [locationList numberOfSections]; i++) {
for (NSUInteger j = 0; j < [locationList numberOfRowsInSection:i]; j++) {
[locationList deselectRowAtIndexPath:[NSIndexPath indexPathForRow:j inSection:i] animated:YES];
}
}
}
The didSelectRowAtIndexPath method
- (void) tableView: (UITableView *) tableView didSelectRowAtIndexPath:(NSIndexPath *)indexPath {
UITableViewCell *cell = [self.tableView cellForRowAtIndexPath:indexPath];
BOOL isChecked = !((NSNumber *) cellToggleDict[indexPath]).boolValue;
cellToggleDict[indexPath] = #(isChecked);
UIView *selectionColorView = [[UIView alloc] init];
if (isChecked) {
selectionColorView.backgroundColor = selectedColor;
selectedLocations[indexPath] = [[Search sharedManager] locationAtIndexPath:indexPath];//PFObject
}
else {
selectionColorView.backgroundColor = unselectedColor;
[selectedLocations removeObjectForKey:indexPath];
}
cell.selectedBackgroundView = selectionColorView;
}
And finally the dequeue and redraw method
- (UITableViewCell *)tableView:(UITableView *)tableView cellForRowAtIndexPath:(NSIndexPath *)indexPath {
UITableViewCell *cell = [tableView dequeueReusableCellWithIdentifier:#"Reuse" forIndexPath:indexPath];
PFObject *object = [[Search sharedManager] locationAtIndexPath:indexPath];
cell.textLabel.text = object[#"Name"];
BOOL isChecked = ((NSNumber *) cellToggleDict[indexPath]).boolValue;
UIView *selectionColorView = [[UIView alloc] init];
if (isChecked) {
selectionColorView.backgroundColor = selectedColor;
}
else {
selectionColorView.backgroundColor = unselectedColor;
}
cell.selectedBackgroundView = selectionColorView;
return cell;
}
You don't clear the cellToggleDict entries in the btnClearTapped: method. You should have.
- (IBAction)btnClearTapped:(id)sender {
UITableView *locationList = self.locationsVc.tableView;
[cellToggleDict removeAllObjects]; // Clear all objects from the selected store
for (NSUInteger i = 0; i < [locationList numberOfSections]; i++) {
for (NSUInteger j = 0; j < [locationList numberOfRowsInSection:i]; j++) {
[locationList deselectRowAtIndexPath:[NSIndexPath indexPathForRow:j inSection:i] animated:YES];
}
}
}

Setting a view in a customTableCell to be visible after beginUpdate and endUpdate

So I have a TableView that loads customTableCells.
- (UITableViewCell *)tableView:(UITableView *)tableView cellForRowAtIndexPath:(NSIndexPath *)indexPath
{
static NSString *CellIdentifier1 = #"ReviewTableCell";
reviewCell = [self.reviewTableView dequeueReusableCellWithIdentifier:CellIdentifier1];
if (reviewCell == nil)
{
NSArray *nib = [[NSBundle mainBundle] loadNibNamed:#"ReviewTableCell" owner:self options:nil];
reviewCell = [nib objectAtIndex:0];
[reviewCell.replyButton addTarget:self action:#selector(reply:) forControlEvents:UIControlEventTouchUpInside]; <----- note! reply button function
}
reviewCell.replyButton.tag = indexPath.row;
if ([[_isExpandList objectAtIndex:indexPath.row]isEqual:#1])
{
[reviewCell.postView setHidden:NO];
}
else if ([[_isExpandList objectAtIndex:indexPath.row]isEqual:#0])
{
[reviewCell.postView setHidden:YES];
}
return reviewCell;
}
As you can see on the customTableCell, there is a button that has the following function:
- (void)reply:(UIButton *)sender {
BOOL isExpand = [_isExpandList[sender.tag] boolValue];
[_isExpandList replaceObjectAtIndex:sender.tag withObject:#(!isExpand)];
if ([[_isExpandList objectAtIndex:sender.tag]isEqual:#1])
{
[self.reviewTableView beginUpdates];
[reviewCell.postView setHidden:NO];
[self.reviewTableView endUpdates];
}
else
{
[self.reviewTableView beginUpdates];
[reviewCell.postView setHidden:YES];
[self.reviewTableView endUpdates];
}
}
When the user presses the button, the sender cell will "expand" (height will extend) and review.postView should appear. However, the cell only expands but the postView does not appear until I scroll down and scroll back up. This is probably because the cell is then reloaded. How can I ensure that the postView appears as soon as I press the button.
_isExpandList is just an array that keeps track of which cell is expanded and which is not. I've initiated it with the following code in ViewDidLoad:
_isExpandList = [[NSMutableArray alloc] init];
for (int i = 0; i < 5; i++) {
[_isExpandList addObject:#NO];
}
I will include the cellHeight function just in case but I don't think it is relevant.
- (CGFloat)tableView:(UITableView *)tableView heightForRowAtIndexPath:(NSIndexPath *)indexPath
{
if ([[_isExpandList objectAtIndex:indexPath.row]isEqual:#0])
{
return 100;
}
else{
return 300;
}
}
You need to explicitly reload the tableview cell using:
- (void)reloadRowsAtIndexPaths:(NSArray *)indexPaths withRowAnimation:(UITableViewRowAnimation)animation
or
- (void)reloadData
if you don't mind the performance hit of reloading all of the cells.

Resources