Swipe to delete moves the UITableViewCell to the left - ios

I use custom code to create cells that get displayed on a UITableView. When a row is swiped, the delete button appears on the far right of the cell as expected. However it causes the contents of the cell to move to the left (partly off screen). This kind of behaviour didn't happen when using the cells that are built in to the framework.

The UIView property autoresizingMask allows you to specify how your subviews should behave when their superview (in this case the UITableViewCell's contentView) gets resized.
See the View Programming Guide for iOS for more information.

Isn't it because your content is bound to the right edge?

Although this answer may be too late, I believe the problem is due to the fact that you happen to be adding your content directly to the cell by writing something like:
MyView* myView = [[MyView alloc] init];
[cell addSubview : myView];
This happens to be good; however, your content will be affected by any change that takes place within the cell. If, on the other hand, you want your views to remain intact while anything else happens to the cell, you must add your content as subviews of the cell's contentView:
MyView* myView = [[MyView alloc] init];
[[cell contentView] addSubview : myView];
I do hope this helps.
Cheers!

Related

UISwitch not displaying in custom UITableView Cell

I need a custom cell with a label and a switch.
Now, the main problem is that I can't get the switch to display. I have tried several methods, including adding the switch programatically to the cell's accessoryView.
I used the IB, added the switch to the cell, connected the IBOutlet. I also tried to add the switch programatically, in cell's awakeFromNib:
- (void)awakeFromNib {
[super awakeFromNib];
if (!self.fieldSwitch) {
self.fieldSwitch = [[UISwitch alloc] init];
[self.fieldSwitch addTarget:self action:#selector(switchUpdatedValue:) forControlEvents:UIControlEventValueChanged];
self.fieldSwitch.onTintColor = [ColorManager sharedInstance].genericSwitchColor;
self.accessoryView = self.fieldSwitch;
}
}
This has had absolutely no effect; I also tried adding it as a subview to the cell's contentView then calling bringSubviewToFront:. Again, no success.
I checked, and self, accessoryView, fieldSwitch none of them were nil.
Does anyone have any idea what could be so wrong? on a side note, does anyone understand why adding a control from the IB is broken by default?
If you are using size classes you have to set a constraint for the UISwitch. For example if you are using an Any Any size class and you place the UISwitch in the cell it may actually be displaying far off to the right. (I would of posted this as a comment however not enough rep)

Create tableHeaderView that always fills the frame of the visible table?

I need to implement the ability to display a label perfectly centered on screen with nothing else visible, but this needs to be done in a UITableView. The setup is a UISpiltViewController that has a UITableViewController for the detail view controller, and when no item is selected on the left I want to display a message stating that on the right, and when the user selects an item that label should instantly disappear and reveal the table. (Just like the Mail app.)
I already have this set up and it's working ok, but for some reason it's not always staying centered on screen, and it isn't a very good solution - there are some minor oddities for example you can partially see the top of the table while the rotation is occurring. I am just creating a UILabel, setting its frame to fill the visible area, then setting the table's tableHeaderView to that label, and finally disabling the ability to scroll the table. And upon rotation, the frame has to be updated to fill the visible area again. That's where the oddities occur, because it's not updating until after the rotation completes.
My question is, what is a better approach to implement this behavior? Is there some way I can prevent having to update the frame after rotation, would it be possible to use Auto Layout for the tableHeaderView?
//Setting the tableHeaderView
self.tableView.tableHeaderView = self.label;
//Creating the UILabel
- (UILabel *)label {
_label = [[UILabel alloc] initWithFrame:CGRectMake(0, 0, self.tableView.bounds.size.width,
self.tableView.bounds.size.height
- self.navigationController.navigationBar.frame.size.height
- self.tabBarController.tabBar.frame.size.height
- MIN([UIApplication sharedApplication].statusBarFrame.size.height,
[UIApplication sharedApplication].statusBarFrame.size.width))];
_label.text = #"Nothing Selected";
_label.textAlignment = NSTextAlignmentCenter;
_label.backgroundColor = self.tableView.backgroundColor;
return _label;
}
- (void)didRotateFromInterfaceOrientation:(UIInterfaceOrientation)fromInterfaceOrientation {
if (_label) {
_label.frame = CGRectMake(0, 0, self.tableView.bounds.size.width,
self.tableView.bounds.size.height
- self.navigationController.navigationBar.frame.size.height
- self.tabBarController.tabBar.frame.size.height
- MIN([UIApplication sharedApplication].statusBarFrame.size.height,
[UIApplication sharedApplication].statusBarFrame.size.width));
self.tableView.tableHeaderView = nil;
self.tableView.tableHeaderView = _label;
}
}
Is your detail controller a UITableViewController? If so, that makes things harder since any subviews you add (your label) become part of the table. It would be easier if you use a UIViewController, and alternately hide the label or table view when you need to. The label can be any size, and use centerX and centerY constraints to keep it centered. If you do it that way, you won't have to do anything on rotation.
You don't have to set the label as the headerView of your UITableView.
You can simply add the label to self.view. Even if you are running inside a UITableViewController, each UIViewController always has a view property.
Add the label to self.view and toggle the visibility of the label and the tableView as needed.This is much easier, than trying to fiddle the label in the tableview - hierarchy ;)
EDIT
As pointed out by #rdelmar, the UITableViewController indeed does not have a separate view which contains the tableview, but rather uses the tableview as it's view directly. -.-
Sorry. I did assume the two views were separated.
All I can say is follow #rdelmar s advice, and stop using UITableViewController. It forces you to do things the default way, and if you want to customized it you WILL have a bad time :(
EDIT 2
Ok so you have 2 options:
1) Do the following:
[_label setAutoResizingMask:(UIViewAutoResizingFlexibleWidth | UIViewAutoResizingFlexibleHeight)];
in your label getter. That way, you don't have to care about screen rotation anymore. The label will always fit its parents bounds.
2) Use UIViewController and treat the label as a sibling of the tableView. <- Better approach but requires more refactoring from your current state.
As pointed out by Cabus, the solution is to set the autoresizingMask of the label to UIViewAutoResizingFlexibleWidth | UIViewAutoResizingFlexibleHeight. That way, the label will always fit its parent. This can be done while using the label for the tableHeaderView, and there's no longer a need for detecting orientation changes.

