Possible bug using ImageSpans inside MenuItem titles (showing icons with text in menus)












0















I like icons in my menus, so I have been using a SpannableString with an ImageSpan in my menu item titles. It works fine, but now I want to tint the icons to reflect whether the menu item is enabled or not. When I changed the code so I can keep a reference to the icon drawable, the icons stopped being displayed.



Working code:



    MenuItem item = menu.findItem(itemId);
SpannableStringBuilder builder = new SpannableStringBuilder(" " +
c.getResources().getString(labelId));
builder.setSpan(new ImageSpan(c, iconId), 0, 1,
Spanned.SPAN_EXCLUSIVE_EXCLUSIVE);
item.setTitle(builder);


Does not display the icon:



    MenuItem item = menu.findItem(itemId);
Drawable icon = c.getResources().getDrawable(iconId);
SpannableStringBuilder builder = new SpannableStringBuilder(" " +
c.getResources().getString(labelId));
builder.setSpan(new ImageSpan(icon), 0, 1,
Spanned.SPAN_EXCLUSIVE_EXCLUSIVE);
item.setTitle(builder);


I suspect it may be due to the fact that I use vector drawables for my icons. I am wondering if anyone has run into this before and is there an easy way to rasterize my vector icons for the ImageSpan constructor?



(I tried using the ContextCompat.getDrawable() and that did not work either and I am using the support library AppBarLayout and ToolBar)



Update:
I did not get the above code to work, but Mike showed me how to get around the problem. Here is my updated function that you can use in your programs:



/**
* Prepends an icon to the menu item's title
* @param c the menu's context
* @param menu the menu
* @param itemId the menu item
* @param labelId the menu label
* @param iconId the icon
* @return the icon as a Drawable
*/
public static Drawable iconifyMenuItem(Context c, Menu menu, int itemId, int labelId, int iconId) {
MenuItem item = menu.findItem(itemId);
ImageSpan icon = new ImageSpan(c, iconId);
SpannableStringBuilder builder = new SpannableStringBuilder(" " + c.getResources().getString(labelId));
builder.setSpan(icon, 0, 1, Spanned.SPAN_EXCLUSIVE_EXCLUSIVE);
item.setTitle(builder);
return icon.getDrawable();
}









share|improve this question

























  • Glancing at the source, when you pass a Drawable directly yourself, it looks like ImageSpan does not explicitly set bounds on it, presumably leaving that up to the caller. Try doing icon.setBounds(0, 0, icon.getIntrinsicWidth(), icon.getIntrinsicHeight()); before passing it to the ImageSpan.

    – Mike M.
    Jan 19 at 6:25











  • Nope Mike, but good try. I would like to try to convert it to a BitmapDrawable and feed that into the ImageSpan(), but I don't know how to get "correct" values for the size of the bitmap...

    – Phil
    Jan 19 at 6:46











  • @Phil drawable.setBounds(0, 0, drawable.getIntrinsicWidth(), drawable.getIntrinsicHeight()); you can play with values to set it to within the bounds of the menuitem since you can call height and width properties on them too

    – Karan Harsh Wardhan
    Jan 19 at 6:55











  • Hmm, that's odd. I just had a more thorough look through the source, and that's really the only difference. Anyway, until I figure that one out, there's another way to do this that really should work. You can get the constructed Drawable from the ImageSpan, instead of creating it yourself first. That is, ImageSpan span = new ImageSpan(c, iconId);, Drawable icon = span.getDrawable();, ..., builder.setSpan(span, ...);.

    – Mike M.
    Jan 19 at 7:13






  • 1





    Mike, that worked. Thank you! The icon appears in the menu and its color changes when I tint it.

    – Phil
    Jan 19 at 7:26
















0















I like icons in my menus, so I have been using a SpannableString with an ImageSpan in my menu item titles. It works fine, but now I want to tint the icons to reflect whether the menu item is enabled or not. When I changed the code so I can keep a reference to the icon drawable, the icons stopped being displayed.



Working code:



    MenuItem item = menu.findItem(itemId);
