I have a UITableView which allows reordering. In all iOS versions before 11 the cell that is currently reordered is shown properly (just slightly transparent) while dragged.
In iOS 11 instead of the actual cell content, I see a white semi-transparent rectangle.
I searched everywhere but could not find a way to show the actual content. Any ideas anyone?
It seems that the problem was that while the cell is being dragged, all subviews of its contentView get a transparent background.
I fixed it by keeping a reference (as an IBOutlet) to my own background view and setting its backgroundColor in the cell's layoutSubviews. You can do the same for all other views whose backgroundColor you want to preserve.
class QuestionOrderTableViewCell: UITableViewCell {
#IBOutlet weak var bgView: UIView!
override func layoutSubviews() {
super.layoutSubviews()
bgView.backgroundColor = UIColor.black
}
}
Related
I have a UITextView Inside a custom UITableview. Whenever I try to click the tableView Cell, the UITextView Bounds gets Highlighted like this. How can I prevent that highlighting? I've tried to disable isUserInteractionEnabled, isEditable and isSelectable inside tableViewCell.swift file but nothing works.
If you want to have an other UIViews in a cell content view to have a the same color as selection and highlight color then use this
class CustomCell: UITableViewCell {
#IBOutlet var textView: UITextView! {
didSet {
textView.backgroundColor = .clear
}
}
}
I have three child VCs that are added to a parent VC. In one of my child VC, I have a view being loaded from a nib. In that nib, I set up a UITextView with no constraints and disabled scrolling so that it dynamically sizes depending on the text. This all works fine so far, I can enter or remove text from the UITextView and it resizes accordingly.
However, if I switch tabs (child VCs), and return back to the one with my UITextView, my UITextView is now of height 0 (cannot be seen). I'm not sure what is causing this to happen, everything works fine until I switch views and return.
My first thought would be to reconfigure my UITextView on viewDidAppear() when returning to my child VC, except my UITextView outlet and setup method is in a separate UIView subclass so I cannot call viewDidAppear(). I'm not even sure if that would be a fix, just what I would guess.
MyParent.swift: UIViewController
MyChild1.swift: UIViewController
MyChild2.swift: UIViewController
MyChild3.swift: UIViewController
MyView.swift: UIView - Custom View loaded from Nib
(this is where my UITextView outlet is and setup for it)
In MyChild3 for example I create the custom view with:
let view = Bundle.main.loadNibNamed("MyView", owner: self, options: nil)?.first! as! MyView
view.myModel = model
view.configure()
Then, in MyView.swift which is the custom class that the nib uses, I have my UITextView outlet and setup method:
#IBOutlet weak var textView: UITextView!
public func configure() {
configureTextView()
}
private func configureTextView() {
textView.delegate = self
textView.text = myModel.text
textView.isScrollEnabled = false
}
EDIT:
I should mention that my UITextView is a part of a horizontal StackView along with a UIImageView, as follows:
UIImageView
UITextView
When I return to my VC, the UIImageView takes up 100% of the height in the StackView, although before leaving my VC, the UITextView height was sized correctly to its text. After doing Show View Hierarchy, I cannot even find my UITextView anymore, only the UIImageView seems to be in the StackView. I essentially want my UITextView to take up as much height as it needs in the StackView, and the UIImageView take up the rest, but the UIImageView is taking it all up.
I did manage to find this error?
I would try setting content compression resistance of the textView to a higher value, maybe that's what causing ambiguity:
textView.setContentCompressionResistancePriority(UILayoutPriority(rawValue: 999), for: .vertical)
The Problem
I have a UITextView inside of a custom UITableViewCell subclass that is producing some odd behavior.
Here is a gif of the problem I'm seeing (relevant items are colored):
The height resizes correctly, but the full contents of the cell are not shown.
But when I pause execution and print out frames of the following:
Cell
Cell's content view
Text View
the frames are all correct!
Further, when I inspect the view using the view hierarchy debugger, the frames are all correct there too. There is one difference when using the view debugger though, and that is that I'm able to view the contents of the text view.
Here is what I see on the simulator vs in the debugger:
There seems to be an extraneous cell separator at the point where the yellow stops. Other than that, I can't find any sort of indicator of why the cell is not expanding past its original height.
My Code
In the storyboard, the UITextView has top, bottom and trailing constraints to the cell's content view, and a vertical spacing constraint to the UIImageView. The UIImageView has a fixed width and has a leading constraint to the cell's content view. I believe my constraints are set up correctly. Oh yeah, and scrolling is disabled on the UITextView.
As for code, I have a custom protocol that informs the table view controller when the notes field has changed:
protocol AddContactCellDelegate {
func notesViewDidChange(textView: UITextView)
}
Here is the relevant code from my UITableViewCell subclass:
class AddContactCell: UITableViewCell, UITextViewDelegate {
var delegate: AddContactCellDelegate?
func textViewDidChange(textView: UITextView) {
delegate?.notesViewDidChange(textView)
}
}
and from my UITableViewController subclass:
class AddContactViewController: UITableViewController, AddContactCellDelegate {
override func viewDidLoad() {
super.viewDidLoad()
tableView.estimatedRowHeight = 60.0
tableView.rowHeight = UITableViewAutomaticDimension
}
override func tableView(tableView: UITableView, cellForRowAtIndexPath indexPath: NSIndexPath) -> UITableViewCell {
let row = rows[indexPath.row]
let cell = tableView.dequeueReusableCellWithIdentifier(row.cellIdentifier, forIndexPath: indexPath) as! AddContactCell
cell.configureForRow(row)
cell.delegate = self
return cell
}
func notesViewDidChange(textView: UITextView) {
tableView.beginUpdates()
tableView.endUpdates()
}
}
Discussion
I've tried adding setNeedsLayout(), in to either the cell, the cell's content view, the tableview, or the textview, in just about every place, to no avail.
I rebuilt the entire view in the storyboard from scratch, same thing.
I tried creating a bare-bones project that has basically only the code above, and the sizing works correctly.
I've ruled out tons of other variables as being the culprit (for example, the tableview is in a container view, but the behavior persists without that).
One final weird point is that sometimes if I scroll the notes cell off the screen, leave the page, and come back again, everything looks as it should. The cell is fully resized and everything is visible. However, the problem resumes as soon as the text view goes to the next line, this time with all the previous text visible but none of the additional text.
If anyone has any ideas on what I might try next, it would be extremely helpful. Thanks!
Thanks to Steve asking for an example project that exhibits the behavior, I was able to figure out what is causing this issue.
To get the rounded corner effect, I had been using a layer mask on my cells. The mask uses the bounds of the cell to calculate its path, so when the cell updated itself to reflect the height of the text view, the mask was still in place and covered up the rest of the cell.
I didn't catch it because the rounding implementation was abstracted away in an extension. Whoops!
I am using a UITableView and using the UITableViewCell Subtitle Style that is provided by Apple.
I am also using the Preferred Fonts so that they work with the Dynamic Type. If the user goes to Settings and changes the UI font size, it also affects the font in my view.
I am also allowing it to dynamically choose the row height based on the length of the text using row.estimatedRowHeight. This is great because with larger fonts and having multiple line text, the cells will adjust accordingly.
Using images is what is the problem. Images are of different sizes so scale them down. The scaling is sort of a hit or miss for the automatic cell height. It may not be done in time so the system calculation of the height may compute wrong.
My question then is, can I manually add constraints to the UITableViewCell's imageView property so that it has a set width and height of 88 pixels. This way, even if the picture isn't done resizing yet, it will at least calculate the height of the containing cell properly?
OR, maybe better to ask this: Is it possible to have a static width/height for the image when the cell and text labels resize dynamically based on content length and size?
Thanks!
There is a good library for creating UI dynamically. It's called Cartography
https://github.com/robb/Cartography
Here code that helps to create resizable cell by image view height:
import UIKit
import Cartography
class TableViewCell: UITableViewCell {
#IBOutlet weak var resizableImage: UIImageView!
override func awakeFromNib() {
super.awakeFromNib()
// Initialization code
}
override func setSelected(selected: Bool, animated: Bool) {
super.setSelected(selected, animated: animated)
}
func configurate() {
constrain(self.resizableImage) { view1 in
view1.width == view1.height
view1.top == view1.superview!.top
view1.bottom == view1.superview!.bottom
}
constrain(self.resizableImage) { view1 in
view1.height == 88
}
}
}
I have a custom tableviewcell with the standard disclosure indicator positioned in the centre vertically by default. How can I move this standard disclosure indicator vertically like in the iOS mail app?
You can adjust the position of the default accessory by subclassing your cell and finding the UIButton in the cell's subviews (which represents the indicator) and holding a reference to it. You can then simply update the frame of the accessoryButton in layoutSubviews or wherever you choose like so:
class CellSubclass: UITableViewCell {
var accessoryButton: UIButton?
override func awakeFromNib() {
super.awakeFromNib()
accessoryType = .DisclosureIndicator
accessoryButton = subviews.flatMap { $0 as? UIButton }.first
}
override func layoutSubviews() {
super.layoutSubviews()
accessoryButton?.frame.origin.y = 8
}
}
You can not move standard disclosure indicator vertically.
If you want to achieve this functionality, then you need to use your custom cell and use image of disclosure indicator and then you can set this image with button on where ever you want to place.
Or you can use view also as a accessory indicator and add as a subview of UITableViewCell
[cell.contentView addSubview:aView];
You can read more over here disclosure indicator
You can modify the Layout Margins to Fixed on TableViewCell in the .xib and then set the right margin to the desired value.