Getting all subviews for a UIScrollView

I need to get an array of all the subviews in a UIScrollView. Right now I'm using
NSArray *subviews = [myScrollView subviews];
but this seems to only be returning the subviews that are visible at the time the code is run. I need all the subviews in the whole extent of the UIScrollView, even those that are currently hidden (as in off screen). How would I get that?
Essentially, I'm looking for something like the contentSize property of a UIScrollView, except instead of returning just the size of the UIScrollView if it were big enough to display all of it's content, I want it to return the content itself.
EDIT: I think I've figured it out: the scroll view this isn't working for is actually a UITableView - and I think it's deque-ing the cells that are off screen on me, and that's why they aren't showing up. I'm going to do some testing to confirm.
Try with following code its working for me.
for(UIView * subView in myScrollView.subviews ) // here write Name of you ScrollView.
{
// Here You can Get all subViews of your myScrollView.
// But For Check subview is specific UIClass such like label, button, textFiled etc.. write following code (here checking for example UILabel class).
if([subView isKindOfClass:[UILabel class]]) // Check is SubView Class Is UILabel class?
{
// You can write code here for your UILabel;
}
}
tl;dr
It turns out that
NSArray *subviews = [myScrollView subviews];
will indeed return all the subviews in a UIScrollView *myScrollView, even if they are off-screen.
The Details
The problem I was actually having was that the scroll view I was trying to use this on was actually a UITableView, and when a UITableViewCell in a UITableView goes off-screen, it actually gets removed from the UITableView - so by the time I was calling subviews, the cells I was looking for were no longer in the scroll view.
My workaround was to build all of my UITableViewCells in a separate method called by my viewDidLoad, then put all of those cells into an array. Then, instead of using subviews, I just used that array. Of course, doing it this way hurts the performance a little (in cellForRowAtIndexPath you just return the cell from the array, which is slower than the dequeueReusableCellWithIdentifier method that is typically used), but it was the only way I could find to get the behavior I needed.