SpannableStringBuilder builder = new SpannableStringBuilder(" " +
c.getResources().getString(labelId));
builder.setSpan(new ImageSpan(c, iconId), 0, 1,
Spanned.SPAN_EXCLUSIVE_EXCLUSIVE);
item.setTitle(builder);


Does not display the icon:



    MenuItem item = menu.findItem(itemId);
Drawable icon = c.getResources().getDrawable(iconId);
SpannableStringBuilder builder = new SpannableStringBuilder(" " +
c.getResources().getString(labelId));
builder.setSpan(new ImageSpan(icon), 0, 1,
Spanned.SPAN_EXCLUSIVE_EXCLUSIVE);
item.setTitle(builder);


I suspect it may be due to the fact that I use vector drawables for my icons. I am wondering if anyone has run into this before and is there an easy way to rasterize my vector icons for the ImageSpan constructor?



(I tried using the ContextCompat.getDrawable() and that did not work either and I am using the support library AppBarLayout and ToolBar)



Update:
I did not get the above code to work, but Mike showed me how to get around the problem. Here is my updated function that you can use in your programs:



/**
* Prepends an icon to the menu item's title
* @param c the menu's context
* @param menu the menu
* @param itemId the menu item
* @param labelId the menu label
* @param iconId the icon
* @return the icon as a Drawable
*/
public static Drawable iconifyMenuItem(Context c, Menu menu, int itemId, int labelId, int iconId) {
MenuItem item = menu.findItem(itemId);
ImageSpan icon = new ImageSpan(c, iconId);
SpannableStringBuilder builder = new SpannableStringBuilder(" " + c.getResources().getString(labelId));
builder.setSpan(icon, 0, 1, Spanned.SPAN_EXCLUSIVE_EXCLUSIVE);
item.setTitle(builder);
return icon.getDrawable();
}









share|improve this question

























  • Glancing at the source, when you pass a Drawable directly yourself, it looks like ImageSpan does not explicitly set bounds on it, presumably leaving that up to the caller. Try doing icon.setBounds(0, 0, icon.getIntrinsicWidth(), icon.getIntrinsicHeight()); before passing it to the ImageSpan.

    – Mike M.
    Jan 19 at 6:25











  • Nope Mike, but good try. I would like to try to convert it to a BitmapDrawable and feed that into the ImageSpan(), but I don't know how to get "correct" values for the size of the bitmap...

    – Phil
    Jan 19 at 6:46











  • @Phil drawable.setBounds(0, 0, drawable.getIntrinsicWidth(), drawable.getIntrinsicHeight()); you can play with values to set it to within the bounds of the menuitem since you can call height and width properties on them too

    – Karan Harsh Wardhan
    Jan 19 at 6:55











  • Hmm, that's odd. I just had a more thorough look through the source, and that's really the only difference. Anyway, until I figure that one out, there's another way to do this that really should work. You can get the constructed Drawable from the ImageSpan, instead of creating it yourself first. That is, ImageSpan span = new ImageSpan(c, iconId);, Drawable icon = span.getDrawable();, ..., builder.setSpan(span, ...);.

    – Mike M.
    Jan 19 at 7:13






  • 1





    Mike, that worked. Thank you! The icon appears in the menu and its color changes when I tint it.

    – Phil
    Jan 19 at 7:26














0












0








0








I like icons in my menus, so I have been using a SpannableString with an ImageSpan in my menu item titles. It works fine, but now I want to tint the icons to reflect whether the menu item is enabled or not. When I changed the code so I can keep a reference to the icon drawable, the icons stopped being displayed.



Working code:



    MenuItem item = menu.findItem(itemId);
SpannableStringBuilder builder = new SpannableStringBuilder(" " +
c.getResources().getString(labelId));
builder.setSpan(new ImageSpan(c, iconId), 0, 1,
Spanned.SPAN_EXCLUSIVE_EXCLUSIVE);
item.setTitle(builder);


Does not display the icon:



    MenuItem item = menu.findItem(itemId);
Drawable icon = c.getResources().getDrawable(iconId);
SpannableStringBuilder builder = new SpannableStringBuilder(" " +
c.getResources().getString(labelId));
builder.setSpan(new ImageSpan(icon), 0, 1,
Spanned.SPAN_EXCLUSIVE_EXCLUSIVE);
item.setTitle(builder);


