Android Tutorial - 2D Graphics : Font
Using Typeface to create ttf file
package app.test; import android.app.Activity; import android.graphics.Bitmap; import android.graphics.Canvas; import android.graphics.Color; import android.graphics.Paint; import android.graphics.Typeface; import android.os.Bundle; import android.widget.ImageView; public class Test extends Activity { ImageView drawingImageView; @Override public void onCreate(Bundle savedInstanceState) { super.onCreate(savedInstanceState); setContentView(R.layout.main); drawingImageView = (ImageView) this.findViewById(R.id.DrawingImageView); Bitmap bitmap = Bitmap.createBitmap((int) getWindowManager() .getDefaultDisplay().getWidth(), (int) getWindowManager() .getDefaultDisplay().getHeight(), Bitmap.Config.ARGB_8888); Canvas canvas = new Canvas(bitmap); drawingImageView.setImageBitmap(bitmap); // Custom Font Text Paint paint = new Paint(); paint.setColor(Color.GREEN); paint.setTextSize(40); Typeface chops = Typeface.createFromAsset(getAssets(), "ChopinScript.ttf"); paint.setTypeface(chops); float text_x = 120; float text_y = 120; canvas.drawText("Hello", text_x, text_y, paint); } }
Using FontMetrics
package app.test; import java.io.InputStream; import android.app.Activity; import android.content.Context; import android.graphics.Bitmap; import android.graphics.BitmapFactory; import android.graphics.Canvas; import android.graphics.Color; import android.graphics.LinearGradient; import android.graphics.Paint; import android.graphics.Picture; import android.graphics.PorterDuff; import android.graphics.PorterDuffXfermode; import android.graphics.Rect; import android.graphics.Shader; import android.graphics.drawable.Drawable; import android.os.Bundle; import android.util.AttributeSet; import android.view.View; import android.view.ViewGroup; import android.view.ViewParent; public class Test extends GraphicsActivity { @Override protected void onCreate(Bundle savedInstanceState) { super.onCreate(savedInstanceState); setContentView(new SampleView(this)); } private static class SampleView extends View { private Bitmap mBitmap; private Bitmap mBitmap2; private Bitmap mBitmap3; private Shader mShader; private static void drawIntoBitmap(Bitmap bm) { float x = bm.getWidth(); float y = bm.getHeight(); Canvas c = new Canvas(bm); Paint p = new Paint(); p.setAntiAlias(true); p.setAlpha(0x80); c.drawCircle(x/2, y/2, x/2, p); p.setAlpha(0x30); p.setXfermode(new PorterDuffXfermode(PorterDuff.Mode.SRC)); p.setTextSize(60); p.setTextAlign(Paint.Align.CENTER); Paint.FontMetrics fm = p.getFontMetrics(); c.drawText("Alpha", x/2, (y-fm.ascent)/2, p); } public SampleView(Context context) { super(context); setFocusable(true); InputStream is = context.getResources().openRawResource(R.drawable.icon); mBitmap = BitmapFactory.decodeStream(is); mBitmap2 = mBitmap.extractAlpha(); mBitmap3 = Bitmap.createBitmap(200, 200, Bitmap.Config.ALPHA_8); drawIntoBitmap(mBitmap3); mShader = new LinearGradient(0, 0, 100, 70, new int[] { Color.RED, Color.GREEN, Color.BLUE }, null, Shader.TileMode.MIRROR); } @Override protected void onDraw(Canvas canvas) { canvas.drawColor(Color.WHITE); Paint p = new Paint(); float y = 10; p.setColor(Color.RED); canvas.drawBitmap(mBitmap, 10, y, p); y += mBitmap.getHeight() + 10; canvas.drawBitmap(mBitmap2, 10, y, p); y += mBitmap2.getHeight() + 10; p.setShader(mShader); canvas.drawBitmap(mBitmap3, 10, y, p); } } } class GraphicsActivity extends Activity { // set to true to test Picture private static final boolean TEST_PICTURE = false; @Override protected void onCreate(Bundle savedInstanceState) { super.onCreate(savedInstanceState); } @Override public void setContentView(View view) { if (TEST_PICTURE) { ViewGroup vg = new PictureLayout(this); vg.addView(view); view = vg; } super.setContentView(view); } } class PictureLayout extends ViewGroup { private final Picture mPicture = new Picture(); public PictureLayout(Context context) { super(context); } public PictureLayout(Context context, AttributeSet attrs) { super(context, attrs); } @Override public void addView(View child) { if (getChildCount() > 1) { throw new IllegalStateException("PictureLayout can host only one direct child"); } super.addView(child); } @Override public void addView(View child, int index) { if (getChildCount() > 1) { throw new IllegalStateException("PictureLayout can host only one direct child"); } super.addView(child, index); } @Override public void addView(View child, LayoutParams params) { if (getChildCount() > 1) { throw new IllegalStateException("PictureLayout can host only one direct child"); } super.addView(child, params); } @Override public void addView(View child, int index, LayoutParams params) { if (getChildCount() > 1) { throw new IllegalStateException("PictureLayout can host only one direct child"); } super.addView(child, index, params); } @Override protected LayoutParams generateDefaultLayoutParams() { return new LayoutParams(LayoutParams.MATCH_PARENT, LayoutParams.MATCH_PARENT); } @Override protected void onMeasure(int widthMeasureSpec, int heightMeasureSpec) { final int count = getChildCount(); int maxHeight = 0; int maxWidth = 0; for (int i = 0; i < count; i++) { final View child = getChildAt(i); if (child.getVisibility() != GONE) { measureChild(child, widthMeasureSpec, heightMeasureSpec); } } maxWidth += getPaddingLeft() + getPaddingRight(); maxHeight += getPaddingTop() + getPaddingBottom(); Drawable drawable = getBackground(); if (drawable != null) { maxHeight = Math.max(maxHeight, drawable.getMinimumHeight()); maxWidth = Math.max(maxWidth, drawable.getMinimumWidth()); } setMeasuredDimension(resolveSize(maxWidth, widthMeasureSpec), resolveSize(maxHeight, heightMeasureSpec)); } private void drawPict(Canvas canvas, int x, int y, int w, int h, float sx, float sy) { canvas.save(); canvas.translate(x, y); canvas.clipRect(0, 0, w, h); canvas.scale(0.5f, 0.5f); canvas.scale(sx, sy, w, h); canvas.drawPicture(mPicture); canvas.restore(); } @Override protected void dispatchDraw(Canvas canvas) { super.dispatchDraw(mPicture.beginRecording(getWidth(), getHeight())); mPicture.endRecording(); int x = getWidth()/2; int y = getHeight()/2; if (false) { canvas.drawPicture(mPicture); } else { drawPict(canvas, 0, 0, x, y, 1, 1); drawPict(canvas, x, 0, x, y, -1, 1); drawPict(canvas, 0, y, x, y, 1, -1); drawPict(canvas, x, y, x, y, -1, -1); } } @Override public ViewParent invalidateChildInParent(int[] location, Rect dirty) { location[0] = getLeft(); location[1] = getTop(); dirty.set(0, 0, getWidth(), getHeight()); return getParent(); } @Override protected void onLayout(boolean changed, int l, int t, int r, int b) { final int count = super.getChildCount(); for (int i = 0; i < count; i++) { final View child = getChildAt(i); if (child.getVisibility() != GONE) { final int childLeft = getPaddingLeft(); final int childTop = getPaddingTop(); child.layout(childLeft, childTop, childLeft + child.getMeasuredWidth(), childTop + child.getMeasuredHeight()); } } } }
Font Test Activity
package app.test; import android.app.Activity; import android.content.Context; import android.graphics.Canvas; import android.graphics.Color; import android.graphics.Paint; import android.graphics.Rect; import android.graphics.Typeface; import android.os.Bundle; import android.view.View; import android.view.Window; import android.view.WindowManager; public class Test extends Activity { class RenderView extends View { Paint paint; Typeface font; Rect bounds = new Rect(); public RenderView(Context context) { super(context); paint = new Paint(); font = Typeface.createFromAsset(context.getAssets(), "font.ttf"); } protected void onDraw(Canvas canvas) { paint.setColor(Color.YELLOW); paint.setTypeface(font); paint.setTextSize(28); paint.setTextAlign(Paint.Align.CENTER); canvas.drawText("This is a test!", canvas.getWidth() / 2, 100,paint); String text = "This is a test"; paint.setColor(Color.WHITE); paint.setTextSize(18); paint.setTextAlign(Paint.Align.LEFT); paint.getTextBounds(text, 0, text.length(), bounds); canvas.drawText(text, canvas.getWidth() - bounds.width(), 140,paint); invalidate(); } } @Override public void onCreate(Bundle savedInstanceState) { super.onCreate(savedInstanceState); requestWindowFeature(Window.FEATURE_NO_TITLE); getWindow().setFlags(WindowManager.LayoutParams.FLAG_FULLSCREEN, WindowManager.LayoutParams.FLAG_FULLSCREEN); setContentView(new RenderView(this)); } }
Set text to use bold and italic font style
package app.test; import android.app.Activity; import android.graphics.Color; import android.os.Bundle; import android.text.Spannable; import android.text.style.BackgroundColorSpan; import android.text.style.StyleSpan; import android.text.util.Linkify; import android.widget.EditText; import android.widget.TextView; public class Test extends Activity { @Override public void onCreate(Bundle savedInstanceState) { super.onCreate(savedInstanceState); setContentView(R.layout.main); TextView tv =(TextView)this.findViewById(R.id.tv); tv.setAutoLinkMask(Linkify.ALL); tv.setText("asdf"); TextView tv3 =(TextView)this.findViewById(R.id.tv3); tv3.setText("asdf",TextView.BufferType.SPANNABLE); Spannable spn = (Spannable) tv3.getText(); spn.setSpan(new BackgroundColorSpan(Color.RED), 0, 7,Spannable.SPAN_EXCLUSIVE_EXCLUSIVE); spn.setSpan(new StyleSpan(android.graphics.Typeface.BOLD_ITALIC),0, 7, Spannable.SPAN_EXCLUSIVE_EXCLUSIVE); EditText et =(EditText)this.findViewById(R.id.et); et.setText("asdf"); Spannable spn2 = (Spannable) et.getText(); spn2.setSpan(new BackgroundColorSpan(Color.RED), 0, 7,Spannable.SPAN_EXCLUSIVE_EXCLUSIVE); spn2.setSpan(new StyleSpan(android.graphics.Typeface.BOLD_ITALIC),0, 7, Spannable.SPAN_EXCLUSIVE_EXCLUSIVE); } } //main.xml <?xml version="1.0" encoding="utf-8"?> <LinearLayout xmlns:android="http://schemas.android.com/apk/res/android" android:orientation="vertical" android:layout_width="fill_parent" android:layout_height="fill_parent" > <TextView android:layout_width="fill_parent" android:layout_height="wrap_content" android:autoLink="web|map" android:text="Please visit www.androidbook.com for more help on using Android." android:minLines="5" android:typeface="serif" /> <TextView android:id="@+id/tv" android:layout_width="fill_parent" android:layout_height="wrap_content" /> <TextView android:id="@+id/tvStyled" android:layout_width="fill_parent" android:layout_height="wrap_content" android:text="@+string/styledText" /> <TextView android:id="@+id/tv3" android:layout_width="fill_parent" android:layout_height="wrap_content" /> <EditText android:id="@+id/et" android:layout_width="fill_parent" android:layout_height="wrap_content" android:inputType="text|textAutoCorrect|textAutoComplete|textMultiLine" /> <Button android:id="@+id/button1" android:layout_width="wrap_content" android:layout_height="wrap_content" android:text="@string/tv" /> <TextView android:id="@+id/errors" style="@style/ErrorText" android:text="There's trouble down at the mill." /> <TextView android:id="@+id/danger" style="@style/ErrorText.Danger" android:text="SERIOUSLY! THERE'S TROUBLE DOWN AT THE MILL!!" /> </LinearLayout> //strings.xml <?xml version="1.0" encoding="utf-8"?> <resources> <string name="hello">Hello World, ActivityMenu</string> <string name="app_name">HelloMenu</string> <string name="button1">button1</string> <string name="button2">button2</string> <string name="tv">I am a TextView</string> <string name="et">I am an EditText</string> <string name="actv">AutoComplete:</string> <string name="mactv">MultiAutoComplete:</string> </resources> //styles.xml <?xml version="1.0" encoding="utf-8"?> <resources> <style name="ErrorText"> <item name="android:layout_width">fill_parent</item> <item name="android:layout_height">wrap_content</item> <item name="android:textColor">#FF0000</item> <item name="android:typeface">monospace</item> </style> <style name="ErrorText.Danger" > <item name="android:textStyle">bold</item> </style> </resources>
Font Sampler
package com.commonsware.android.fonts; import android.app.Activity; import android.graphics.Typeface; import android.os.Bundle; import android.widget.TextView; public class FontSampler extends Activity { @Override public void onCreate(Bundle icicle) { super.onCreate(icicle); setContentView(R.layout.main); TextView tv=(TextView)findViewById(R.id.custom); Typeface face=Typeface.createFromAsset(getAssets(),"fonts/HandmadeTypewriter.ttf"); tv.setTypeface(face); } } //res\layout\main.xml <?xml version="1.0" encoding="utf-8"?> <TableLayout xmlns:android="http://schemas.android.com/apk/res/android" android:layout_width="fill_parent" android:layout_height="fill_parent" android:stretchColumns="1"> <TableRow> <TextView android:text="sans:" android:layout_marginRight="4px" android:textSize="20sp" /> <TextView android:id="@+id/sans" android:text="Hello, world!" android:typeface="sans" android:textSize="20sp" /> </TableRow> <TableRow> <TextView android:text="serif:" android:layout_marginRight="4px" android:textSize="20sp" /> <TextView android:id="@+id/serif" android:text="Hello, world!" android:typeface="serif" android:textSize="20sp" /> </TableRow> <TableRow> <TextView android:text="monospace:" android:layout_marginRight="4px" android:textSize="20sp" /> <TextView android:id="@+id/monospace" android:text="Hello, world!" android:typeface="monospace" android:textSize="20sp" /> </TableRow> <TableRow> <TextView android:text="Custom:" android:layout_marginRight="4px" android:textSize="20sp" /> <TextView android:id="@+id/custom" android:text="Hello, world!" android:textSize="20sp" /> </TableRow> </TableLayout>
Typefaces Demo
package app.test; import android.app.Activity; import android.content.Context; import android.graphics.Canvas; import android.graphics.Color; import android.graphics.Paint; import android.graphics.Picture; import android.graphics.Rect; import android.graphics.Typeface; import android.graphics.drawable.Drawable; import android.os.Bundle; import android.util.AttributeSet; import android.view.View; import android.view.ViewGroup; import android.view.ViewParent; public class Test extends GraphicsActivity { @Override protected void onCreate(Bundle savedInstanceState) { super.onCreate(savedInstanceState); setContentView(new SampleView(this)); } private static class SampleView extends View { private Paint mPaint = new Paint(Paint.ANTI_ALIAS_FLAG); private Typeface mFace; public SampleView(Context context) { super(context); mFace = Typeface.createFromAsset(getContext().getAssets(), "fonts/samplefont.ttf"); mPaint.setTextSize(64); } @Override protected void onDraw(Canvas canvas) { canvas.drawColor(Color.WHITE); mPaint.setTypeface(null); canvas.drawText("Default", 10, 100, mPaint); mPaint.setTypeface(mFace); canvas.drawText("Custom", 10, 200, mPaint); } } } class GraphicsActivity extends Activity { // set to true to test Picture private static final boolean TEST_PICTURE = false; @Override protected void onCreate(Bundle savedInstanceState) { super.onCreate(savedInstanceState); } @Override public void setContentView(View view) { if (TEST_PICTURE) { ViewGroup vg = new PictureLayout(this); vg.addView(view); view = vg; } super.setContentView(view); } } class PictureLayout extends ViewGroup { private final Picture mPicture = new Picture(); public PictureLayout(Context context) { super(context); } public PictureLayout(Context context, AttributeSet attrs) { super(context, attrs); } @Override public void addView(View child) { if (getChildCount() > 1) { throw new IllegalStateException( "PictureLayout can host only one direct child"); } super.addView(child); } @Override public void addView(View child, int index) { if (getChildCount() > 1) { throw new IllegalStateException( "PictureLayout can host only one direct child"); } super.addView(child, index); } @Override public void addView(View child, LayoutParams params) { if (getChildCount() > 1) { throw new IllegalStateException( "PictureLayout can host only one direct child"); } super.addView(child, params); } @Override public void addView(View child, int index, LayoutParams params) { if (getChildCount() > 1) { throw new IllegalStateException( "PictureLayout can host only one direct child"); } super.addView(child, index, params); } @Override protected LayoutParams generateDefaultLayoutParams() { return new LayoutParams(LayoutParams.MATCH_PARENT, LayoutParams.MATCH_PARENT); } @Override protected void onMeasure(int widthMeasureSpec, int heightMeasureSpec) { final int count = getChildCount(); int maxHeight = 0; int maxWidth = 0; for (int i = 0; i < count; i++) { final View child = getChildAt(i); if (child.getVisibility() != GONE) { measureChild(child, widthMeasureSpec, heightMeasureSpec); } } maxWidth += getPaddingLeft() + getPaddingRight(); maxHeight += getPaddingTop() + getPaddingBottom(); Drawable drawable = getBackground(); if (drawable != null) { maxHeight = Math.max(maxHeight, drawable.getMinimumHeight()); maxWidth = Math.max(maxWidth, drawable.getMinimumWidth()); } setMeasuredDimension(resolveSize(maxWidth, widthMeasureSpec), resolveSize(maxHeight, heightMeasureSpec)); } private void drawPict(Canvas canvas, int x, int y, int w, int h, float sx, float sy) { canvas.save(); canvas.translate(x, y); canvas.clipRect(0, 0, w, h); canvas.scale(0.5f, 0.5f); canvas.scale(sx, sy, w, h); canvas.drawPicture(mPicture); canvas.restore(); } @Override protected void dispatchDraw(Canvas canvas) { super.dispatchDraw(mPicture.beginRecording(getWidth(), getHeight())); mPicture.endRecording(); int x = getWidth() / 2; int y = getHeight() / 2; if (false) { canvas.drawPicture(mPicture); } else { drawPict(canvas, 0, 0, x, y, 1, 1); drawPict(canvas, x, 0, x, y, -1, 1); drawPict(canvas, 0, y, x, y, 1, -1); drawPict(canvas, x, y, x, y, -1, -1); } } @Override public ViewParent invalidateChildInParent(int[] location, Rect dirty) { location[0] = getLeft(); location[1] = getTop(); dirty.set(0, 0, getWidth(), getHeight()); return getParent(); } @Override protected void onLayout(boolean changed, int l, int t, int r, int b) { final int count = super.getChildCount(); for (int i = 0; i < count; i++) { final View child = getChildAt(i); if (child.getVisibility() != GONE) { final int childLeft = getPaddingLeft(); final int childTop = getPaddingTop(); child.layout(childLeft, childTop, childLeft + child.getMeasuredWidth(), childTop + child.getMeasuredHeight()); } } } }
Draw text with custom font
package app.test; import android.app.Activity; import android.graphics.Bitmap; import android.graphics.Canvas; import android.graphics.Color; import android.graphics.Paint; import android.graphics.Typeface; import android.os.Bundle; import android.widget.ImageView; public class Test extends Activity { ImageView drawingImageView; @Override public void onCreate(Bundle savedInstanceState) { super.onCreate(savedInstanceState); setContentView(R.layout.main); drawingImageView = (ImageView) this.findViewById(R.id.DrawingImageView); Bitmap bitmap = Bitmap.createBitmap((int) getWindowManager() .getDefaultDisplay().getWidth(), (int) getWindowManager() .getDefaultDisplay().getHeight(), Bitmap.Config.ARGB_8888); Canvas canvas = new Canvas(bitmap); drawingImageView.setImageBitmap(bitmap); // Custom Font Text Paint paint = new Paint(); paint.setColor(Color.GREEN); paint.setTextSize(40); Typeface chops = Typeface.createFromAsset(getAssets(), "ChopinScript.ttf"); paint.setTypeface(chops); float text_x = 120; float text_y = 120; canvas.drawText("Hello", text_x, text_y, paint); } }