I have a VC where I created a UITableView and added it to the main view. The table has his delegate and datasource added to the VC:
choicesTableView.dataSource = self
choicesTableView.delegate = self
I can see the table correctly and everything runs smooth.
In cellForRowAtIndexPath I've created a new UITextView and added to cell:
let myTextView = UITextView(frame: CGRectMake(0, 0, myVar.sW, 100))
(myVar.sW is a referenced value token from the screen width)
I added the UITextView to the cell:
cell.addSubview(myTextView)
Again, I see all as expected.
The Dark Side Of The Moon of this situation is that now I cannot get the didSelectRowAtIndexPath event since the UITextView is covering the cell's view. If I comment the addSubview method, the didSelectRowAtIndexPath is correctly fired.
Is there any way to let the UITextView pass the user interaction to the cell without creating a custom cell view from scratch?
(for your information, in this phase I'm not using the Interface Builder)
Thank you.
The solution was pretty simple. I resolved my problem by adding this line:
myTextView.userInteractionEnabled = false
So the touch can pass through the UITextView's layer and reach the cell layer.
This thread has helped me.
Related
I have an extension for UITextView which centers the text on a UITextView vertically that I found in the following SO answer: https://stackoverflow.com/a/38855122/4660602
My UITextView lives within a UITableViewCell, and the problem is that the function doesn't seem to work on the initial load. It only works when I reload the tableView or when I scroll.
I am calling the method within cellForRowAtIndexPath but I have tried adding it to my custom cell class in awakeFromNib and prepareForReuse but have and no luck. Wondering if anyone has any other advice / solutions.
EDIT:
Also forgot to mention, my VC with the tableView is embedded in a navigationBar and tabBar. When I switch to a new VC in the tabBar and then back, the UITextView text realigns to the top incorrectly, even if it was centered already.
Thanks!
The correct place for sizing code in a view is UIView.layoutSubviews. Since your centering function depends on the bounds, you have to call it in layoutSubviews, otherwise the bounds may not be correct (ie they match whats in the nib and not the current device). You can call setNeedsLayout in your cellforRowAtIndexPath to tell the view to update its layout after you ahve set the text.
In iOS 10, a bound of view hasn't initialized in viewDidLoad or awakeFromNib as before, so functions based on the view's bound don't work in viewDidLoad or awakeFromNib.
You should use it in viewDidAppear or when view's bound has certainly been initialized.
Works for me (Swift 5):
class VerticallyCenteredTextView: UITextView {
override var contentSize: CGSize {
didSet {
var topCorrection = (bounds.size.height - contentSize.height * zoomScale) / 2.0
topCorrection = max(0, topCorrection)
contentInset = UIEdgeInsets(top: topCorrection, left: 0, bottom: 0, right: 0)
}
}
}
The source - https://geek-is-stupid.github.io/2017-05-15-how-to-center-text-vertically-in-a-uitextview/
I have a problem with my textViews, because when they appear, always appear scrolled to the bottom, I read here that is a problem that occurs when the textview has constraints, and the solution is set the isScrollEnabled to false and in the didAppear set to true, but because the superview of my textview is a cell in a collectionView, I don't know how to solve this
BTW, I'm using swift 3 and XCode 8
edit: Sorry, I'm not using a nib
I suggest to override prepareForReuse to make any changes before the cell will be visible.
I just solved this, but i did a lot of things, i'm new in ios programming and i don't understand very well a lot of things, but this is how i did it.
To make a textView scrolls to top in a collectionView in my view controller i search for any textViews there and when find it, i set the contentOffset, for the first cell i used the viewdidlayoutsubviews, but for the other cell i had to use the willDisplay and didEndDisplaying, making exactly the same:
let container = collectionView.subviews[0].subviews
for v in container {
if let fView = v as? UITextView {
fView.contentOffset = CGPoint(x: 0,y :0)
}
}
I enter to the cell subviews directly, and set is contentOffset, but the trick is to reload the cell in the cellForItemAt, just like this:
collectionView.reloadItems(at: [indexPath])
and thats it, i hope this helps some one and thanks for your answers.
I have a very peculiar situation and want to know why its happening. I have an edit box and button in a view that I put into a tableview's tableHeaderView property. I call this view InputToListCell.
Now when the view extends UIView I get the following:
i.e all I change in the code is:
class InputToListCell: UIView{
//Code Here
}
I then change InputToListCell to extend UITableViewCell and get the following:
i.e
class InputToListCell: UITableViewCell{
//Code Here
}
Why is this behaviour occurring? I cant see why because UITableViewCell extends UIView. Any thoughts?
Update:
Based on a comment made here are the constraints for the InputToListCell:
I basically pin both the edit text's and Add buttons constraints to the margin, except for the edit text's trailing value.
In short
Use UITableViewCell for table view elements.
self.tableView.tableHeaderView =
tableView.dequeueReusableCellWithIdentifier("sectionIdentifier")
Discussion
Using UITableViewCell objects for all table view elements not only provide an umbrella behavior when presented inside a UITableView, but will also allow loading from a .storyboard or .xib, an added bonus and cohesion.
Thus, even though tableHeaderView (and viewForHeaderInSection for that matter) is informally just a UIView, you can return a UITableViewCell. According to this post, to take advantage of Autolayout in tableHeaderView, you need to do a bit of gymnastics:
if let tableHeaderView = tableView.dequeueReusableCellWithIdentifier("tableHeaderViewIdentifier") {
tableHeaderView.setNeedsLayout()
tableHeaderView.layoutIfNeeded()
let height = tableHeaderView.systemLayoutSizeFittingSize(UILayoutFittingCompressedSize).height
var frame = tableHeaderView.frame
frame.size.height = height
tableHeaderView.frame = frame
self.tableView.tableHeaderView = tableHeaderView
}
From a different post:
For a complete example on how to use .storyboard or .xib for headers, including an Xcode project, see https://stackoverflow.com/a/32261262/218152
I have created a test project in order to verify this problem. In the project storyboard I have two scenes. One scene is based on the initial ViewController that was added to the single view application when the project was created. The second scene was created by dragging a UITableViewController onto the storyboard.
In both scenes, I believe I have configured the prototype cell so it should auto size. When I set the initial ViewController to the one based on the UIViewController, the UITableViewCell do not show / size correctly. (See below)
However, when I set the initial ViewController to the one based on the UITableViewController, everything works fine. (see below)
The code / project is very simple and I am hoping someone has seen this and can tell me why the auto size for the UITableViewCell is not working correctly when the class is based on UIViewController verses a UITableViewController. Any help would be greatly appreciated. It appears I cannot upload the project here so I will try to get it uploaded to another location and update the question with a link.
To answer standard questions
Both prototype cells have two UILabel in them
The first UILabel has left, top, right and bottom constraints specified.
The second UILabel has left, right and bottom constraints specified.
Both classes set the estimatedRowHeight to a number and the rowHeight to UITableViewAutomaticDimension
All UILabel have their lines property set to 0
The first UILabel in both scenes has its Line Breaks set to Word Wrap
The second UILabel in both scenes has its Line Breaks set to Truncate Tail.
Below is a screen shot of the scene in interface builder. Left is based in UIViewController, right is based on UITableViewController
Here is a link to the code I hope: Sample Project
So I have found the "silver bullet" that seems to resolve a great number of challenges regarding auto layout of prototype cells.
In the cellForRowAtIndexPath function I added the following line of code right before I return the cell:
lobj_NearbyLocationEntry!.layoutIfNeeded()
(lobj_NearbyLocationEntry is the name of my cell variable I am returning.)
When I do this, the auto layout for my table works fine. On a side note, I found a defect in the code that uses the UITableViewController also. Once the data loads and it all looks good, if you scroll down and then scroll back up, you will see a couple of the cells are now not laid out correctly. Putting this line of code in that view controller's code also resolved that layout problem.
I hope this helps many people who are sitting there trying to figure out why their app is not auto laying out a tableView cell correctly. :)
For Me It Works
Give upper UILabel (right,top,left) constraints
Give lower UILabel (right,top,left,bottom) constraints
In Custom UITableViewcell
override func awakeFromNib() {
super.awakeFromNib()
up.lineBreakMode = NSLineBreakMode.ByWordWrapping // Label outlet
down.lineBreakMode = NSLineBreakMode.ByWordWrapping // Label outlet
up.numberOfLines = 0
down.numberOfLines = 0
// Initialization code
}
EDIT
InUITableViewController
override func tableView(tableView: UITableView, heightForRowAtIndexPath indexPath: NSIndexPath) -> CGFloat {
return UITableViewAutomaticDimension
}
In UIViewController
func tableView(tableView: UITableView, heightForRowAtIndexPath indexPath: NSIndexPath) -> CGFloat {
return UITableViewAutomaticDimension
}
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];