We can draw text, graphics, and animations in a page of HTML5.
The page can be displayed by both Android and Apple iOS,
so you only have to write it once.
The page is displayed in a
WebView
object in Android,
and in a
UIWebView
object in iOS.
These objects act as tiny web browsers.
Android documentation:
class
WebView
,
Building
Web Apps in WebView,
and
Debugging
Web Apps.
iOS documentation: see
this example.
In the page of HTML5,
the graphics are drawn in the language JavaScript using a
canvas
object.
See the
HTML5
canvas
tutorial.
The page of HTML or HTML5 displayed by a
WebView
can come from one of three sources:
.java
file (exercise 5)MainActivity.java
:
onCreate
configures the
WebView
object.
activity_main.xml
creates the
WebView
.
res/values/dimens/dimens.xml
res/values-w820dp/dimens.xml
for wider screens.
japan.html
in the
assets
folder.
Multiplication by π/180 converts
degrees
to
radians.
AndroidManifest.xml
:
a
WebView
requires the
<uses-permission>
element (exercise 4).
build.gradle
(Module: app)
Select the
app
folder at the top of the Android Studio
project
view
and pull down
File →
New →
Folder →
Assets Folder
Creates a source root for assets which will be included in the APK.
☐ Change Folder Location
Target Source Set: main (vs. debug or release)
Finish
Control-click on the
assets
folder you just created in the Android Studio
project
view
and select
New →
File
Enter a new file name: japan.html
OK
activity_main.xml
specified that the
WebView
should occupy the entire
RelativeLayout
(“match
parent, match
parent”),
but it doesn’t.
The
RelativeLayout
is blue,
and part of it is visible because of its padding specified in
activity_main.xml
.
Set the horizontal and vertical padding to
0dp
in
dimens.xml
.
japan.html
,
change
<BODY STYLE = "background-color: cyan;" onLoad = "load();">to
<BODY STYLE = " background-color: cyan; margin-left: 0px; margin-top: 0px; " onLoad = "load();">
alert
prints the dimensions of the canvas in dp:
originaly 328 × 527
and now 360 × 559.
window.innerWidth
and
window.innerHeight
from receiving their correct values until a fraction of a second after
load
is called.
I fixed it by changing
load
to the following.
//This function is called when the web page has been loaded into the WebView. function load() { window.setTimeout(load2, 300); //milliseconds } //This function is called 300 milliseconds after the web page has been loaded //into the WebView. function load2() { try { var canvas = document.getElementById("flag"); //etc.: all the code that was originally in load.
onCreate
,
change
webView.loadUrl("file:///android_asset/japan.html");to
webView.loadUrl("http://www.nyt.com/"); //New York TimesAdd the following element to the
AndroidManifest.xml
file immediately before the
<application>
element.
(It’s already added.)
<uses-permission android:name="android.permission.INTERNET" />Then change it back.
onCreate
,
comment out the call to
loadUrl
and comment in the call to
loadData
.
load
function do something more interesting.
Change the page of HTML to the following.
See the
Manhattan project
and
HTML5 on iPhone.
<!doctype html> <HTML> <HEAD> <META CHARSET = "utf-8"> <TITLE>Manhattan</TITLE> <SCRIPT TYPE = "text/javascript"> //Constructor for class Location. function Location(longitude, latitude) { this.longitude = longitude; this.latitude = latitude; } //This function is called when the web page has been loaded into the WebView. function load() { window.setTimeout(load2, 300); //milliseconds } //This function is called 300 milliseconds after the web page has been loaded //into the WebView. function load2() { try { var canvas = document.getElementById("map"); var context = canvas.getContext("2d"); //Make the canvas occupy the whole web page. canvas.width = window.innerWidth; canvas.height = window.innerHeight; //Fill the map with a white background. context.fillStyle = "white"; context.fillRect(0, 0, canvas.width, canvas.height); /* An array of Location objects, counterclockwise around the shore of Manhattan. Longitude west of Greenwich is negative. Latitude north of the equator is positive. */ var point = new Array( new Location(-73.971548, 40.72921), //East River at East 17th Street new Location(-73.974595, 40.735519), //24 new Location(-73.971806, 40.742998), //34 new Location(-73.96215, 40.754767), //53 new Location(-73.954296, 40.762146), //65 new Location(-73.946185, 40.771474), //81 new Location(-73.942022, 40.776154), //89 new Location(-73.942022, 40.776154), //96 new Location(-73.93816, 40.787008), //103 new Location(-73.929534, 40.795326), //118 new Location(-73.929062, 40.800946), //125 new Location(-73.934212, 40.808775), //Harlem River at 132nd Street new Location(-73.933868, 40.817772), //143 new Location(-73.935113, 40.83547), //163 new Location(-73.922195, 40.855857), //Dyckman Street new Location(-73.91078, 40.869878), //218 new Location(-73.911767, 40.873416), //Broadway Bridge new Location(-73.922968, 40.877018), //Henry Hudson Parkway Bridge new Location(-73.926916, 40.877082), //Hudson River new Location(-73.933096, 40.867379), //Riverside Drive new Location(-73.943224, 40.852417), //Hudson River at West 181st Street new Location(-73.946786, 40.850339), //George Washington Bridge new Location(-73.946786, 40.850339), //168 new Location(-73.95052, 40.834626), //155 new Location(-73.955026, 40.827417), //144 sewage treatment plant new Location(-73.956399, 40.828034), //144 new Location(-73.959446, 40.82365), //137 new Location(-73.957601, 40.822676), //137 new Location(-73.994765, 40.771669), //57 new Location(-73.995152, 40.769524), //54 new Location(-73.999872, 40.763316), //44 new Location(-74.001718, 40.762276), //42 new Location(-74.007726, 40.754052), //29 new Location(-74.009442, 40.749825), //23 new Location(-74.00794, 40.748362), //21 new Location(-74.009228, 40.740754), //Meatpacking District new Location(-74.010344, 40.739258), //Gansevoort Street new Location(-74.011545, 40.726218), //Holland Tunnel new Location(-74.013176, 40.718315), //Battery Park City new Location(-74.016609, 40.718737), //Battery Park City new Location(-74.019227, 40.706539), //South Cove new Location(-74.014893, 40.70078), //Battery Park new Location(-74.009314, 40.701919), //Heliport new Location(-73.997984, 40.708523), //north of Brooklyn Bridge new Location(-73.977985, 40.710475), //Corlears Hook Park new Location(-73.976011, 40.712752), //Grand Street new Location(-73.972964, 40.720819) //East 6th Street ); //Three transformations: //Transformation 1: move the origin (0, 0) to the center of the canvas. context.translate(canvas.width / 2, canvas.height / 2); //Center of Manhattan, near the Angel of the Waters in Central Park. var center = new Location(-73.965, 40.79); var latitude = center.latitude * Math.PI / 180; //latitude in radians //The screen will cover 1/4 of a degree of latitude vertically, //approx 15 miles. New York, New York, it's a helluva town! //pixels per degree of latitude (approx 60 miles) var verticalScale = 4 * canvas.height; //pixels per degree of longitude (approx 45 miles in New York) var horizontalScale = verticalScale * Math.cos(latitude); //Transformation 2: magnify the map, and make the Y axis point up. context.scale(horizontalScale, -verticalScale); //Transformation 3: move the camera from Latitude 0, Longitude 0 //(in the South Atlantic) to the center of Manhattan. context.translate(-center.longitude, -center.latitude); context.beginPath(); context.moveTo(point[0].longitude, point[0].latitude); for (var i = 1; i < point.length; ++i) { context.lineTo(point[i].longitude, point[i].latitude); } context.closePath(); context.fillStyle = "red"; context.fill(); } catch (exception) { alert("canvas not supported: " + exception); } } </SCRIPT> </HEAD> <BODY STYLE = " background-color: cyan; margin-left: 0px; margin-top: 0px; " onLoad = "load();"> <CANVAS ID = "map"> </CANVAS> </BODY> </HTML>
Activity
object call a Javascript function in the web page.
We can’t do this until the page is fully loaded.
A
WebViewClient
will tell us when the page is fully loaded.
Create another Javascript function in the web page.
function f() { alert(window.innerWidth + " \u00D7 " + window.innerHeight); }In
onCreate
,
insert a
WebViewClient
into the
WebView
before inserting the
WebChromeClient
into the
WebView
.
webView.setWebViewClient(new WebViewClient() { @Override public void onPageFinished(WebView view, String url) { Toast toast = Toast.makeText(MainActivity.this, url + " loaded", Toast.LENGTH_LONG); toast.show(); view.loadUrl("javascript:f()"); } });The toast says “file:///android_asset/japan.html loaded”. How could we return a return value from
f
?