开发者

Font in Android Library

At the follow link

Android Dev Guide

is write:

Library projects cannot include raw assets The tools do not support the use of raw asset files (saved in the assets/ directory) in a library project. Any asset resources used by an application must be stored in the assets/ directory of the application project itself. However, resource files saved in the res/ directory are supported.

So if I want to create a custom view component that use a custom font how can I access the resour开发者_Python百科ce? Can't I redistribute my component with my favorite font !!!!

Best regards


Here's a method for loading fonts from resources that actually works ;-) Credit to mr32bit for the first version.

private Typeface getFontFromRes(int resource)
{ 
    Typeface tf = null;
    InputStream is = null;
    try {
        is = getResources().openRawResource(resource);
    }
    catch(NotFoundException e) {
        Log.e(TAG, "Could not find font in resources!");
    }

    String outPath = getCacheDir() + "/tmp" + System.currentTimeMillis() ".raw";

    try
    {
        byte[] buffer = new byte[is.available()];
        BufferedOutputStream bos = new BufferedOutputStream(new FileOutputStream(outPath));

        int l = 0;
        while((l = is.read(buffer)) > 0)
            bos.write(buffer, 0, l);

        bos.close();

        tf = Typeface.createFromFile(outPath);

        // clean up
        new File(outPath).delete();
    }
    catch (IOException e)
    {
        Log.e(TAG, "Error reading in font!");
        return null;
    }

    Log.d(TAG, "Successfully loaded font.");

    return tf;      
}


Ok I have found a workaround for the problem. You need to copy the file to an external directory then load a typeface from file with Typeface.createFromFile and then delete the temporary file. I know is not a clean mode of work but is working grate.

1 - You need to put your font on "/res/raw/font.ttf"

2 - Inser in your code the following method

3 - put in your code Typeface mFont = FileStreamTypeface(R.raw.font);

4 - All is done

 Typeface FileStreamTypeface(int resource)
{
    Typeface tf = null;

    InputStream is = getResources().openRawResource(resource);
    String path = Environment.getExternalStorageDirectory().getAbsolutePath() + "/gmg_underground_tmp";
    File f = new File(path);
    if (!f.exists())
    {
        if (!f.mkdirs())
            return null;
    }

    String outPath = path + "/tmp.raw";

    try
    {
        byte[] buffer = new byte[is.available()];
        BufferedOutputStream bos = new BufferedOutputStream(new FileOutputStream(outPath));

        int l = 0;
        while((l = is.read(buffer)) > 0)
        {
            bos.write(buffer, 0, l);
        }
        bos.close();

        tf = Typeface.createFromFile(outPath);

        File f2 = new File(outPath);
        f2.delete();
    }
    catch (IOException e)
    {
        return null;
    }

    return tf;      
}

if someone have an alternative I'm pleased to read it. Do you have to remember that this workaround is only for Android Libraries

Best regards


