Material design icons in action bar


#1

Hi there,

I can’t seem to get my icons to display in the action bar. Below is my code, can someone please tell me what I am doing wrong? It works in the normal body of the app, and I have tried it without the labels too, as just properties of the NavigationBar element, same thing: does not display.

<ActionBar class="action-bar" title="My Bookings">
        <NavigationButton ios:visibility="collapsed" tap="onDrawerButtonTap">
            <Label text="menu" class="mdi" />
        </NavigationButton>
        <!--<NavigationButton ios:visibility="collapsed" icon="res://menu" tap="onDrawerButtonTap"></NavigationButton>-->
        <ActionItem text="menu" 
            class="mdi"
            android:visibility="collapsed" 
            tap="onDrawerButtonTap"
            ios.position="left">
        </ActionItem>
        <!--<ActionItem icon="res://navigation/menu" 
            android:visibility="collapsed" 
            tap="onDrawerButtonTap"
            ios.position="left">
        </ActionItem>-->
    </ActionBar>

The commented out code is what I had before I included material design icons.


#2

When you say material design icons, do you mean the font icons or the actual image icons?

If you are trying to apply font icon, it’s not possible to apply font on the navigation bar items in Android until you use a custom view. You will have to apply a custom action view, use a label / butotn to apply font icon.

If you really want to utlize font icon without a custom view, you may programmatically create image version of the icon and assign same with little native code.


#3

Ideally I would like to use the fonts as they take up less space. Otherwise I guess images will have to do for the navigation/action bar at lease.

Can you provide me some dummy/working code on how to do either? The inclusion of images and the custom view you refer to?


#4

You may use anything inside custom view, I think a label / button with font applied should work for you.

https://docs.nativescript.org/ui/action-bar#using-custom-view-in-action-items

As I mentioned already, you can build the image at runtime from font icon at least for using action bar which will not have any impact on size of your package.


#5

If you really want to utlize font icon without a custom view, you may programmatically create image version of the icon and assign same with little native code.

How would I do that?


#6

HO do I do a custom view inside the NavigationItem?


#7

I have posted the exact link for docs where custom views are explained. Did you check them?


#8

I did. They only talk about custom views in actionItems, not NavigationItems. I need it for the menu button on Android too, which users NavigationItem.


#9

What you mean by NavigationItem, is it NavigationButton? It should be the same as it inherited from ActionItem.


#10

Ah yes, I mean NavigationButton, my apologies. But in Action items they use <ActionItem.actionView>, what will I use in NavigationButton?


#11

Sorry, I almost forgot. You can’t customize NavigationButton, you will be able to set only the icon (image) there and nothing else, the limitation is from Android.

An alternative is to use a TitleView.
docs: https://docs.nativescript.org/ui/action-bar#using-a-custom-title-view

I’m not finding time to experiment converting a font icon to image at run time, when I do I may post it here.


#12

Thanks so much for your help so far, I understand you’re busy too!

I will check it out, thanks! :slight_smile:

Please do post if you find some time :slight_smile:


#13

I have implemented the Android version here. Yet to look at iOS.

Inspired by react-native-vector-icons plugin.


#14

Here a working version for both iOS and Android, utilizes material icons (or any font icon) for ActionBar and TabView etc.,

But the one tiny issue is, font scale in Android seems not perfect or results in too low resolution images. In my example, I expect 48 pixel (internally converted as - 48 x display density) to give better resolution image for action bar but it’s too low.

If anyone of you can take a look and provide any suggestion or feedback will be great @Pete.K, @jen.looper, @Eddy, @multishiv19, @bradwaynemartin.


#15

Not really sure - did you play with paint.setTextSize(layout.toDevicePixels(font.fontSize)); trying different approaches here?

Very cool stuff BTW, if you get that cleaned up on Android, are you going to publish this as a plugin? I can see this being very useful in a lot of use cases. Great work @manojdcoder


#16

Thank you @bradwaynemartin. Yes of course I’m planning to release this as plugin once I cleanup Android.

I’m playing with setTextSize and textBounds to see where exactly the issue is. Thanks for the tip.


#17

Great work @manojdcoder
Loved the idea.


#18

After digging a while, I found the image being created is just perfect but the problem is with the way icon is loaded in {N}. To be more precise, at this line

Looks like we are using a deprecated version of the BitmapDrawable(Bitmap bitmap) constructor here, it’s recommended to use BitmapDrawable(Resources res, Bitmap bitmap) to get right one based on device density.

You may verify this by replacing the code of app.ts in my playground example.

import * as app from 'application';
import { isIOS, isAndroid } from 'platform';
import { Color } from 'color';
import { ActionBar, ActionItem } from 'ui/action-bar';

declare var android, java;

if (isIOS) {
    (<any>ActionBar.prototype).originalUpdateColors = (<any>ActionBar.prototype).updateColors;
    (<any>ActionBar.prototype).updateColors = function (navigationBar) {
        this.originalUpdateColors(navigationBar);
        this.nativeView.tintColor = new Color('green').ios;
    };
}

if (isAndroid) {
    (<any>ActionBar.prototype)._addActionItems = function () {
        let menu = this.nativeViewProtected.getMenu();
        let items = this.actionItems.getVisibleItems();

        menu.clear();
        for (let i = 0; i < items.length; i++) {
            let item = <ActionItem>items[i];
            let menuItem = menu.add(android.view.Menu.NONE, (<any>item)._getItemId(), android.view.Menu.NONE, item.text + "");
            let filePath = item.icon
            if (filePath) {
                // *** Important ***
                const bitmap = android.graphics.BitmapFactory.decodeFile(filePath);
                menuItem.setIcon(new android.graphics.drawable.BitmapDrawable(app.android.context.getResources(), bitmap));
            }
            menuItem.setShowAsAction(android.view.MenuItem.SHOW_AS_ACTION_ALWAYS);
        }
    };
}

app.start({ moduleName: 'home/home-page' });

The problem should be similar with TabView as well,


#19

@multishiv19 @bradwaynemartin Finally I found some time to wrap up the same as plugin.


#20

Amazing work @manojdcoder ! How would I use the plugin in a {N} Core JS app? Your API note is understandable to me, but I just don’t know nhow to use it. How would I assign that vector to a specific tab?

Great work again!