I suspect it may be due to the fact that I use vector drawables for my icons. I am wondering if anyone has run into this before and is there an easy way to rasterize my vector icons for the ImageSpan constructor?



(I tried using the ContextCompat.getDrawable() and that did not work either and I am using the support library AppBarLayout and ToolBar)



Update:
I did not get the above code to work, but Mike showed me how to get around the problem. Here is my updated function that you can use in your programs:



/**
* Prepends an icon to the menu item's title
* @param c the menu's context
* @param menu the menu
* @param itemId the menu item
* @param labelId the menu label
* @param iconId the icon
* @return the icon as a Drawable
*/
public static Drawable iconifyMenuItem(Context c, Menu menu, int itemId, int labelId, int iconId) {
MenuItem item = menu.findItem(itemId);
ImageSpan icon = new ImageSpan(c, iconId);
SpannableStringBuilder builder = new SpannableStringBuilder(" " + c.getResources().getString(labelId));
builder.setSpan(icon, 0, 1, Spanned.SPAN_EXCLUSIVE_EXCLUSIVE);
item.setTitle(builder);
return icon.getDrawable();
}









share|improve this question
















I like icons in my menus, so I have been using a SpannableString with an ImageSpan in my menu item titles. It works fine, but now I want to tint the icons to reflect whether the menu item is enabled or not. When I changed the code so I can keep a reference to the icon drawable, the icons stopped being displayed.



Working code:



    MenuItem item = menu.findItem(itemId);
SpannableStringBuilder builder = new SpannableStringBuilder(" " +
c.getResources().getString(labelId));
builder.setSpan(new ImageSpan(c, iconId), 0, 1,
Spanned.SPAN_EXCLUSIVE_EXCLUSIVE);
item.setTitle(builder);


Does not display the icon:



    MenuItem item = menu.findItem(itemId);
Drawable icon = c.getResources().getDrawable(iconId);
SpannableStringBuilder builder = new SpannableStringBuilder(" " +
c.getResources().getString(labelId));
builder.setSpan(new ImageSpan(icon), 0, 1,
Spanned.SPAN_EXCLUSIVE_EXCLUSIVE);
item.setTitle(builder);


I suspect it may be due to the fact that I use vector drawables for my icons. I am wondering if anyone has run into this before and is there an easy way to rasterize my vector icons for the ImageSpan constructor?



(I tried using the ContextCompat.getDrawable() and that did not work either and I am using the support library AppBarLayout and ToolBar)



Update:
I did not get the above code to work, but Mike showed me how to get around the problem. Here is my updated function that you can use in your programs:



/**
* Prepends an icon to the menu item's title
* @param c the menu's context
* @param menu the menu
* @param itemId the menu item
* @param labelId the menu label
* @param iconId the icon
* @return the icon as a Drawable
*/
public static Drawable iconifyMenuItem(Context c, Menu menu, int itemId, int labelId, int iconId) {
MenuItem item = menu.findItem(itemId);
ImageSpan icon = new ImageSpan(c, iconId);
SpannableStringBuilder builder = new SpannableStringBuilder(" " + c.getResources().getString(labelId));
builder.setSpan(icon, 0, 1, Spanned.SPAN_EXCLUSIVE_EXCLUSIVE);
item.setTitle(builder);
return icon.getDrawable();
}






android






share|improve this question















share|improve this question













share|improve this question




share|improve this question








edited Jan 20 at 1:06







Phil

















asked Jan 19 at 6:16









PhilPhil

11




