Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

Porting Java class and methods to Android. (TextLayout, Font, Graphics2D, & more)

I've been toying around in Android and attempting to port over a Java app. Below are some questions regarding to issues I've run into and would like some guidance on.

It is a rather large question (multiple questions rather). However, I'm not asking them blindly as I have researched what I could about them and attempted to put my understanding to use. I've put time into asking the questions in hopes that they are half-ways clear on what I'm wanting to achieve.

I'll be offering half of my rep as a bounty since I'm hoping for thorough answers and help, hopefully it will be enough to entice a few people to help.

In advance, thank you for your time and help! (looking forward to reading responses).

TextLayout && Font && Graphics2D

In question are the following classes and methods:

  • TextLayout
  • TextLayout.getAdvance()
  • TextLayout.getAscent()
  • TextLayout.draw()
  • Graphics2D.getFontRenderContext()

I'm not quite sure what is equivalent of TextLayout in Android. I had read that some make a TextView and use that, but am unsure if that will

work for the following. I'll provide some source of what I'm wanting to do and perhaps one can help me.

Java Source:

private Font myStringFont = new Font("Helvetica", Font.BOLD, 12);
private String myString = "My Test String";
private int midX = getWidth() / 2;
private int midY = getHeight() / 2;
Graphics2D g2 = new Graphics2d();

TextLayout layout = new TextLayout(myString, font, g2.getFontRenderContext());
g2.drawString(myString, midX - ((int)layout.getAdvance() /2), midY);

Android Replication Attempt:

Canvas canvas;
Paint paint;
private String myString = "My Test String";
private float midX = getWidth() / 2;
private float midY = getHeight() / 2;
//Unsure what to do about TextLayout <- this is where I need an alternative
canvas.drawText(myString, midX - /* whatever my alternative to layout.getAdvance() is */ /2), midY);

Im stuck at determining how to create a TextLayout and what to do for the method getAdvance(). I noticed that in Paint.FontMetrics() there are

some possible alternatives, but I don't know if any compare.

I'm also unsure how to deal with the following Java code:

Graphics2D g2 = new Graphics2d();
private int midX = getWidth() / 2;
private int midY = getHeight() / 2;

TextLayout layout = new TextLayout(myString, g2.getFont(), g2.getFontRenderContext());
layout.draw(g2, midX, MidY);

Review/Summary of Questions Above:

  • What is an Android alternative for TextLayout?
  • What is equivalent to TextLayout.getAdvance()? (Am I able to use fontMetrics to achieve it?)
  • Are there Android equivalents to Graphics2D.getFontRenderContext()?
  • Can you provide example source for Android?

This is currently one of my biggest issues with porting Java over to Android. I would be greatful for any help, advice, examples, etc.

Font

Below are the methods I am wanting to replicate that deal with font, textlayout, and graphics2d. The first source is the Java methods and

below it is my attempt to replicate it.

In question are the following classes and methods:

  • Font.deriveFont(float size) Creates a new font objects by replicating the current font object and applying a new style to it
  • TextLayout.getAdvance() The advance is the distance from the origin to the advance of the rightmost (bottommost) character measuring in the line direction
  • Graphics2D.setRenderingHint(RenderingHints, RenderingHints)
  • Graphics2D.getFontRenderContext() Encapsulates application hints such as anti-aliasing and fractional metrics

Java Source:

private String myString = "Print this test statement";
private int myStringFontSize = 15;
private Color myStringFontColor = Color.red;
private Font myStringFont = new Font("Helvetica", Font.BOLD, myStringFontSize);
private int midX = getWidth() / 2;
private int midY = getHeight() / 2;

public drawString(Graphics2D g2) {
    g2.setFont(myStringFont.deriveFont(determineFontSize(g2, myString)));
    g2.setRenderingHint(RenderingHints.KEY_TEXT_ANTIALISING, RenderingHints.VALUE_TEXT_ANTIALIAS_ON);
    TextLayout layout = new TextLayout(myString, g2.getFont(), g2.getFontRenderContext());

    g2.setPaint(myStringFontColor);
    g2.drawString(myString, midX - ((int) layout.getAdvance() / 2), midY);
}

protected float determinFontSize(Graphics2D g2, String myString) {
    int space = getWidth();
    float fontSize = 1.0f;
    float finalFontSize = fontSize;

    while(fontSize < 25) {
        Font font myString.deriveFont(fontSize);
        Textlayout layout = new TextLayout(waitingMessage, font, g2.getFontRenderContext());

        if(layout.getAdvance() > space) {
            finalFontSize = fontSize - 2;
            break;
        }
        fontSize++;
    }
    finalFontSize = fontSize - 4;
    return finalFontSize;
}

Android Attempt:

private String myString = "Print this test statement";
private int myStringFontSize = 15;
private int myStringFontColor = Color.RED;  //Android uses int rather than Color
Typeface tf = new Typeface();               //Android uses Typeface rather than Font  
private float midX = getWidth() / 2;        //Changed to float because drawText requires float
private float midY = getHeight() / 2;       //changed to float because drawText requires float


public drawString(Canvas canvas, Paint paint) {
    tf.create("Helvetica", BOLD);
    paint.setTypeface(tf);
    paint.setTextSize((float) myStringFontSize);

    paint.setTextSize(determineFontSize(canvas, myString, paint);
    paint.setAntiAlias(true);
    //NOT SURE WHAT TO DO WITH TextLayout YET

    paint.setColor(myStringFontColor);
    canvas.drawText(myString, midX - ((int)layout.getAdvance() / 2), midY, paint);  //Not sure how to deal with layout.getAdvance() just yet    

}

protected float determineFontSize(Canvas canvas, String myString, Paint paint) {
    float fontSize = 1.0f;
    float finalFontSize = fontSize;
    int space = getWidth();

    while(fontSize < 25) {
        paint.setTextSize(fontSize);
        //NOT SURE WHAT TO DO ABOUT TextLayout.getAdvance() YET or g2.getFontRenderContext()

        if(layout.getAdvance() > space) {
            finalFontSize = fontSize - 2;
            break;
        }
        fontSize++;
    }
    finalFontSize = fontSize - 4;
    return finalFontSize;            
}

Final Questions About The Above Methods:

  • What alternative do I have for TextLayout.getAdvance()? (Ignore if it has been answered due to the question regarding TextLayout)
  • What alternative do I have for Graphics2D.getFontRenderContext()?
  • Does my Android source replicate the Java source? If not, what needs to be changed?
  • Are there better ways of doing this? If so, how?

Elipse2D.Double(double x, double y, double w, double h)

Is there a way to make a subclass of oval to create something equal to Java Ellipse2D.Double? If so, how would one go about it?

ComponentAdapter && ComponentEvent

I have these in java because my component is able to be resized, in Android what are the equivalents of these for views? (if any)

like image 634
StartingGroovy Avatar asked Jul 25 '11 21:07

StartingGroovy


2 Answers

The TextLayout, Font and Graphics2D question can be achieved simply in Android by using a TextView, some layout attributes in the layout xml file and possibly augmenting it with some code. To illustrate with an example, the TextView could be declared in the layout xml as follows:

<TextView android:id="@+id/logo"
    android:layout_width="0dip"
    android:layout_height="wrap_content"
    android:paddingTop="5dip"
    android:text="Fancy Logo"
    android:textSize="24sp"
    android:layout_weight="0.8"
    android:textStyle="bold"
    android:textColor="@color/black" />

Most of the attributes are self-explanatory, but the layout_width hasn't been set as we'll augment the TextView with a Font which will affect the width it takes up.

AssetManager assetManager = getContext().getAssets();       

Typeface tf = Typeface.createFromAsset(assetManager,"GILB.TTF");                

TextView logo = (TextView)findViewById(R.id.logo);
logo.setTypeface(tf);

The setTypeface() method is overloaded with an additional style parameter which can also provide bold and/or italic effects.

The specific position this text is drawn on-screen will be dependent on the layout or combinations of layouts you choose e.g. RelativeLayout, AbsoluteLayout, etc - there are a lot of resources which can teach you how to use these to good effect.

If this is too limited, then you can draw on the Canvas directly. Here, you can specify a Paint, or TextPaint object, where you can set anti-aliasing and several other paint effects.

In place of Ellipse2D.Double, you could use Canvas.drawOval(RectF oval, Paint paint) where the RectF object specifies the bounding box for the oval.

To enable views (components) to be resized automatically, you should use where possible, flexible layout attributes such as wrap_content, match_parent or fill_parent rather than specific 'dip' sizes. Graphics should be converted to 9-patch formats so that they can stretch to accommodate size changes.

If you really need to calculate the length of text, or specify text size to fit a specific physical space, then you can refer to this answer on SO.

like image 132
John J Smith Avatar answered Nov 07 '22 15:11

John J Smith


There is no exact equivalent to TextLayout but you can use FontMetrics (see the Paint) class to get the advance and ascent. To draw text, simply use a Canvas. There is no equivalent of FontRenderContext (it's not needed on Android.)

Graphics2D's rendering hints equivalents are simply properties on the Paint class. Font.deriveFont() has no equivalent, simply set the appropriate properties on Paint.

Ovals are drawn using a Canvas, there is no Oval class. You can use a Path instance to do the same thing though.

like image 39
Romain Guy Avatar answered Nov 07 '22 17:11

Romain Guy