- Add
LDOTiledView
to your view hierarchy (you probably want to embed it into aUIScrollView
). - Set
maximumZoomLevel
,imageSize
andtileSize
(details see below). - Implement the only method of
LDOTiledViewDataSource
func tiledView(_ tiledView: LDOTiledView, tileForRow row: Int, column: Int, zoomLevel: Int) -> UIImage?
UIScrollView Setup:
- Embed the
LDOTiledView
in aUIScrollView
. - Constrain its leading, top, trailing and bottom space to its container/superview (the
UIScrollView
). - Setup and implement a
UIScrollViewDelegate
. - Return the
LDOTiledView
instance fromviewForZooming(in scrollView: UIScrollView) -> UIView?
.
If you want to see an implementation of this, please check out the example app.
A typical use case for LDOTiledView
is to be able to zoom into an image.
This is done by embedding it in a UIScrollView
.
However UIScrollView.zoomScale
refers to the content size (as area) and thus grows exponentially.
Repeatadly doubling the size of an image, the zoom scale grows as follows: 1, 2, 4, 8.
LDOTiledView
works with the more intuitive concept of zoom levels.
In its smallest resolution an image is at zoom level 1.
At twice the size it's at level 2, doubling the size again is level 3 and so on.
The zoom level grows linearly and at every level the image is twice as large as on the previous level.
This is also how tiled maps (Google Maps, OpenStreetMaps, etc) work.
The image size refers to the image dimensions in points at the smallest zoom level.
The following table illustrates the relationship between image size and zoom level.
Zoom Level | Image Size [pt] | 2x Retina [px] | 3x Retina [px] |
---|---|---|---|
1 | 410 x 890 | 820 x 1780 | 1230 x 2670 |
2 | 820 x 1780 | 1640 x 3560 | 2460 x 5340 |
3 | 1230 x 2670 | 2460 x 5340 | 3690 x 8010 |
4 | 1640 x 3560 | 3280 x 7120 | 4920 x 10680 |
That means to be able to zoom a full screen image on an iPhone Xs Max four times, you need a 52 MP source image.
In this example maximumZoomLevel
would be 4 and imageSize
would be 410 x 890.
The general idea behind CATiledLayer
and thus LDOTiledView
is that instead of loading a huge image into memory at once, the image is split up in smaller sqares and only the squares that are currently visible are loaded.
That means no matter how large the image is, roughly the same number of small squares are loaded at any given time. As result the memory consumption is (nearly) constant and independant of the image dimensions.
The tile size specifies the size of the small squares you sliced your large image into. It is defined in points. That means if you set your tile size to 256x256, your retina tiles have to be 512x512 px. Consequently non-Retina, Retina and Super Retina images are sliced into the same number of tiles.
A common complaint about the underlying CATiledLayer
is that it sometimes displays black squares instead of image tiles.
In our experience, this is actually not a problem of CATiledLayer
, but caused by a failing image load.
Sometimes UIImage(named:)
will return nil
if it's called too frequently. (This might be caused by the caching performed by UIImage(named:)
, and the fact that the tile loading happens asynchronously.)
Loading the images as Data
and creating the UIImage
from that worked flawlessly for us. YMMV.
While there are no strict requirements on how you create your image tiles, we included a small Ruby script to get you started. It is based on libvips, so be sure to have that installed if you want to use it.
The script uses the input image for the largest zoom level at the highest scale (1x/2x/3x). It then scales the image down for all smaller zoom levels and scales.
The tiles of the earth example were created with this command:
$ ./gen_tiles.rb Example/Demo\ Images/Earth/earth.jpg -scale 2 -scale 3 -levels 4
Level 1 image size: 450 x 450
Check gen_tiles.rb --help
for more details.
To run the example project:
-
git clone https://github.com/lurado/LDOTiledView.git
-
cd LDOTiledView/Example/
-
pod install
-
open LDOTiledView.xcworkspace
-
Trigger Build and then run the current scheme in Xcode
LDOTiledView is available through CocoaPods. To install it, simply add the following line to your Podfile:
pod 'LDOTiledView'
Raschke & Ludwig GbR, https://www.lurado.com/
LDOTiledView is available under the MIT license. See the LICENSE file for more information.
Inspired by and based on JCTiledScrollView.
The earth image in the example project comes from NASA's earth observatory: NASA Earth Observatory image by Robert Simmon, using Suomi NPP VIIRS imagery from NOAA's Environmental Visualization Laboratory. Suomi NPP is the result of a partnership between NASA, NOAA and the Department of Defense