11













  • Glancing at the source, when you pass a Drawable directly yourself, it looks like ImageSpan does not explicitly set bounds on it, presumably leaving that up to the caller. Try doing icon.setBounds(0, 0, icon.getIntrinsicWidth(), icon.getIntrinsicHeight()); before passing it to the ImageSpan.

    – Mike M.
    Jan 19 at 6:25











  • Nope Mike, but good try. I would like to try to convert it to a BitmapDrawable and feed that into the ImageSpan(), but I don't know how to get "correct" values for the size of the bitmap...

    – Phil
    Jan 19 at 6:46











  • @Phil drawable.setBounds(0, 0, drawable.getIntrinsicWidth(), drawable.getIntrinsicHeight()); you can play with values to set it to within the bounds of the menuitem since you can call height and width properties on them too

    – Karan Harsh Wardhan
    Jan 19 at 6:55











  • Hmm, that's odd. I just had a more thorough look through the source, and that's really the only difference. Anyway, until I figure that one out, there's another way to do this that really should work. You can get the constructed Drawable from the ImageSpan, instead of creating it yourself first. That is, ImageSpan span = new ImageSpan(c, iconId);, Drawable icon = span.getDrawable();, ..., builder.setSpan(span, ...);.

    – Mike M.
    Jan 19 at 7:13






  • 1





    Mike, that worked. Thank you! The icon appears in the menu and its color changes when I tint it.

    – Phil
    Jan 19 at 7:26



















  • Glancing at the source, when you pass a Drawable directly yourself, it looks like ImageSpan does not explicitly set bounds on it, presumably leaving that up to the caller. Try doing icon.setBounds(0, 0, icon.getIntrinsicWidth(), icon.getIntrinsicHeight()); before passing it to the ImageSpan.

    – Mike M.
    Jan 19 at 6:25











  • Nope Mike, but good try. I would like to try to convert it to a BitmapDrawable and feed that into the ImageSpan(), but I don't know how to get "correct" values for the size of the bitmap...

    – Phil
    Jan 19 at 6:46











  • @Phil drawable.setBounds(0, 0, drawable.getIntrinsicWidth(), drawable.getIntrinsicHeight()); you can play with values to set it to within the bounds of the menuitem since you can call height and width properties on them too

    – Karan Harsh Wardhan
    Jan 19 at 6:55











  • Hmm, that's odd. I just had a more thorough look through the source, and that's really the only difference. Anyway, until I figure that one out, there's another way to do this that really should work. You can get the constructed Drawable from the ImageSpan, instead of creating it yourself first. That is, ImageSpan span = new ImageSpan(c, iconId);, Drawable icon = span.getDrawable();, ..., builder.setSpan(span, ...);.

    – Mike M.
    Jan 19 at 7:13






  • 1





    Mike, that worked. Thank you! The icon appears in the menu and its color changes when I tint it.

    – Phil
    Jan 19 at 7:26

















Glancing at the source, when you pass a Drawable directly yourself, it looks like ImageSpan does not explicitly set bounds on it, presumably leaving that up to the caller. Try doing icon.setBounds(0, 0, icon.getIntrinsicWidth(), icon.getIntrinsicHeight()); before passing it to the ImageSpan.

– Mike M.
Jan 19 at 6:25





Glancing at the source, when you pass a Drawable directly yourself, it looks like ImageSpan does not explicitly set bounds on it, presumably leaving that up to the caller. Try doing icon.setBounds(0, 0, icon.getIntrinsicWidth(), icon.getIntrinsicHeight()); before passing it to the ImageSpan.

– Mike M.
Jan 19 at 6:25













Nope Mike, but good try. I would like to try to convert it to a BitmapDrawable and feed that into the ImageSpan(), but I don't know how to get "correct" values for the size of the bitmap...

– Phil
Jan 19 at 6:46





Nope Mike, but good try. I would like to try to convert it to a BitmapDrawable and feed that into the ImageSpan(), but I don't know how to get "correct" values for the size of the bitmap...

– Phil
Jan 19 at 6:46













@Phil drawable.setBounds(0, 0, drawable.getIntrinsicWidth(), drawable.getIntrinsicHeight()); you can play with values to set it to within the bounds of the menuitem since you can call height and width properties on them too

– Karan Harsh Wardhan
Jan 19 at 6:55





@Phil drawable.setBounds(0, 0, drawable.getIntrinsicWidth(), drawable.getIntrinsicHeight()); you can play with values to set it to within the bounds of the menuitem since you can call height and width properties on them too

– Karan Harsh Wardhan
Jan 19 at 6:55













