Skip to content
Tristus1er edited this page Aug 26, 2013 · 12 revisions

The TileView widget is a subclass of ViewGroup that provides a mechanism to asynchronously display tile-based images, with additional functionality for 2D dragging, flinging, pinch or double-tap to zoom, adding overlaying Views (markers), built-in Hot Spot support, dynamic path drawing, multiple levels of detail, and support for any relative positioning or coordinate system.

Following the steps to follow to create a new project.

Setup the project

Create a new project

In Eclipse : Menu File/New/Android Application Project

Create Android Project

Then fill the name and the package of the application. Exemple :

Create Android Project

Press Next button for the next screens, till the end (Finish Button).

Add the DiskLruCache lib

To add the library [Jake Wharton's DiskLruCache] (https://github.com/JakeWharton/DiskLruCache) to the project do the following steps:

  • Download the jar Here
  • Then add the downloaded file to the folder "libs" of your project

Add the TitleView code

  • Download the current project and put the src files in your src folder
  • Then in Eclipse, refresh your project

You'll have the following:

Full Project

Generate the pictures

Install Image Magick

Image Magick is a tool that will allow us to generate all the needed pictures (all the tiles).

Generate the tiles

For this exemple we will use a big world map.

Then split it using Image Magick: you can use the following script (under Windows) to generate the nedded pictures.
Note: _J:\installed\ImageMagick-6.8.6-Q16_ is the folder where I have installed Image Magic, the best: add it to your PATH:

@echo off

set filename=big-world-map.gif

set /a tilesize=256
set /a downsamplesize=1000

set tilesfolder=tiles
set downsamplesfolder=downsamples

mkdir %tilesfolder% %downsamplesfolder%

echo Generate the smaller map images (divide by 2 each time)
echo Generate 1/2
J:\installed\ImageMagick-6.8.6-Q16\convert %filename% -resize 50%%  map500.jpg
echo Generate 1/4
J:\installed\ImageMagick-6.8.6-Q16\convert %filename% -resize 25%%  map250.jpg
echo Generate 1/8
J:\installed\ImageMagick-6.8.6-Q16\convert %filename% -resize 12.5%%  map125.jpg

echo Generate the smaller map images (divide by 2 each time)
J:\installed\ImageMagick-6.8.6-Q16\convert %filename% -resize %downsamplesize%x%downsamplesize%  ./%downsamplesfolder%/map.png


echo Generate the downsample map
J:\installed\ImageMagick-6.8.6-Q16\convert %filename% -crop %tilesize%x%tilesize% -set filename:tile "%%[fx:page.x/%tilesize%]_%%[fx:page.y/%tilesize%]" +repage +adjoin "./%tilesfolder%/1000_%%[filename:tile].png"

echo Generate the tile for the half size map
J:\installed\ImageMagick-6.8.6-Q16\convert map500.jpg -crop %tilesize%x%tilesize% -set filename:tile "%%[fx:page.x/%tilesize%]_%%[fx:page.y/%tilesize%]" +repage +adjoin "./%tilesfolder%/500_%%[filename:tile].png"

echo Generate the tile for the 1/4 size map
J:\installed\ImageMagick-6.8.6-Q16\convert map250.jpg -crop %tilesize%x%tilesize% -set filename:tile "%%[fx:page.x/%tilesize%]_%%[fx:page.y/%tilesize%]" +repage +adjoin "./%tilesfolder%/250_%%[filename:tile].png"

echo Generate the tile for the 1/8 size map
J:\installed\ImageMagick-6.8.6-Q16\convert map125.jpg -crop %tilesize%x%tilesize% -set filename:tile "%%[fx:page.x/%tilesize%]_%%[fx:page.y/%tilesize%]" +repage +adjoin "./%tilesfolder%/125_%%[filename:tile].png"

echo DONE
pause

Then put the generated files (folders downsamples AND tiles) in the assets folder. Under Eclipse, refresh your project, you'll now have the following.

Full Project with content

Write our code

Minimum code

The minimum implementation requires that setSize be called, and at least one detail level (tile set) is registered.

Edit the MainActivity.java class file

Replace the current code:

	@Override
	protected void onCreate(Bundle savedInstanceState) {
		super.onCreate(savedInstanceState);
		setContentView(R.layout.activity_main);
	}
 

By:

	TileView tileView;

	@Override
	protected void onCreate(Bundle savedInstanceState) {
		super.onCreate(savedInstanceState);

		// Create our TileView
		tileView = new TileView(this);
		
		// Set the minimum parameters
		tileView.setSize(6252,4087);
		tileView.addDetailLevel(1f, "tiles/1000_%col%_%row%.png", "downsamples/map.png");

		// Add the view to display it
		setContentView(tileView);
	}

Multiple zoom levels

As we have generated 4 zoom level of tiles we can use them:
Replace the previous code:

		// Set the minimum parameters
		tileView.setSize(6252,4087);
		tileView.addDetailLevel(1f, "tiles/1000_%col%_%row%.png", "downsamples/map.png");

By:

		tileView.setSize(6252,4087);
		tileView.addDetailLevel(1f, "tiles/1000_%col%_%row%.png", "downsamples/map.png");
		tileView.addDetailLevel(0.5f, "tiles/500_%col%_%row%.png", "downsamples/map.png");
		tileView.addDetailLevel(0.25f, "tiles/250_%col%_%row%.png", "downsamples/map.png");
		tileView.addDetailLevel(0.125f, "tiles/125_%col%_%row%.png", "downsamples/map.png");

Center and default Zoom

Now we can center our map by default, and set the default zoom by adding the following code at the end of the method onCreate:

		// use pixel coordinates to roughly center it
		// they are calculated against the "full" size of the mapView 
		// i.e., the largest zoom level as it would be rendered at a scale of 1.0f
		tileView.moveToAndCenter( 6252, 4087 );
		tileView.slideToAndCenter( 6252, 4087 );
		
		// Set the default zoom (zoom out by 4 => 1/4 = 0.25)
		tileView.setScale( 0.25 );

Add markers

To add some markers on our map:

  • Add the following image Full Project to the res\drawable-hdpi folder
  • Then add the following code:
		ImageView markerA = new ImageView(this);
		markerA.setImageResource(R.drawable.maps_marker_blue);
		markerA.setTag("Nice");

		ImageView markerB = new ImageView(this);
		markerB.setImageResource(R.drawable.maps_marker_blue);
		markerB.setTag("Paris");

		tileView.addMarker(markerA, 3245, 2056, -0.5f, -1.0f);
		tileView.addMarker(markerB, 3162, 1942, -0.5f, -1.0f);

You can also set some listeners on the click over the markers using:

		tileView.addMarkerEventListener(new MarkerEventListener(){
		  @Override
		  public void onMarkerTap( View view, int x, int y ){
		    Log.d("Marker Event", "marker tag = " + view.getTag() );
		  }
		});

Use Geographic coordinate system

If you want to use Geographic coordinate system, you can define the relative bounds of your map. You must set the top left and bottom right bounds using this code:

tileView.defineRelativeBounds( 42.379676, -71.094919, 42.346550, -71.040280);

After this line, all the coordinates will use the Geographic coordinate system and no more the pixel based coordonate.

Activate the cache

You can activate the cache is you are using remote pictures with the following code:

tileView.setCacheEnabled( true );
Clone this wiki locally