iOS increase edit mode indentation for custom UITableViewCell - objective-c

I've got a UITableView with the ability to delete the rows using edit mode etc. As standard, when you tap the 'edit' button, you go into edit mode and the content of the cells gets moved to the right. If you do a 'swipe to delete', the cell content stays where it is.
What I want to do is increase the indentation when you enter edit mode. I've tried the UITableView delegate method indentationLevelForRowAtIndexPath but that doesn't seem to work when I'm using a UITableViewCell subclass.
In the end I used the layoutSubviews method in my UITableViewCell subclass. Below is my code:
- (void)layoutSubviews
{
[super layoutSubviews];
CGRect b = [self bounds];
if(self.editing && !self.showingDeleteConfirmation){
b.origin.x = 42;
}
[self.contentView setFrame:b];
}
This indents the cell content further when you enter edit mode and thanks to the "!self.showingDeleteConfirmation", when you do a 'swipe to delete', it doesn't indent it.
However, when you tap the 'edit' button, then tap one of the circle delete buttons, the cell content slides back to the original 0 x axis position. This is because the showingDeleteConfirmation is now set to true.
I've tried to fix this by checking what the current origin.x value is, but every time I check, it's set to 0.
Is there a way I can achieve what I want?

Related

Resize UICollectionView cells after their data has been set

