UITableViewCell AccessoryView not displayed properly - ios

I have a UITableviewCell with a UISwitch in the accessoryView and it is displayed properly at runtime, but as soon as I rotate the device, the switch isn't anymore at the right place.
I could use constraints and not use the accessoryView, but I thought I could use this field..
Does anyone have an idea ?
Thanks !
EDIT :
here is the configuration in Interface Builder :
EDIT 2 :
I used a Custom cell :
with initialization on the default properties :
self.textLabel.font = [UIFont preferredDynamicFontForTextStyle:UIFontTextStyleBody fontSize:16.0];
self.backgroundColor = self.contentView.backgroundColor;
self.textLabel.text = item.title;
self.selectedImage = item.imageSelected;
self.unselectedImage = item.image;
self.imageView.image = self.unselectedImage;
// if I do it programmatically
self.accessoryView = [[UISwitch alloc] init];
I don't set constraints at all, because I use the default properties..

I'm just having the same issue as you.
Here are my observations:
If you set the accessoryView by code, it's always OK, whether the cell is selected or not, on both iOS 7 and iOS 8.
If you set the accessoryView by IB, the accessoryView moves to the top left corner after the first selection of the cell, and only on iOS 8.
I don't know if the issue is from IB or the way cells layout the accessory view on iOS 8 but so far the workaround is simple: always set the accessoryView by code to avoid unexpected behavior.

Looks like if you create the accessoryView and the editingAccessoryView in code and set it, everything works great!
If you try to set them in the UIStoryBoard, the UITableViewCell will remove the constraints after they fade away the first time, and it won't add them back. It's a shame, but hopefully they change it in a later version.
Hope that Helps!

If you are using autolayout (probably), you should setup constraints first.

For anyone finding this issue currently, I think I have an explanation of what might be happening here:
This is an issue with the translatesAutoresizingMaskIntoConstraints property on the view. From Apple's documentation, particularly relevant bits in bold:
If this property’s value is YES, the system creates a set of
constraints that duplicate the behavior specified by the view’s
autoresizing mask. This also lets you modify the view’s size and
location using the view’s frame, bounds, or center properties,
allowing you to create a static, frame-based layout within Auto
Layout. Note that the autoresizing mask constraints fully specify the
view’s size and position; therefore, you cannot add additional
constraints to modify this size or position without introducing
conflicts. If you want to use Auto Layout to dynamically calculate the
size and position of your view, you must set this property to NO, and
then provide a non ambiguous, nonconflicting set of constraints for
the view. By default, the property is set to YES for any view you
programmatically create. If you add views in Interface Builder, the
system automatically sets this property to NO.
So, when I came across this issue it was when I was changing the tableview from the contents being a stack view with label and switch into being a label with a UISwitch as the accessory view. The switch was being programmatically created earlier on view load for the container view the table was sitting in and the translatesAutoresizingMaskIntoConstraints was being set to NO - essentially the same situation that happens when you create the switch in interface builder. The code I was changing then tried to set up constraints but the switch would always bug out and be floating over to the wrong side when you rotated the screen. The solution for me was changing the translatesAutoresizingMaskIntoConstraints property to YES and letting the constraints be created by the view itself. It looks to me like this is a conflicting issue between what this property does on most views and what the accessory view itself tries to handle and if a programmer tries to go in and set things up themselves there seems to not be a good indication of what has gone wrong here. Hope this helps someone in the future!

I can say with some certainty that your constraints are not properly set up. But without seeing the storyboard's constraints, there's no way to say what is broken for sure.

Related

hide/ show controls in View controllers

My application gathers input from users and hence it is full of Labels, text boxes and buttons and I have to show or hide set of labels and text boxes based on certain conditions.
To accomplish it, I did the following.
Set fixed height (lets say 30) for all the controls
Set height constraint on each of the controls and created an outlet to the height constraint in the ViewController
Alter the heightConstraint.constant value programatically (between 0.0 and 30.0) based on the scenarios.
Having programmed like this, it is very difficult for me if there is any change in layout. (i.e., if user requested to add/remove any particular control from the view Controller).
I am using Auto Layout constraints. Could anyone suggest if there is a better way to accomplish my goal.
I am using IOS9 and Swift.
Many thanks in advance.
You can use UITableViewController with static cells for this case.
For hide/show row or section, you can change the size in the tableView:heightForRowAtIndexPath method.
UITableViewController automatically manages the layout and with static cell you can even create outlet for all the controls.
Have you considered using a table for this? It has mechanisms for inserting and deleting rows and would manage the layouting for you - only part you'd need to care about are the contents of the cells.
Instead of making IBOutlets to the height constraints of all the views that you might need to hide, you can just use the hidden property of UIViews to hide/show the view.
In case you need the view to make space for other views, you could set a simple animation and move the view out of screen bounds. You might face issues with layout constraints but it's surely worth the effort from a UI/UX perspective.
Additionally, if you know that you don't need a view any more you can even remove the view from it's superview.