Prevent UITableViewCells from creating as you scroll down

I'm creating a mail screen using which visually resembles the iOS native email app. It looks like this (Both images are of the same screen. First one is the top half and the second one is the rest of it).
The difference is my mail screen has more custom fields in addition to normal To, Cc, Subjet fields.
I'm using a UITableViewController to create this. Below is a code snippet which creates a cell (For each cell it's pretty much the same).
- (UITableViewCell *)tokenTableView:(TITokenTableViewController *)tableView cellForRowAtIndexPath:(NSIndexPath *)indexPath {
UITableViewCell *cell = nil;
self.tableView.frame = CGRectMake(0,0,320,320);
UIView *contentSubview = nil;
cell = [[UITableViewCell alloc] initWithStyle:UITableViewCellStyleSubtitle reuseIdentifier:CellIdentifierSubject];
if(!self.txtSubject) {
self.txtSubject = [[UITextField alloc] initWithFrame:CGRectMake(0, 0, 0, 0)];
self.txtSubject.frame = CGRectMake(10, cell.frame.size.height / 2 - self.txtSubject.font.lineHeight / 2, tableView.tableView.bounds.size.width, 30);
self.txtSubject.placeholder = #"Subject";
[self setupMailData:indexPath.row];
}
contentSubview = self.txtSubject;
}
Say, I open up a draft. All the details in the input fields are filled and without changing anything, I hit send and it crashes the app. I know what's causing this. The problem is that normally the cells that are under the viewable portion of the screen gets created as you scroll down, right? But in this scenario, if I send it without scrolling down but those cells below the viewport don't exist thus it throws the error.
If I open the draft, scroll down and hit send, it works fine.
I need to know if there's a way to create all these cells at once. Even the cells that are below the viewport at first. Not depending on the user to scroll down.
I hope you have an idea about my situation. Can anyone suggest a solution?
Thank you.
follow steps:
Take uiscrollview and set scrollview frame as which you want to display.
Take uitableview as a subview of uiscrollview
set property Scrolling Enabled = NO (uncheck checkbox in .xib) of uitableview
call reloaddata method of uitableview
set tableview frame and contentsize of scrollview
tblEmail.frame = CGRectMake(yourXPos, yourYPos, yourWidth, tblEmail.contentSize.height);
scrollObj.contentSize = CGSizeMake(yourScrollWidth,tblEmail.contentSize.height+10);
so, the height of tableview is equal its contentsize. so, its create all cells at a time. and set contentsize of scrollview is equal tableview contentsize. so, the scrolling feature is worked like uitableview scrolling...
Use a Storyboard, add a UITableViewController and set the 'Content' to StaticCells.
Then you can define all the cells and their content in the Storyboard. You can even wire stuff up to IBOutlets in your UITableViewController subclass and they will all be there for you when viewDidLoad is fired ...
When using a Storyboard your code for getting the ViewController looks like:
[[UIStoryboard storyboardWithName:#"MyStoryboard" bundle:nil] instantiateInitialViewController];

Can't get UILabel to show properly on top of UITableView

I am struggling to achieve what I thought was nothing but a 1' coding but apparently
adding a UILabel above my UITableView in a UITableViewController is not a piece of cake...?
Here is the code (yes basic, I know):
UILabel *label = [[UILabel alloc] initWithFrame:CGRectMake(0, 0, 310, 20)];
[[self tableView] addSubview:label];
The result can be seen in the screenshot below, the label on the top right is just half displayed, saying "Balance..."
Please note that if I try to change CGRect origin.y or size.height the UILabel is not displayed at all.
I also tried adding the following, with no change in result:
[[self tableView] bringSubviewToFront:balanceLabel];
I don't care if the UILabel is scrolled up when scrolling up the UITableView, I want it to stick with the first section header.
I know this can be achieved in other ways, using a custom UIView for the header, changing to UIViewController or using a .xib, but really I would like to understand why this happens.
Thanks for any help.
F.
It does look like the header is hiding your label, maybe you could try setting the header background to clearColor. Since you have no control on the table view loop I suspect that after your addSubView somewhere the table builds its own header and does another addSubView.

Resources