How to make a reader like the kindle app? - ios

I'd like to make a reader that behaves like Amazon's Kindle app. Specifically, I want to present a bunch of justified text in paragraphs, one column per page, and have it scroll between pages like the Kindle app does.
Let's assume I have the text in a simple format, like a text file per chapter, or even a string hard-coded in memory per chapter.
They're obviously using Core Text. Are they using a paged scroll view? Would that run in to memory problems for large books?

My initial thought is that they are using a UITextView to display a large amount of text, this kind of view allows you to add margin, padding, text and for iOS 6 you could use something like NSParagraphStyle to give styling to the text, the easy approach would be to create a really long text in different UITextViews within a UIScrollView and that would give you a nice result however if memory is a concern and the iOS version is not a problem I'd recommend using UICollectionViews, you can make each page a "cell" and then write some custom layout so when the user is scrolling the book you can actually just instanciate the page the user is using at a certain moment
The cool thing about NSCollectionView is that it behaves exactly like a UITableView so it's very memory efficient, something that is not on the screen is not displayed, and if it's going to be displayed then it's loaded.
hope this can give you some insight on the matter.

I ended up making something completely custom. It consists of 3 views, a left main and right view.
The view controller renders the text on the main view using Core Text, and calculates the size of the text frames (and therefore the number of pages) for each page in the current chapter.
If the user taps or drags right or left, the view controller will render one of the side views and let you drag it on. When you finish dragging or complete the tap action, it animates the pages into place, then swaps the main view with the one you dragged on.
The advantage to this method over using a UICollectionView is that it's very expensive to calculate the exact contents that should be displayed on a given page in a deterministic way, as a table/collection view would require. This way allows me to render the text of any chapter, and go back or forward lazily without laying out the whole book at once.

Related

Advantages of tableView vs. creating UI elements in code?

I have a feature that allows users to tap the side of the screen to go through content (like instagram stories). The information is presented in different formats:
example of screen types
Currently, I am just creating UI elements (through CGRect) and placing the content on the screen according to the template type that comes in. There are many screen types and the canvas has to repaint with each switch. Should I be utilizing tableView for speed (development or otherwise)?
Repainting on condition
Is this bad practice to constantly reload and recreate items with each tap?
A table view is a vertically scrolling sequence of "cells" and has nothing in common with the situation you are describing, as far as I can see.
Actually what you are describing might be a UIPageViewController, which lets you "page" through entire screens of material and yet create each "page" dynamically according to what comes "next" in the series.
Each page would be its own view controller and could configure its own views. There would be no subviews to remove; rather, the "next" view is just sitting there waiting to be asked for. Each time the user changes the "page", the old screenful of views just goes away after sliding off the screen.

Should I choose ViewController or TableViewController?

New to Swift. I am trying to write a recipe-sharing app for fun. One of the features is to let users create a new recipe. On this page, users should be able to give an intro to the recipe to be created, upload an image THEN add a LIST of ingredients dynamically (as we have no idea how many ingredients in total beforehand).
I have created a UIViewController, which includes a UIViewTable, an image view and a "add another ingredient" button. I have created a class for the ingredient. And when the "add" button is pressed, a new "Ingredient" cell will be added to the table. However, I found that adjusting the UIViewTable height dynamically is quite hard.
I want my table to adjust its height according to the number of cells (rows). I haven't found much useful info online.
Or maybe I should've not even used this structure. Instead, just use UITableController (The entire page is a table)? But I got confused that some of the elements (image view, submit a recipe button, recipe-intro textfield etc) will be only created once. Why do I bother making them as prototype cells and add them to my view programmatically?
Thanks in advance!
First of all, welcome to Swift!
You put a few questions together, I will try to answer them one by one. Let's start with the simple stuff.
Don't try to change the height of UITableView based on the number of items. If you want to achieve similar functionality, take a look at UIStackView. Set fixed size for the tableView, ideally with constraints using auto layout.
UITableView is supposed to fill specified space and scroll items inside or show cell on top if there are not enough cells to cover all space.
UITableView is highly optimized to scroll over huge amount of cells as the cells are reused on the background. If you are new to the iOS world, take a look at this function https://developer.apple.com/documentation/uikit/uitableviewcell/1623223-prepareforreuse it can save you hours of debugging (I have been there)
UITableView vs UITableController
UITableController can save you a few lines of code, but using UITableView inside of UIViewController can give you more freedom and save you refactoring if your app is likely to change in the future. There is no specific advantage of UITableController
If you want to provide the extra elements (image view, submit button, text field etc), you can use several methods and this is where the UIViewController with your own UITableView comes in handy.
You can put some buttons, like a plus icon or "Done" button into the navigation bar, as the native Calendar app does.
You can put the static content (intro text field, image view) above the table view (visible always). Use constraints to place the static content on the viewController.view and constraint the table view under your static content. The table view will take less space on the view keeping the space for your content.
Insert your static content as a table view header (will scroll out with the content). Search "HeaderView" here on stack overflow to see how to achieve that.
Place your content over the tableView. If your button is small (rounded), you can place it over the tableView, eg. Twitter uses this for a new tween button.
Hope this answer your questions. Cheers!