UILabel redraws the view. How to avoid this behavior?

I have a viewController with three subviews.
Also I use AutoLayout and size classes.
These views are animated and change location and size.
After the animations I update a label but the whole view is redrawn so each view is in their initial position and size. This shouldn't happen.
As in Apple developer reference that says:
"The default content mode of the UILabel class is
UIViewContentModeRedraw. This mode causes the view to redraw its
contents every time its bounding rectangle changes. You can change
this mode by modifying the inherited contentMode property of the
class."
It doesn't seem clear to me how to modify the -contentMode- in order to update that label and leave the view -as is-. Can anyone give me a clue?
Thanks in advance.
It sounds like you may be using autolayout to lay out your view (e.g., via constraints in IB), but then you're manipulating your views' frames directly for your animations - is this the case? If so, you should instead be animating the constant values of your constraints, or possibly the transforms of your subviews.
If you manipulate frames directly in a view which uses autolayout, your changes will be over-written the next time the system lays out your view (e.g. after a label's text changes).
You have 3 options to overcome your issue -
Stop using AutoLayout in your Storyboard/Xib.
Not a great solution
Animate changes to the transform property of your subviews. e.g. myView.transform = CGAffineTransformMakeScale(2.0,2.0);
Useful for presentation and dismissal animations, but mixing AutoLayout and transforms has some issues pre-iOS 8.0
Add IBOutlets for the constraints you need to change in your animations. Animate changes to the constant values of those constraints.
Most robust approach but can lead to a lot of properties and code for complex animations
Try contentMode = UIViewContentModeCenter. This should prevent the redraw you're seeing. Although that may not be the contentMode you want.
Option 2 is to use CATextLayer to draw the label. It will resize very nicely with animation, but it's a lot more work to set up.

Why would all views in a view have userInteractionEnabled set to NO

I have a view and for some unknown reason, it's not receiving any touches. When I debugged the view, I've found out that its views' userInteractionEnabled is set to NO. The problem is that, I haven't set it anywhere; neither in Interface Builder (triple checked) and code. The problem started when I first created the regular UIViewController in Interface Builder, without a subclass or any custom code. I know it's near impossible to tell something without code samples, but my project is heavily complicated, and as I've said, the problem is appearing in a regular UIViewController (no subclass) that I've set in interface builder, so there is no relevant code that would mean anything. The rest of the app just works fine, though.
What can possibly cause all views in a regular, default view controller to become userInteractionEnabled = NO?
Found the answer myself after traversing window's recursive description more carefully. I had a scroll view, and inside that, a content view, and other views inside. I'm on pure auto layout, so my scroll view's content view needs to calculate it's own intrinsic size. I was using a placeholder height for the content view in Interface Builder, to make editing interface visually easier. Apparently, I forgot to connect the last view inside my content view to bottom of my content view with a constraint, resulting in my content view having a height of 0 (though still displaying perfectly as it doesn't have clipping enabled). When it's size was 0, it was calculating userInteractionEnabled as NO automatically without being explicitly set to NO. I've added the required bottom constraint and the problem went away.

Xcode Interface Builder Height/Width Settings vs. View Controller

I'm having a hard time wrapping my head around how frame properties (height, width, posX, posY) work in terms of setting them in a View Controller vs on the Storyboard (Interface Builder).
For instance, let's say I have a UICollectionView object that I set to have a width of 400 and a height of 800. Then, in my code, I set the frame of that same object to 600 x 400. I haven't really found a consistent behavior. I tried setting the frame in viewDidLayoutSubviews and it sort of worked - but it seem to 'jump' back and forth between that and what was set on the storyboard.
Basically my question is, when do the properties on the storyboard change the UI object? I assume that I just need to know that, and then reset them in the View Controller after the fact. Or, is there a way to set the height and width empty so that I can do it all in the code?
Any insight into this would be very helpful!
If you use AutoLayout in your project then setting frames of the view objects you configured in storyboard won't work. Because after you set the frames, AutoLayout will update frames again which makes the frames set by you not working. If you want detail, you can check this article:Advanced Auto Layout Tools But you can set frames of view objects created programmatically to position them.
You can check if you have turned on AutoLayout in you storyboard file's file inspector. There is one thing though, if you do want to use AutoLayout, be sure to not set view's translatesAutoresizingMaskIntoConstraints to NO. The default value of this property is YES. If you use AutoLayout, this property is set by storyboard for you, because constraints created in storyboard are enough to layout the views.
EDIT:
1) if you are not using AutoLayout then setting frames in code should work as expected.
2) yes you can, a little tricky though. you must create UICollectionView yourself using [[UICollectionView alloc] init] or load it from nib. and then configure cell in IB with a xib file. you can use AutoLayout to layout subviews of cell in xib file. and register the class of cell to UICollectionView or load cell object from nib yourself. then you should calculate the size of every cell and let AutoLayout layout subviews of cells.
although this is easier than layout interface entirely in code, it's still a little complicated. the better way is using AutoLayout. Since not all the layout detail can be done in the design time since some views' frame may be different depending on data. you can make a basic layout with AutoLayout first, then IBOutlet the constraints you want to configure on the fly. and change the constant property of constraint objects later. this way, you can 100% control the layout process and also let AutoLayout do the dirty jobs you don't want to do yourself. I suggest you read official docs of AutoLayout and other good resources about it. The learning curve is steep at first, it may make you want to kill yourself too. But it's really powerful and easy to use. once you figured out how AutoLayout works, it will make your iOS development life much easier.
If you want to set the size of things through code, you could try creating outlets from the storyboard to the View Controller. Then in the View Controller, you can use viewDidLoad or viewDidAppear to set the size properties of your object(s).
viewDidLoad will get called when that view is first created. viewDidAppear will get called each time that view comes back onto the screen (like if you are going back with a navigation controller).