Intellij Idea (and android studio as it's based on intellij) has a feature that let you include the asset files of the library module to application module, I don't know about other environment.

Go to project structure in file menu, then facets, choose application module, in compiler tab check "include assets from dependencies to the into APK" checkbox.

As intellij is far better than Eclipse, I think migrating is reasonable.

EDIT:

Asset and manifest merging are fully supported in android studio.


If you extend a TextView and want to use many of this views you should have only one instance of the Typeface in this view. Copy the *.ttf file into res/raw/ and use the following code:

public class MyTextView extends TextView {
    public static final String FONT = "font.ttf";
    private static Typeface mFont;

    private static Typeface getTypefaceFromFile(Context context) {
        if(mFont == null) {
            File font = new File(context.getFilesDir(), FONT);
            if (!font.exists()) {
                copyFontToInternalStorage(context, font);
            }
            mFont = Typeface.createFromFile(font);
        }
        return mFont;
    }

    private static void copyFontToInternalStorage(Context context, File font) {
        try {
            InputStream is = context.getResources().openRawResource(R.raw.font);
            byte[] buffer = new byte[4096];
            BufferedOutputStream bos = new BufferedOutputStream(new FileOutputStream(font));
            int readByte;
            while ((readByte = is.read(buffer)) > 0) {
                bos.write(buffer, 0, readByte);
            }
            bos.close();
        } catch (FileNotFoundException e) {
            e.printStackTrace();
        } catch (IOException e) {
            e.printStackTrace();
        }
    }

    public MyTextView(Context context, AttributeSet attrs) {
        super(context, attrs);
        setTypeface(getTypefaceFromFile(context));
    }
}

mFont is a static variable, so the reference will not be destroyed and can be reused in other MyTextViews. This code is nearly the same as the other answers but I guess mor efficient and consumes less memory if you are using it in a ListView or something.


So if I want to create a custom view component that use a custom font how can I access the resource?

Your code would access it the same way that it does not. You will simply have to tell reusers of your custom view to include the font file in their assets.

Can't I redistribute my component with my favorite font !!!!

Sure you can. Put the font in a ZIP file along with the rest of your library project, along with instructions for where to place it in a project. Be sure to use a font that you have rights to redistribute this way, though.


Even though You put Your fonts in assets/fonts folder, somehow this library works and its very easy to use: https://github.com/neopixl/PixlUI . I've successfully tested it on Android 2.3. as well as 4.4


Just use the response of @bk138 with this little change it works to me

add this in the manifest

<uses-permission android:name="android.permission.WRITE_EXTERNAL_STORAGE"/>

and add this before creating the Buffered

        File f2 = new File(outPath);
        BufferedOutputStream bos = new BufferedOutputStream(new FileOutputStream(outPath));


The code below modifies the solution from @bk138 and includes @Jason Robinson recommendations for not deleting the file and checking for a previously cached file first. Also, it names the temp file after the font instead of the time created.

public static Typeface getFontFromRes(Context context, int resId, boolean deleteAfterwards){ 
    String tag = "StorageUtils.getFontFromRes";

    String resEntryName = context.getResources().getResourceEntryName(resId);
    String outPath = context.getCacheDir() + "/tmp_" + resEntryName + ".raw";

    //First see if the file already exists in the cachDir
    FileInputStream fis = null;
    try {
        fis = new FileInputStream(new File(outPath));
    } catch (FileNotFoundException e) {
        Log.d(tag,"fileNotFoundException outPath:"+outPath+e.getMessage());
    }

    if(fis != null){            
        try {
            Log.d(tag,"found cached fontName:"+resEntryName);
            fis.close();
        } catch (IOException e) {
            Log.d(tag,"IOException outPath:"+outPath+e.getMessage());
        }

        //File is already cached so return it now
        return Typeface.createFromFile(outPath);
    }       

    InputStream is = null;
    try {
        is = context.getResources().openRawResource(resId);
    }catch(NotFoundException e) {
        Log.e(tag, "Could not find font in resources! " + outPath);
    }

    try{
        byte[] buffer = new byte[is.available()];
        BufferedOutputStream bos = new BufferedOutputStream(new FileOutputStream(outPath));

        int l = 0;
        while((l = is.read(buffer)) > 0)
            bos.write(buffer, 0, l);

        bos.close();
    }catch (IOException e){
        Log.e(tag, "Error reading in font!");
        return null;
    }           

    Typeface tf = Typeface.createFromFile(outPath);

    if(deleteAfterwards){
        // clean up if desired
        new File(outPath).delete();
    }

    Log.d(tag, "Successfully loaded font.");

    return tf;      
}


Here's my modified version/improvement on @Mr32Bit's answer. On the first call, I copy the font to the app private dir /custom_fonts. Future reads check if exists and if so reads existing copy (saves time on coping file each time).

note: This assumes only a single custom font.

 /**
     * Helper method to load (and cache font in app private folder) typeface from raw dir this is needed because /assets from library projects are not merged in Eclipse
     * @param c
     * @param resource ID of the font.ttf in /raw
     * @return
     */
    public static Typeface loadTypefaceFromRaw(Context c, int resource)
    {
        Typeface tf = null;

        InputStream is = c.getResources().openRawResource(resource);
        String path = c.getFilesDir() + "/custom_fonts";
        File f = new File(path);
        if (!f.exists())
        {
            if (!f.mkdirs())
                return null;
        }

        String outPath = path + "/myfont.ttf";

        File fontFile = new File(outPath);
        if (fontFile.exists()) {
            tf = Typeface.createFromFile(fontFile);
        }else{
            try
            {
                byte[] buffer = new byte[is.available()];
                BufferedOutputStream bos = new BufferedOutputStream(new FileOutputStream(outPath));
                int l = 0;
                while((l = is.read(buffer)) > 0)
                {
                    bos.write(buffer, 0, l);
                }
                bos.close();
                tf = Typeface.createFromFile(outPath);
            }
            catch (IOException e)
            {
                return null;
            }
        }
        return tf;
    }
0

上一篇:

下一篇:

精彩评论

暂无评论...
验证码 换一张
取 消

最新问答

问答排行榜