Performance issue on custom font TextView - android

I have a custom TextView, with a personalized font attribute:
public class TextViewPlus extends TextView {
private static final String TAG = "TextViewPlus";
public TextViewPlus(Context context) {
super(context);
}
public TextViewPlus(Context context, AttributeSet attrs) {
// This is called all the time I scroll my ListView
// and it make it very slow.
super(context, attrs);
setCustomFont(context, attrs);
}
public TextViewPlus(Context context, AttributeSet attrs, int defStyle) {
super(context, attrs, defStyle);
setCustomFont(context, attrs);
}
private void setCustomFont(Context ctx, AttributeSet attrs) {
TypedArray a = ctx.obtainStyledAttributes(attrs, R.styleable.TextViewPlus);
String customFont = a.getString(R.styleable.TextViewPlus_customFont);
setCustomFont(ctx, customFont);
a.recycle();
}
public boolean setCustomFont(Context ctx, String asset) {
Typeface tf = null;
try {
tf = Typeface.createFromAsset(ctx.getAssets(), asset);
setTypeface(tf);
} catch (Exception e) {
Log.e(TAG, "Could not get typeface: "+e.getMessage());
return false;
}
return true;
}
}
I'm using it in my XML files with the attribute customFont="ArialRounded.ttf", and it is working quite well.
I'm using this TextViewPlus in a ListView, populated with an ArrayAdapter.
TextViewPlus dataText = (TextViewPlus) itemView.findViewById(R.id.data_text);
dataText.setText("My data String");
My problem is that the performance, when I'm scrolling the ListView, are terrible! Very slow and full of lags. The TextViewPlus constructor n°2 it's called all the time i scroll the list.
If I change TextViewPlus in a normal TextView, and use dataText.setTypeface(myFont), everything is smood and is working well.
How can I use my TextViewPlus without performance issue?

Why don't you keep the created typface object in memory so that you don't create every time the text view is getting created.
Following is a sample class that creates and cache the typeface object:
public class TypeFaceProvider {
public static final String TYPEFACE_FOLDER = "fonts";
public static final String TYPEFACE_EXTENSION = ".ttf";
private static Hashtable<String, Typeface> sTypeFaces = new Hashtable<String, Typeface>(
4);
public static Typeface getTypeFace(Context context, String fileName) {
Typeface tempTypeface = sTypeFaces.get(fileName);
if (tempTypeface == null) {
String fontPath = new StringBuilder(TYPEFACE_FOLDER).append('/').append(fileName).append(TYPEFACE_EXTENSION).toString();
tempTypeface = Typeface.createFromAsset(context.getAssets(), fontPath);
sTypeFaces.put(fileName, tempTypeface);
}
return tempTypeface;
}
}

Related

Setting Custom Font for TextView causing the onCreate to take longer to build