Create a listing inside of a ScrollView

I am writing a Swift app, and on my main screen I have a long scrollview with several regions of content in it (upcoming events, announcements, and then featured products, and finally some basic info). So it's this really long scroll, and you can swipe down to the bottom.
So visualize 4 boxes, if you will, stacked vertically.
The 3rd box shows featured products. This can be anywhere from 1 to 30 items, depending upon any filters the user has in their settings.
My first try was using a UITableView for region#3 inside of this parent scrollview, but the problem is it only shows the first few items/rows and then the rest you scroll inside the table (which is the default/natural behavior of a table, right?). Unfortunately, the requirement I have is that the inner table can't scroll - it needs to display everything at once and you have to scroll (in the main UIScrollView) to get to the bottom (not scroll inside the inner uitableview scroll). Also, everyone seems to say don't use UITableView inside of a scroll.
So how do I create some sort of list where I create one template (like how you would in a xib/tablecell, and then assign a data source to it, and then repeat down without scrolling? Should I use a tableview after all, and just make the height of it very high and turn scrolling off?
Do I somehow instantiate xibs in a for loop and assign them dynamically to some view?
Thanks so much!
Sounds like you want a Table View with Grouped style. That would make it fairly easy to keep your "4 boxes" segregated, and your "3rd box" would simply be 1 to 30 rows in that section.
On note: you don't want to have a "very tall" table view - or any other type of view, for that matter. You want to allow iOS to manage memory for you, and to load and display only those parts of your content that is visible at any one time.
In other words, use a table view like its designed to be used :)

Presenting a Text Stream in iOS

i need to present a running text stream in my apps, i got the running text from my server and i can see it using NSLog that the stream is running. The text is change and have a new line every second.
Since i'm newbie in iOS i already made a research and there are couples that i still confuse :
1.Between UITableView and UIScrollView, which one you recommended regarding the performance?
2.What is the right library to use?is it llike NSStream or i just present it to my UITable?
Will appreciate if you can have a snippet code or tutorial for this.
Thanks...
I don't have time to write the code, as it's not simple.
You will want to create a UITextView and append the string to the text view as you recieve new content.
UITextView is a subclass of UIScrollView, so you can use all UIScrollView operations on it, including scrolling down to the bottom as new content is added. This is the best way to have good performance, as UIScrollView and UITextView are both tightly integrated into the graphics hardware on the device.
If the text is really big (hundreds of megabytes) then you should also delete old text from the top of the text view as you add new text to the end.
Just use the code you have now, but instead of NSLog(), append it to the UITextView.
IMHO, UITableView would be ideal choice, since it's well optimized to reuse its cells. If you use scroll view, 3600 lines (that's 1 hour log) will probably end up with 3600 text views (or labels), while for table view, it would always be the number of rows visible on the screen.
For data model, I think you can just use a big array, which is continuously fetched with data from the server, possibly truncated when it gets too big (I mean deleting the very old lines).
Remember the rule of optimization: get it working first before optimizing it.

Construction of long texts in chapters inside UIScrollView

One of the views of my iOS app contains a quite long text inside a UIScrollView, with an user guide. The text is localized in three languages and splitted in chapters with titles.
I'm using multiple UITextView. At the end of each view constructor I'm adding it to the main view and I call:
[self autoSizeTextView:myuitexview];
to make it resize accordingly to the length of the text for the language in use.
The next UITextView is positioned calculating the position and the height of the previous one, to have them presented in order and not overlapped.
This is a tedious job! Considering that I don't want to use a web view (to keep good performances), is there an another way to display a long and not mono-block text (with chapters and a not so simple layout) on iOS?
Posting from my comment:
Is there a reason for not using UITableView? I'd suggest, instead of doing this in a UIScrollView, do it in a UITableView. It'd save your app some resources to do your positioning calculations, and the lazy loading of paragraphs will be taken care of by the cellForRowAtIndexPath, which will keep the app very responsive
#flip79: glad it helped!

Resources