[F/OS] ๐Ÿ”˜ Button Icon Extension - Android, Material and Custom Icons

Could the material icons be made to show in companion if one used a ttf font file, as with @Anke 's extension?

Do you add text to a button using the standard button text property?

No, there is a function in TextView that allows you to assign a Drawable to a button. You can take a look at the source code.

I do not see in your extension blocks where one would add the text?

Try it in the built app.

1 Like

What does that mean? (The assets are in the ASD with Companion).

The extension assets are not sent over to the Companion, but it is compiled with the built app. (this is with extensions template)

Still not answered my question about button text...

You don't need to add the text, because the extension only changes the drawable of the button, not the text. Those are two different properties of a Button.

And yes, you add the text using the Text property. It's in the AIA file.

Thank you :blush:

1 Like

one suggestion:
for this block:
https://community.appinventor.mit.edu/uploads/default/original/3X/c/0/c09bb463f7f9368ff2d5d91d799da3913e53765d.png
you can add a line to avoid use the replace block by users.

public Drawable createDrawable(String path) {
      if(path.startsWith("file://")) {
			path = path.replace("file://", "");
		}
        if (path == "") {
            return null;
        } else {
3 Likes

Reworked (using RUSH) with a bit of extra code to make a temp file of the ttf, and now works in companion and when compiled:

JAVA
package uk.co.metricrat.buttonmaticon;


import android.graphics.Canvas;
import com.google.appinventor.components.annotations.SimpleFunction;
import com.google.appinventor.components.runtime.AndroidNonvisibleComponent;
import com.google.appinventor.components.runtime.AndroidViewComponent;
import com.google.appinventor.components.runtime.ComponentContainer;
import android.widget.Button;
import android.graphics.Paint;
import java.io.*;
import java.io.File;
import android.graphics.Bitmap;
import android.graphics.drawable.Drawable;
import android.graphics.Typeface;
import android.graphics.drawable.BitmapDrawable;
import android.util.DisplayMetrics;


public class ButtonMatIcon extends AndroidNonvisibleComponent {
  String filePath;
  String newFilePath;
  public ButtonMatIcon(ComponentContainer container) {
    super(container.$form());
  }


  public String GetFont() throws IOException {

    File file = File.createTempFile("temp", ".ttf");
    filePath = file.getAbsolutePath();
    try {
      InputStream in = form.openAssetForExtension(this, "material-icons.ttf");
      int size = in.available();
      byte[] buffer = new byte[size];
      in.read(buffer);
      in.close();
      FileOutputStream out = new FileOutputStream(filePath);
      out.write(buffer);
      out.close();
    } catch (IOException e) {
      e.printStackTrace();
    }
    return filePath;
  }


  public Drawable createMaterialIcon(String icon, int color, int size) throws IOException {
    if (icon == "") {
      return null;
    } else {
      newFilePath = GetFont();
      Typeface typeface = Typeface.createFromFile(newFilePath);
      Paint paint = new Paint();
      paint.setTypeface(typeface);
      paint.setColor(color);
      paint.setTextSize((float)size);
      paint.setTextAlign(Paint.Align.CENTER);
      Bitmap bit = Bitmap.createBitmap(size, size, Bitmap.Config.ARGB_8888);
      Canvas canvas = new Canvas(bit);
      canvas.drawText(icon, (float) (canvas.getWidth() / 2),   (((float) (canvas.getHeight() / 2)) - ((paint.descent() + paint.ascent()) / 2)), paint);
      return new BitmapDrawable(form.getResources(), bit);
    }
  }

  @SimpleFunction(description = "Sets the material icon of the specified button. Use an empty text block if you do not want an icon to appear. The size of the icons should be in pixels.")
  public void SetMaterialButtonIcons(AndroidViewComponent component, String leftIcon, String topIcon, String rightIcon, String bottomIcon, int color, int size) throws IOException {
    Button button = (Button) component.getView();
    int pixels = size * getDensity();
    button.setCompoundDrawablesWithIntrinsicBounds(createMaterialIcon(leftIcon, color, pixels), createMaterialIcon(topIcon, color, pixels),
            createMaterialIcon(rightIcon, color, pixels), createMaterialIcon(bottomIcon, color, pixels));
  }

  @SimpleFunction(description = "Sets the size of the padding between the icon and the text.")
  public void SetIconPadding(AndroidViewComponent component, int padding) {
    Button button = (Button) component.getView();
    button.setCompoundDrawablePadding(padding);
  }

  public int getDensity(){
    DisplayMetrics metrics = form.getResources().getDisplayMetrics();
    return (int) metrics.density;
  }

}

uk.co.metricrat.buttonmaticon.aix (192.5 KB)

image

image

8 Likes

Thank you for all of your suggestions. I made version 2 of this extension that works in the Companion, accepts full paths, and even accepts custom icon fonts. I also renamed SetButtonIcons to SetAndroidButtonIcons because the former sounded too generic.

image

Icon font from: Journal Dingbats 2 Font ยท 1001 Fonts

Credits: @TIMAI2, @Kevinkun Thank you both!

4 Likes

below code can get Typeface no mater the font file at assets or asd, then no need to copy font file from asset to asd.

Typeface tf = Typeface.DEFAULT;
		if (fontName.startsWith("//")) {
			fontName = fontName.substring(2);
			if (isReplForm) {
				String realpath;
				String files = this.context.getExternalFilesDir(null).getPath();
				if (Build.VERSION.SDK_INT >= 29) {
					realpath = files + "/assets/" + fontName;
				} else {
					realpath = files + "/AppInventor/assets/" + fontName;
				}
				tf = Typeface.createFromFile(realpath);
			} else {
				tf = Typeface.createFromAsset(this.context.getAssets(), fontName);
			}
		} else {
			if (fontName.toLowerCase().startsWith("file://")) {
				fontName = fontName.substring(7);
			}
			tf = Typeface.createFromFile(fontName);
		}
5 Likes

Thanks @gordonlu310 for such a long awaited and useful feature!

1 Like

Hello, I'm trying to add my custom icon to the button I created. I followed the blocks displayed above when putting custom buttons, but it didn't work. What did I do wrong?


I want to put the icon on the left side of the button with the text "Restaurants Near Me."

I would appreciate your help. Thank you!

For this version, you will have to also copy the image to ASD before you set the custom button icons. Look at the sample project.

Do You plan to implement Materia Symbols?

Material icons are already implemented. I can add Material Symbols Rounded if you want to.

I know, that there are Material Icons. Bug it will be great to have Material Symbols also.

1 Like