My UICollectionView cells contain UILabels with multiline text. I don't know the height of the cells until the text has been set on the label.
-(CGSize)collectionView:(UICollectionView *)collectionView
layout:(UICollectionViewLayout*)collectionViewLayout
sizeForItemAtIndexPath:(NSIndexPath *)indexPath;
This was the initial method I looked at to size the cells. However, this is called BEFORE the cells are created out of the storyboard.
Is there a way to layout the collection and size the cells AFTER they have been rendered, and I know the actual size of the cell?
I think your are looking for the invalidateLayout method you can call on the .collectionViewLayout property of your UICollectionView. This method regenerates your layout, which in your case means also calling -collectionView: layout: sizeForItemAtIndexPath:, which is the right place to reflect your desired item size. Jirune points the right direction on how to calculate them.
An example for the usage of invalidateLayout can be found here. Also consult the UICollectionViewLayout documentation on that method:
Invalidates the current layout and triggers a layout update.
Discussion:
You can call this method at any time to update the layout information. This method invalidates the layout of the collection view itself and returns right away. Thus, you can call this method multiple times from the same block of code without triggering multiple layout updates. The actual layout update occurs during the next view layout update cycle.
Edit:
For storyboard collection view which contains auto layout constraints, you need to override viewDidLayoutSubviews method of UIViewController and call invalidateLayout collection view layout in this method.
- (void)viewDidLayoutSubviews {
[super viewDidLayoutSubviews];
[yourCollectionView.collectionViewLayout invalidateLayout];
}
subclass UICollectionViewCell and override layoutSubviews like this
hereby you will anchor cell leading and trailing edge to collectionView
override func layoutSubviews() {
super.layoutSubviews()
self.frame = CGRectMake(0, self.frame.origin.y, self.superview!.frame.size.width, self.frame.size.height)
}
Hey in the above delegate method itself, you can calculate the UILabel size using the below tricky way and return the UICollectionViewCell size based on that calculation.
// Calculate the expected size based on the font and
// linebreak mode of your label
CGSize maximumLabelSize = CGSizeMake(9999,9999);
CGSize expectedLabelSize =
[[self.dataSource objectAtIndex:indexPath.item]
sizeWithFont:[UIFont fontWithName:#"Arial" size:18.0f]
constrainedToSize:maximumLabelSize
lineBreakMode:NSLineBreakByWordWrapping];
- (void)viewDidLoad {
self.collectionView.prefetchingEnabled = NO;
}
In iOS 10, prefetchingEnabled is YES by default. When YES, the collection view requests cells in advance of when they will be displayed. It leads to crash in iOS 10

UITableView setContentOffset but don't scroll tableView?

I am using setContentOffset on a UITableView because I want to initially hide a search field that is my tableHeaderView.
[self.tableView setContentOffset:CGPointMake(0, 56)]; // No scroll please!
Each time I push a new viewController I want to hide the search bar with contentOffset. But when I pop a viewController that offset is no longer in effect for some reason and shows the search bar. Why is this?
you can try and implement it on the following
- (void)viewWillAppear:(BOOL)animated {
[self.tableView setContentOffset:CGPointMake(0, 56)];
}
that will put the table in the correct position before it is displayed on the screen, I am assuming you mean no animation while setting the position.
I am guessing that you want to stop the user being able to scroll to the very top of the screen. If so you can implement the following UITableView delegate (on iOS5 and above):
scrollViewWillEndDragging:withVelocity:targetContentOffset:
which allows you to modify the final target for a change in the contentOffset. In the implementation you do:
- (void)scrollViewWillEndDragging:(UIScrollView *)theScrollView withVelocity:(CGPoint)velocity targetContentOffset:(inout CGPoint *)targetContentOffset
{
if(targetContentOffset->y < 56) {
targetContentOffset->y=56;
}
}
If you are trying to preserve the value of something during an action that loses it, the natural solution is to hold onto it yourself ("Hold/Restore"):
"Hold": get content offset to a field or local variable. Apple doc
.. do whatever you want.
"Restore": set content offset to the value you got above.
(Sorry, I don't write Objective C code, so can't provide the exact code. An edit to add the code, would be welcome.)
In a different situation, it might be necessary to hold the row you were at, and then scroll back to that row:
(Adapted from: https://stackoverflow.com/a/34270078/199364)
(Swift)
1. Hold current row.
let holdIndexPath = tableView.indexPathForSelectedRow()
.. do whatever (perhaps ending with "reloadData").
Restore held row:
// The next line is to make sure the row object exists.
tableView.reloadRowsAtIndexPaths([holdIndexPath], withRowAnimation: .None)
tableView.scrollToRowAtIndexPath(holdIndexPath, atScrollPosition: atScrollPosition, animated: true)

How to add an image in UITableView's content view while we reodering cells?

I have a tableview where I provide the option to reoder the cells. But, I don't want to show the delete icon when the user doing rearranging cells. So I did like this to remove the delete button.
In normal mode..
After edit mode (That is, non deletable but rearrangable mode)..
Here, two things are happening. One is the accessoryview of each cell has a image(that represents rearrangement). Second thing is, all strings are moved some points from the left screen. This gap is actually for the deletion symbol. Since I hide the delete button, an empty space appears.
Ok, here is the problem comes. I now want to add some custom button with an image in each cell's content view.
So, I added the following code in my tableView: cellForRowAtIndexPath:
if (isEditable)
{
selectionButton = [UIButton buttonWithType:UIButtonTypeCustom];
UIImage *img = [UIImage imageNamed:#"blue_button.png"];
selectionButton.frame = CGRectMake(-25, 10, img.size.width, img.size.height);
[selectionButton setBackgroundImage:img forState:UIControlStateNormal];
[selectionButton addTarget:self action:#selector(buttonClickAction:) forControlEvents:UIControlEventTouchUpInside];
[cell.contentView addSubview:selectionButton];
}
The blue button was 24*24 pixels.
The reason why I used -25 as "x" value:
If I give a positive value or zero, the button will overlapped with cell text. Below image represents when the x value is 0.
But for x=-25,
What I need:
Since I added the button with negative x value, the whole image width (24 pixels) will be hiden in the x value (25 pixels). So the button action buttonClickAction: was not called. I want to change the image when the user tapping on it(switching between selected/unselected mode).
Is there any way to call the button's action method? Or should I create a custom cell?
Just confused..
Add this to your Table View Controller
- (BOOL) tableView:(UITableView *)tableView shouldIndentWhileEditingRowAtIndexPath:(NSIndexPath *)indexPath {
return NO;
}
It will remove empty space.

How to catch an event when the "delete" button appears in a UITableView?

I have a table section with a bunch of custom cells, each of which has two UITextFields right next to each other.
When the table enters editing mode, I have to resize the right UITextField of each cell so that it doesn't get pushed off the screen by the delete minus sign that appears to the left of the cell.
I need to do a similar thing for when the user presses the delete minus sign and the "Delete"m button appears on the right side of the cell. I need to resize the right UITextField so that it isn't partially obscured by the Delete button. However, I can not find any protocol method or anything that alerts me when the delete button appears.
When the user swipes the row to delete, this method seems to work:
- (void)tableView:(UITableView *)tableView willBeginEditingRowAtIndexPath:(NSIndexPath *)indexPath
However, when the user presses the red minus button to delete, it doesn't call that function.
Try using these:
- (void)willTransitionToState:(UITableViewCellStateMask)newState{
[super willTransitionToState:newState];
//deletebutton (minusbutton) will be animated in
if(newState == UITableViewCellStateShowingEditControlMask){
}
//deletebutton (minusbutton) will be animated out
if(newState == UITableViewCellStateDefaultMask){
}
//deletebutton (minusbutton) will be rotated 90 degrees ccw
if(newState == 3){
}
//deletebutton (minusbutton) will be rotated 90 degrees cw
if(newState == UITableViewCellStateShowingEditControlMask){
}
}
cell.showingDeleteConfirmation is what you're looking for.

Animate UITableViewCell ContentView to fade upon entering Edit Mode

I've noticed this functionality in the iPhone Mail.app and SMS.app apps, but I'm unsure how to implement it myself.
In a standard UITableView, when a user taps the 'Edit' button and the deletion buttons move into position, as the content views are sliding to the right, they perform a quick fade transition where they are replaced by thinner versions of themselves (to account for the space the deletion button is taking up).
I initially thought this was done by calling the following method when editing mode is enabled:
[self.tableView reloadRowsAtIndexPaths: [tableView indexPathsForVisibleRows] withRowAnimation: UITableViewRowAnimationFade];
However this cannot be right as it also fade transitions the delete button itself as well as any accessory views the cell has (suffice it to say, it looks quite odd).
I was wondering, how would it be possible to force the content view to redraw itself, and to then fade the new drawn version over the old one when the table enters edit mode?
UPDATE:
Thanks to Caleb's answer, this is the final block of code that allowed me to get what I was after:
My final solution was to subclass UITableViewCell and then apply the following code to the setEditing accessor:
-(void) setEditing: (BOOL)editing animated: (BOOL)animated
{
[super setEditing: editing animated: animated];
CATransition *animation = [CATransition animation];
animation.duration = 0.2f;
animation.type = kCATransitionFade;
//redraw the subviews (and animate)
for( UIView *subview in self.contentView.subviews )
{
[subview.layer addAnimation: animation forKey: #"editingFade"];
[subview setNeedsDisplay];
}
}
I probably should just clarify as well. Since performance is of utmost importance, everything inside my cell's contentView is being rendered through CG (ie drawRect:), so I can't control any elements being drawn in there specifically.
That animation happens when you call -setEditing:animated: on the table. The table then calls -setEditing:animated: on each of the visible cells. It looks like the standard behavior for a table cell is to adjust the size of the content views, shift them right, and remove the right accessory. If you have your own cells and want a different look in editing mode, I think you can override -setEditing:animated: to adjust the cell content as you like.