iOS UITableView with dynamic text and images rendered together (NSAttributedString + images)
This post may get you going in the right direction for calculating row height:
Retrieve custom prototype cell height from storyboard?
As for performance, have you run Time Profiler to narrow down what is causing lag?
UITextView with long text using PageControl
Ok,
Here is my solution :
https://github.com/rorlich/LongTextView
i'm guessing i will need to improve it in the future but it's a good start for now
Render an arbitrarily large NSAttributedString
You could use a UITableView and split the NSAttributedString
into an array of substrings that would each fit a cell's label width. The table view's data source would index into the array of substrings to determine which line of the original string should be placed in each cell.
Retrieve custom prototype cell height from storyboard?
For static (non-data-driven) height, you can just dequeue the cell once and store the height:
- (CGFloat)tableView:(UITableView *)tableView heightForRowAtIndexPath:(NSIndexPath *)indexPath
{
static NSNumber *height;
if (!height) {
UITableViewCell *cell = [self.tableView dequeueReusableCellWithIdentifier:@"MyCustomCell"];
height = @(cell.bounds.size.height);
}
return [height floatValue];
}
For dynamic (data-driven) height, you can store a prototype cell in the view controller and add a method to the cell's class that calculates the height, taking into account the default content of the prototype instance, such as subview placement, fonts, etc.:
- (MyCustomCell *)prototypeCell
{
if (!_prototypeCell) {
_prototypeCell = [self.tableView dequeueReusableCellWithIdentifier:@"MyCustomCell"];
}
return _prototypeCell;
}
- (CGFloat)tableView:(UITableView *)tableView heightForRowAtIndexPath:(NSIndexPath *)indexPath
{
// Data for the cell, e.g. text for label
id myData = [self myDataForIndexPath:indexPath];
// Prototype knows how to calculate its height for the given data
return [self.prototypeCell myHeightForData:myData];
}
Of course, if you're using custom height, you probably have multiple cell prototypes, so you'd store them in a dictionary or something.
As far as I can tell, the table view doesn't attempt to reuse the prototype, presumably because it was dequeued outside of cellForRowAtIndexPath:
. This approach has worked very well for us because it allows the designer to modify cells layouts in the storyboard without requiring any code changes.
Edit: clarified the meaning of sample code and added an example for the case of static height.
UITableViewRowAction image for title
iOS 11.0
Swift
Apple introduced flexible way to declare row actions with great benefits.
extension ViewController: UITableViewDelegate {
func tableView(_ tableView: UITableView, trailingSwipeActionsConfigurationForRowAt indexPath: IndexPath) -> UISwipeActionsConfiguration? {
let askAction = UIContextualAction(style: .normal, title: nil) { action, view, complete in
print("Ask!")
complete(true)
}
// here set your image and background color
askAction.image = IMAGE
askAction.backgroundColor = .darkGray
let blockAction = UIContextualAction(style: .destructive, title: "Block") { action, view, complete in
print("Block")
complete(true)
}
return UISwipeActionsConfiguration(actions: [blockAction, askAction])
}
func tableView(_ tableView: UITableView, willDisplay cell: UITableViewCell, forRowAt indexPath: IndexPath) {
cell.textLabel?.text = "row: \(indexPath.row)"
}
}
Example:
iOS 8.0
You need to set UIImage to backgroundColor of row action, concretely by:
Swift:
UIColor(patternImage: UIImage(named: "IMAGE_NAME"))
Objective-C:
[UIColor colorWithPatternImage:[UIImage imageNamed:@"IMAGE_NAME"]];
Displaying Lots Of RichText : Choosing the best option
So if I am reading this right, you want the forum posts of a given topic to be cells of a UITableView and the cells need rich formatting?
Assuming this is correct, I imagine each post will take up a lot of the screen (large cell height). In this case, having a UIWebView as a subview might not be as bad performance-wise as you might think. UITableView reuses cells so really only the visible cells need be loaded into memory.
I'm also assuming you are able to access the forum via an API, right? In which case, you should be able to pre-load data immediately prior to loading the view and the UIWebViews will only be used for formatting. You can even load a CSS file from your app bundle when you loadHTMLString into your UIWebView so you're not loading that from a server every time.
All that being said, if you did have a lot of concurrently visible cells it might be a different story and I'd maybe consider only showing plain text in the UITableView index and displaying the rich formatting only when the user taps the cell to view the single post. This might also be better from a design standpoint as having a ton of differently formatted cells on screen could potentially end up looking a bit sloppy.
Also, this may be obvious (especially since you seem to be both performance and design conscious) but please don't use UIWebView for UI controls. Any time I see a UIWebView tab bar or fake navigation bar I cringe (ack, Netflix). For formatting though, a lot times it's the only way to fly if you're loading a lot of dynamic content from a server.
Related Topics
Phonegap on iOS with Absolute Path Urls for Assets
What Is the Swift Preprocessor Equivalent to iOS Version Check Comparison
Adding Swift Files to Test Target Not Fixing Unit Tests
Core Data Predicate:Unimplemented SQL Generation for Predicate
iOS Swift 3:Convert "Yyyy-Mm-Dd'T'Hh:Mm:Ssz" Format String to Date Object
Calling Instance Method During Initialization in Swift
iOS Client Certificates and Mobile Device Management
How to Control Avassetwriter to Write at the Correct Fps
How to Read Incoming Sms by Using Application in iOS
How to Determine If a User Has an iOS App Installed
Libz.Dylib Versus Libz.1.2.3.Dylib Versus Libz.1.2.5.Dylib
How to Draw on an Image in Swift
How to Permanently Allow Usage of Camera on Trusted Websites with iOS - Safari