UITableView in storyboard not updating content size on rotation

I'm working on project targeted for iOS 6 that leverages storyboards and auto layout. In the storyboard there are many places where a UITableView is added as a subview to a view controllers view. This table view uses prototype cells from the storyboard.
The issue we're running into is that if the view controller is initially loaded in landscape orientation and the device is then rotated to portrait, the table view begins to scroll both vertically and horizontally. The table views cells are drawn with the correct dimensions but there is additional white space to the right.
It appears that while the frame and bounds of the table view are being updated to the correct size on rotation, the table views content size is not. Regardless of any update rotation change the content size remains the same dimensions.
The issue doesn't present itself if programatic table view cells are used.
A few garish work arounds I've found, 1.) calling reloadData or reloadRowsAtIndexPaths:withRowAnimation: 2.) manually setting the property contentSize.
Both of these seem less than ideal.
I've added this
link to a dead simple sample project which demonstrates this issue. The only changes made are to the storyboard and the main view controllers implementation.
Before rotation
After rotation
I'm having the same issue - can't seems to find any documented answer related to this. I ended up manually modifying the UITableView contentSize like you mentioned in:
- (void) viewWillLayoutSubviews
{
self.tableView.contentSize = CGSizeMake(self.tableView.frame.size.height, self.tableView.contentSize.height);
}
I ran into this issue today and filed a bug report with Apple.
Appears that if you are using a custom cell with a UI element AND autoLayout, the UIScrollView content size is having problems.
If you remove all UI elements, OR turn off autoLayout, OR use a factory cell (basic, etc), all works fine.
Same issue I have rectified in my project.
I guess this is a bug in Storyboard.
Then I have solved it by manual coding in willAutorotate method by setting
tableview.contentsize = CGSizeMake(tableview.width, tableview.contentsize.height);
Hope this will work for you as well.
If you find any apple documentation regarding the same then please update me as well. Till then you can use the same solution.
Appears that if you are using a custom cell with a UI element AND autoLayout, the UIScrollView content size is having problems.
I had to turn off AutoLayout for my custom UITableViewCells to be able to scroll to the bottom on updating the data and then [self.tableView reloadData].
With AutoLayout turned on, the tableView.contentSize was being updated, but I still wasn't able to scroll to the bottom unless I rotated the device.
I found the following to work for me:
- (void)viewDidLayoutSubviews
{
[super viewDidLayoutSubviews];
dispatch_async(dispatch_get_main_queue(), ^{
self.tableView.contentSize = CGSizeMake(self.tableView.frame.size.width, self.tableView.contentSize.height);
});
}
Notice the async dispatch: if that line would be executed synchronously then the contentSize change would trigger another layout pass before the current one would have completed. This triggers an exception:
Auto Layout still required after sending -viewDidLayoutSubviews to the
view controller.
Usage of Constraints helped me. Since you are using Storyboards, it is really easy to set Constraint values for all edges, so UITableView will always fill the whole ViewController (of course if UITableView fills whole ViewController) regardless of device orientation.
I had the same problem.
I found this link. When I tried to implement this I did not find the Auto-sizing attributes for my view then I clicked on Master View Controller and then clicked on the File Inspector and uncheck Use Autolayout and then go to Attributes inspector auto-resizing should be there then you can change the attributes how you want it.
I am sure you must have managed to figure this out.

Resources