I am currently implementing Roboto font within my project. For some fragments, there are a lot of TextView's. I am creating a custom View that exends TextView to implement custom fonts. Is there a better way to load the fonts without increasing the onCreate times?
Extends TextView
public class TextViewFont extends TextView {
public TextViewFont(Context context, AttributeSet attrs, int defStyle) {
super(context, attrs, defStyle);
init(attrs);
}
public TextViewFont(Context context, AttributeSet attrs) {
super(context, attrs);
init(attrs);
}
public TextViewFont(Context context) {
super(context);
init(null);
}
private void init(AttributeSet attrs) {
if (attrs != null) {
TypedArray a = getContext().obtainStyledAttributes(attrs, R.styleable.TextViewFont);
String fontName = a.getString(R.styleable.TextViewFont_fontName);
if (fontName != null) {
Typeface myTypeface = Typeface.createFromAsset(getContext().getAssets(), "fonts/" + fontName);
setTypeface(myTypeface);
}
a.recycle();
}
}
}
XML
<com.eugene.fithealthmaingit.Custom.TextViewFont
android:layout_width="0dp"
android:layout_height="wrap_content"
android:layout_marginLeft="16dp"
android:layout_weight="1"
android:text="#string/dinner"
android:textColor="#color/text_color"
android:textSize="16sp"
app:fontName="Roboto-Regular.ttf"/>
Example of how many TextView's
This is the library that saved my life Calligraphy. It's really nice and easy to use.
Typeface.createfromassets is a time taking process. You should declare typeface as static varaiable in class and just use it in constructor.
But here you are loading fonts in every textview's constructor.
If you having multiple fonts, have all tytypeface as static and use it appropriately.
UPDATE CODE:
public class TextViewFont extends TextView {
public static Typeface typeface1 = Typeface.createFromAsset(getContext().getAssets(), "fonts/fontName1");
public static Typeface typeface2 = Typeface.createFromAsset(getContext().getAssets(), "fonts/fontName2");
public static Typeface typeface3 = Typeface.createFromAsset(getContext().getAssets(), "fonts/fontName3");
public static Typeface typeface4 = Typeface.createFromAsset(getContext().getAssets(), "fonts/fontName4");
public static Typeface typeface5 = Typeface.createFromAsset(getContext().getAssets(), "fonts/fontName5");
public TextViewFont(Context context, AttributeSet attrs, int defStyle) {
super(context, attrs, defStyle);
init(attrs);
}
public TextViewFont(Context context, AttributeSet attrs) {
super(context, attrs);
init(attrs);
}
public TextViewFont(Context context) {
super(context);
init(null);
}
private void init(AttributeSet attrs) {
if (attrs != null) {
TypedArray a = getContext().obtainStyledAttributes(attrs, R.styleable.TextViewFont);
String fontName = a.getString(R.styleable.TextViewFont_fontName);
if (fontName != null) {
setTypeface(getTypeFace(fontName));
}
a.recycle();
}
}
public Typeface getTypeFace(String fontName){
if(fontName.equals("fontName1")){
return typeface1;
}else if(fontName.equals("fontName2")){
return typeface2;
}else if(fontName.equals("fontName3")){
return typeface3;
}else if(fontName.equals("fontName4")){
return typeface4;
}else if(fontName.equals("fontName5")){
return typeface5;
}
}
}
}
Try using an instance singleton or applicationsingleton. See if this works. So you can just call TextLover.get(context).getFont(id). It will create and cache it on the fly. This way your other views can also reuse the font cache. eg. buttons
class TextLover {
private static TextLover singleton;
private final Context context;
private final SparseArray<Typeface> faces = new SparseArray<Typeface>();
public TextLover get(Context context) {
if (singleton == null) {
singleton = new TextLover(context);
}
return singleton;
}
private TextLover(Context context) {
this.context = context;
}
private static final String[] fonts = {
"fonts/fontName1",
"fonts/fontName2",
"fonts/fontName3",
"fonts/fontName4",
"fonts/fontName5",
...
"fonts/fontName100"
}
// NOTE you need a mapping of ids to each asset font in fonts[]
public Typeface getFont(int id) {
Typeface font = faces.get(id);
if (font == null) {
font = Typeface.createFromAsset(context.getAssets(), fonts[id]);
faces.append(id, font);
}
return font;
}
}

Set font face in android

I want to change some textview font-face to external font and i do something like this :
typeFace = Typeface.createFromAsset(getAssets(),"fonts/bkoodak.ttf");
tv1.setTypeface(typeFace);
tv2.setTypeface(typeFace);
tv3.setTypeface(typeFace);
...
But this form is't nice to me.
Is there some way to do this better?
Yes there is a better way.
But you have to create your own derived TextView that apply the TypeFace. And use it in your XML Layout.
Refer to this question for more details:
How to make a custom TextView?
You can create own TextView class:
public class MyTextView extends TextView {
public MyTextView(Context context, AttributeSet attrs, int defStyle) {
super(context, attrs, defStyle);
init(attrs);
}
public MyTextView(Context context, AttributeSet attrs) {
super(context, attrs);
init(attrs);
}
public MyTextView(Context context) {
super(context);
init(null);
}
private void init(AttributeSet attrs) {
if (attrs != null) {
TypedArray a = getContext().obtainStyledAttributes(attrs,
R.styleable.MyTextView);
Typeface myTypeface = Typeface.createFromAsset(getContext()
.getAssets(), "fonts/bkoodak.ttf");
setTypeface(myTypeface);
a.recycle();
}
}
}
and use it in you layout:
<yourpackage.MyTextView
android:layout_width="wrap_content"
android:layout_height="wrap_content"/>
You can use create a class and use it everywhere.
For example:
FontChanger Class:
public class FontChanger
{
private Typeface typeface;
public FontChanger(Typeface typeface)
{
this.typeface = typeface;
}
public FontChanger(AssetManager assets, String assetsFontFileName)
{
typeface = Typeface.createFromAsset(assets, assetsFontFileName);
}
public void replaceFonts(ViewGroup viewTree)
{
View child;
for(int i = 0; i < viewTree.getChildCount(); ++i)
{
child = viewTree.getChildAt(i);
if(child instanceof ViewGroup)
{
// recursive call
replaceFonts((ViewGroup)child);
}
else if(child instanceof TextView)
{
// base case
((TextView) child).setTypeface(typeface);
}
}
}
}
onCreate of your activity :
FontChanger fontChanger = new FontChanger(getAssets(), "font.otf");
fontChanger.replaceFonts((ViewGroup)this.findViewById(android.R.id.content));

particular custom font used is not working in android application