Hmm, that's odd. I just had a more thorough look through the source, and that's really the only difference. Anyway, until I figure that one out, there's another way to do this that really should work. You can get the constructed Drawable from the ImageSpan, instead of creating it yourself first. That is, ImageSpan span = new ImageSpan(c, iconId);, Drawable icon = span.getDrawable();, ..., builder.setSpan(span, ...);.

– Mike M.
Jan 19 at 7:13





Hmm, that's odd. I just had a more thorough look through the source, and that's really the only difference. Anyway, until I figure that one out, there's another way to do this that really should work. You can get the constructed Drawable from the ImageSpan, instead of creating it yourself first. That is, ImageSpan span = new ImageSpan(c, iconId);, Drawable icon = span.getDrawable();, ..., builder.setSpan(span, ...);.

– Mike M.
Jan 19 at 7:13




1




1





Mike, that worked. Thank you! The icon appears in the menu and its color changes when I tint it.

– Phil
Jan 19 at 7:26





Mike, that worked. Thank you! The icon appears in the menu and its color changes when I tint it.

– Phil
Jan 19 at 7:26












0






active

oldest

votes











Your Answer






StackExchange.ifUsing("editor", function () {
StackExchange.using("externalEditor", function () {
StackExchange.using("snippets", function () {
StackExchange.snippets.init();
});
});
}, "code-snippets");

StackExchange.ready(function() {
var channelOptions = {
tags: "".split(" "),
id: "1"
};
initTagRenderer("".split(" "), "".split(" "), channelOptions);

StackExchange.using("externalEditor", function() {
// Have to fire editor after snippets, if snippets enabled
if (StackExchange.settings.snippets.snippetsEnabled) {
StackExchange.using("snippets", function() {
createEditor();
});
}
else {
createEditor();
}
});

function createEditor() {
StackExchange.prepareEditor({
heartbeatType: 'answer',
autoActivateHeartbeat: false,
convertImagesToLinks: true,
noModals: true,
showLowRepImageUploadWarning: true,
reputationToPostImages: 10,
bindNavPrevention: true,
postfix: "",
imageUploader: {
brandingHtml: "Powered by u003ca class="icon-imgur-white" href="https://imgur.com/"u003eu003c/au003e",
contentPolicyHtml: "User contributions licensed under u003ca href="https://creativecommons.org/licenses/by-sa/3.0/"u003ecc by-sa 3.0 with attribution requiredu003c/au003e u003ca href="https://stackoverflow.com/legal/content-policy"u003e(content policy)u003c/au003e",
allowUrls: true
},
onDemand: true,
discardSelector: ".discard-answer"
,immediatelyShowMarkdownHelp:true
});


}
});














draft saved

draft discarded


















StackExchange.ready(
function () {
StackExchange.openid.initPostLogin('.new-post-login', 'https%3a%2f%2fstackoverflow.com%2fquestions%2f54264581%2fpossible-bug-using-imagespans-inside-menuitem-titles-showing-icons-with-text-in%23new-answer', 'question_page');
}
);

Post as a guest















Required, but never shown

























0






active

oldest

votes








0






active

oldest

votes









active

oldest

votes






active

oldest

votes
















draft saved

draft discarded




















































Thanks for contributing an answer to Stack Overflow!


  • Please be sure to answer the question. Provide details and share your research!

But avoid



  • Asking for help, clarification, or responding to other answers.

  • Making statements based on opinion; back them up with references or personal experience.


To learn more, see our tips on writing great answers.




draft saved


draft discarded














StackExchange.ready(
function () {
StackExchange.openid.initPostLogin('.new-post-login', 'https%3a%2f%2fstackoverflow.com%2fquestions%2f54264581%2fpossible-bug-using-imagespans-inside-menuitem-titles-showing-icons-with-text-in%23new-answer', 'question_page');
}
);

Post as a guest















Required, but never shown





















































Required, but never shown














Required, but never shown












Required, but never shown







Required, but never shown

































Required, but never shown














Required, but never shown












Required, but never shown







Required, but never shown







Popular posts from this blog

Liquibase includeAll doesn't find base path

How to use setInterval in EJS file?

Petrus Granier-Deferre