jueves, 26 de noviembre de 2015

Cargar custom fonts en Android WebView

Cuando usamos el componente WebView de android, cargar fuentes personalizadas puede ser un pequeño infierno. Vamos a ver un ejemplo de como podemos cargar customs fonts en el navegador de android. Para este ejemplo se han usado las siguientes tecnologías
  • Mac OsX El capitan
  • Android Studio 1.5
  • JDK 1.8.0_65

Project ejemplo


Para ver como podemos añadir custom fonts a nuestro WebView vamos a crear un proyecto de ejemplo, para ello pulsamos File -> New -> Project en AndroidStudio


A continuación elegimos la API target de android y el tipo de dispositivos que queremos cubrir, en nuestro caso solo phones y tablets


Ahora elegimos un proyecto vacío


A continuación le damos un nombre a nuestra actividad inicial, en este ejemplo lo dejamos a como viene por defecto


Ahora ya tenemos nuestro proyecto listo.

Pagina a mostrar


Ahora que tenemos nuestro proyecto listo, añadimos al fichero res/layout/content_main.xml un objeto webView
<?xml version="1.0" encoding="utf-8"?>
<RelativeLayout xmlns:android="http://schemas.android.com/apk/res/android"
    xmlns:app="http://schemas.android.com/apk/res-auto"
    xmlns:tools="http://schemas.android.com/tools"
    android:layout_width="match_parent"
    android:layout_height="match_parent"
    android:paddingBottom="@dimen/activity_vertical_margin"
    android:paddingLeft="@dimen/activity_horizontal_margin"
    android:paddingRight="@dimen/activity_horizontal_margin"
    android:paddingTop="@dimen/activity_vertical_margin"
    app:layout_behavior="@string/appbar_scrolling_view_behavior"
    tools:context="com.example.fhernandez.webviewcustomfontsexample.MainActivity"
    tools:showIn="@layout/activity_main">

    <WebView
        android:layout_width="fill_parent"
        android:layout_height="400dp"
        android:id="@+id/myBowser"
        android:layout_marginTop="10dp" />
</RelativeLayout>

Vamos a definir una pagina HTML estática que será completada dinámicamente en el código dentro de la carpeta de recursos raw de android. Por defecto esta carpeta no se añade al proyecto, para añadirla hacemos doble click sobre el proyecto y pulsamos New -> Android resource directory


A continuación seleccionamos raw


Al hacer esto se nos ha creado la carpeta raw dentro de resources en el proyecto. Dentro de ella creamos un fichero llamado our_page.html y le añadimos el siguiente contenido
<html>
<head>
<style>

    @font-face {
        font-family: "AppleGaramond";
        src: url("fonts/AppleGaramond.ttf");
        font-style: normal;
        font-weight: normal;
    }
    @font-face {
        font-family: "AppleGaramond";
        src: url("fonts/AppleGaramond-Bold.ttf");
        font-style: normal;
        font-weight: bold;
    }


    * {font-family: 'AppleGaramond' !important;}
</style>

</head>

<body>

Hello to all, this is a <b>bold</b> text<br>

Como se puede observar, estamos definiendo nuestras fuentes en los estilos de la páginas y se lo aplicamos a todo la página.

Añadir custom fonts

Para añadir nuestras fuentes lo haremos añadiendo los ficheros al directorio assets. AndroidStudio no añade este directorio por defecto en el proyecto, para añadirlo hacemos doble click sobre el proyecto y pulsamos New -> Folder -> Assets Folder


En la siguiente ventana confirmamos


Ahora tendremos el directorio assets disponible, creamos dentro de él un directorio llamado fonts y copiamos ahi nuestro archivos de fuentes. Nuestro proyecto queda de la siguiente manera



Cargamos nuestra página en el webview

Vamos a modificar la actividad principal para cargar nuestra pagina, para ello el código quedara asi
package com.example.fhernandez.webviewcustomfontsexample;

import android.content.Context;
import android.content.res.Resources;
import android.os.Bundle;
import android.support.design.widget.FloatingActionButton;
import android.support.design.widget.Snackbar;
import android.support.v7.app.AppCompatActivity;
import android.support.v7.widget.Toolbar;
import android.view.View;
import android.view.Menu;
import android.view.MenuItem;
import android.webkit.WebView;

import java.io.IOException;
import java.io.InputStream;

public class MainActivity extends AppCompatActivity {

    private WebView myBowser;

    @Override
    protected void onCreate(Bundle savedInstanceState) {
        super.onCreate(savedInstanceState);
        setContentView(R.layout.activity_main);
        Toolbar toolbar = (Toolbar) findViewById(R.id.toolbar);
        setSupportActionBar(toolbar);

        FloatingActionButton fab = (FloatingActionButton) findViewById(R.id.fab);
        fab.setOnClickListener(new View.OnClickListener() {
            @Override
            public void onClick(View view) {
                Snackbar.make(view, "Replace with your own action", Snackbar.LENGTH_LONG)
                        .setAction("Action", null).show();
            }
        });

        myBowser = (WebView) findViewById(R.id.myBowser);

        // Load our page
        loadData();


    }

    private void loadData() {

        // read the file
        String myPage = "";
        try {
            myPage = getStringFromFile(this, R.raw.our_page);
        } catch (IOException e) {
            e.printStackTrace();
        }

        // Complete the page
        myPage = myPage + "This is a part added from code <b>awesome!</b></body></html>";

        myBowser.loadData(myPage, "text/html; charset=UTF-8", null);
    }

    // Read from res/raw
    public String getStringFromFile (Context context, int resId) throws IOException {

        String result;
        Resources res = context.getResources();
        InputStream in_s = res.openRawResource(resId);

        byte[] b = new byte[in_s.available()];
        in_s.read(b);
        result = new String(b);

        return result;
    }

    @Override
    public boolean onCreateOptionsMenu(Menu menu) {
        // Inflate the menu; this adds items to the action bar if it is present.
        getMenuInflater().inflate(R.menu.menu_main, menu);
        return true;
    }

    @Override
    public boolean onOptionsItemSelected(MenuItem item) {
        // Handle action bar item clicks here. The action bar will
        // automatically handle clicks on the Home/Up button, so long
        // as you specify a parent activity in AndroidManifest.xml.
        int id = item.getItemId();

        //noinspection SimplifiableIfStatement
        if (id == R.id.action_settings) {
            return true;
        }

        return super.onOptionsItemSelected(item);
    }
}



Resultado

Ahora que ya tenemos nuestro proyecto listo, ejecutamos nuestra aplicación y veremos lo siguiente


El resultado no es correcto, ya que se NO se están usando nuestras fuentes.

Corregir el uso de custom fonts

Para que el navegador pueda cargar nuestras fuentes debemos modificar la forma en que se carga la página y hacerlo de esta forma
myBowser.loadDataWithBaseURL("file:///android_asset/", myPage, "text/html", "utf-8",null);

Ahora, si ejecutamos de nuevo, veremos que carga nuestra fuente correctamente


Puedes descargar el código de este ejemplo desde github

No hay comentarios:

Publicar un comentario