i am using DIEHL DECO font for my text view. the class file in my code is as below. the application is running without any errors but the font displayed is the default font. the font is not changed to the font file I am using.
I tried with another font file the code runs well but does not run well for this particular font. not understanding what the issue is. please help me.
public class MyTextView extends TextView{
public MyTextView(Context context, AttributeSet attrs, int defStyle) {
super(context, attrs, defStyle);
}
public MyTextView(Context context, AttributeSet attrs) {
super(context, attrs);
}
public MyTextView(Context context) {
super(context);
}
public void setTypeface(Typeface tf, int style) {
if (style == Typeface.BOLD) {
super.setTypeface(TypeFaces.getTypeFace(getContext(),
"fonts/DIEHLD_.ttf"));
} else if (style == Typeface.ITALIC) {
super.setTypeface(TypeFaces.getTypeFace(getContext(),
"fonts/DIEHLD_.ttf"));
} else {
super.setTypeface(TypeFaces.getTypeFace(getContext(),
"fonts/DIEHLD_.ttf"));
}
}
}
this is the typefaces class
public class TypeFaces {
private static final Hashtable<String, Typeface> cache = new Hashtable<String, Typeface>();
public static Typeface getTypeFace(Context context, String assetPath) {
synchronized (cache) {
if (!cache.containsKey(assetPath)) {
try {
Typeface typeFace = Typeface.createFromAsset(
context.getAssets(), assetPath);
cache.put(assetPath, typeFace);
} catch (Exception e) {
Log.e("TypeFaces", "Typeface not loaded.");
return null;
}
}
return cache.get(assetPath);
}
}
}
Use assets/fonts/DIEHLD_.ttf, if you hae created fonts folder in assets folder.
I assume you placed your all font in "fonts" folder which is in assets folder in your project.
Typeface tf = Typeface.createFromAsset(mContext.getAssets(), "fonts/DIEHLD_.ttf");
this.setTypeface(tf);

Getting resource ID or InputStream from ImageView Drawable

I am developing a GifView class, extending android.view.ImageView to show an animation gif in Android.
The problem is getting android:src="#drawable/myGif" from XML layout to load it in Movie automatically. When I override setImageDrawable(Drawable drawable) to intercept default android behaviour, I have two differents ways to do it: getting the id resource from #drawable/myGif and save it for later use, or load it on demand in Movie. But with the latter option I need to convert Drawable in InputStream unused compress method from Bitmap class to can safe GIF layers.
How can I do it?
public class GifView extends ImageView {
...
private Movie movie;
private int resId;
public GifView(Context context) {
super(context);
this.context = context;
}
public GifView(Context context, AttributeSet attrs) {
super(context, attrs);
this.context = context;
}
public GifView(Context context, AttributeSet attrs, int defStyle) {
super(context, attrs, defStyle);
this.context = context;
}
#Override
public void setImageDrawable(Drawable drawable) {
// ONE OF THOSE WAYS TO DO
// this.redId = ...
// this.movie = Movie.decodeStream(...);
}
...
}
ok, you can do it automatically, but does it really pay of?
public class GifImageView extends ImageView {
private final static String TAG = "GifImageView";
public GifImageView(Context context, AttributeSet attrs) {
super(context, attrs);
int[] attrArray = {
android.R.attr.src
};
TypedArray a = context.obtainStyledAttributes(attrs, attrArray);
int id = a.getResourceId(0, 0);
a.recycle();
if (id != 0) {
try {
Drawable d = new GifDrawable(getResources(), id);
setImageDrawable(d);
} catch (Exception e) {
Log.d(TAG, "GifImageView " + e.getMessage());
}
}
}
class GifDrawable extends Drawable implements Runnable {
...
}
}

Where to Set Custom Typeface in Custom View Class (extends Button)?

I have a custom View class that extends Button. I'd like to set a custom Typeface to all instances of this class, but since some methods get called multiple times in a view, I was wondering what is the best overwriting method to place the following code in?
final Typeface face = Typeface.createFromAsset(getContext().getAssets(),
"myfont.ttf");
this.setTypeface(face);
Currently, I have it in onMeasure(), but I noticed it gets called multiple times, which I assume won't be good for performance.
Most correct is to add your code to constructor.
public class ButtonPlus extends Button {
public ButtonPlus(Context context) {
super(context);
}
public ButtonPlus(Context context, AttributeSet attrs) {
super(context, attrs);
setCustomFont(context, attrs);
}
public ButtonPlus(Context context, AttributeSet attrs, int defStyle) {
super(context, attrs, defStyle);
setCustomFont(context, attrs);
}
private void setCustomFont(Context ctx, AttributeSet attrs) {
TypedArray a = ctx.obtainStyledAttributes(attrs,
R.styleable.TextViewPlus);
String customFont = a.getString(R.styleable.TextViewPlus_customFont);
setCustomFont(ctx, customFont);
a.recycle();
}
public boolean setCustomFont(Context ctx, String asset) {
Typeface tf = null;
try {
tf = Typeface.createFromAsset(ctx.getAssets(), asset);
} catch (Exception e) {
return false;
}
setTypeface(tf);
return true;
}
}
here customFont - is my custom attribute. i specify font from layout using this attr. I just created following custom attr in values/attrs.xml

Categories

Resources