Possible bug using ImageSpans inside MenuItem titles (showing icons with text in menus)
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
|
show 7 more comments
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
Glancing at the source, when you pass aDrawable
directly yourself, it looks likeImageSpan
does not explicitly set bounds on it, presumably leaving that up to the caller. Try doingicon.setBounds(0, 0, icon.getIntrinsicWidth(), icon.getIntrinsicHeight());
before passing it to theImageSpan
.
– 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 constructedDrawable
from theImageSpan
, 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
|
show 7 more comments
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
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
android
edited Jan 20 at 1:06
Phil
asked Jan 19 at 6:16
PhilPhil
11
11
Glancing at the source, when you pass aDrawable
directly yourself, it looks likeImageSpan
does not explicitly set bounds on it, presumably leaving that up to the caller. Try doingicon.setBounds(0, 0, icon.getIntrinsicWidth(), icon.getIntrinsicHeight());
before passing it to theImageSpan
.
– 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 constructedDrawable
from theImageSpan
, 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
|
show 7 more comments
Glancing at the source, when you pass aDrawable
directly yourself, it looks likeImageSpan
does not explicitly set bounds on it, presumably leaving that up to the caller. Try doingicon.setBounds(0, 0, icon.getIntrinsicWidth(), icon.getIntrinsicHeight());
before passing it to theImageSpan
.
– 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 constructedDrawable
from theImageSpan
, 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
|
show 7 more comments
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
});
}
});
Sign up or log in
StackExchange.ready(function () {
StackExchange.helpers.onClickDraftSave('#login-link');
});
Sign up using Google
Sign up using Facebook
Sign up using Email and Password
Post as a guest
Required, but never shown
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
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.
Sign up or log in
StackExchange.ready(function () {
StackExchange.helpers.onClickDraftSave('#login-link');
});
Sign up using Google
Sign up using Facebook
Sign up using Email and Password
Post as a guest
Required, but never shown
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
Sign up or log in
StackExchange.ready(function () {
StackExchange.helpers.onClickDraftSave('#login-link');
});
Sign up using Google
Sign up using Facebook
Sign up using Email and Password
Post as a guest
Required, but never shown
Sign up or log in
StackExchange.ready(function () {
StackExchange.helpers.onClickDraftSave('#login-link');
});
Sign up using Google
Sign up using Facebook
Sign up using Email and Password
Post as a guest
Required, but never shown
Sign up or log in
StackExchange.ready(function () {
StackExchange.helpers.onClickDraftSave('#login-link');
});
Sign up using Google
Sign up using Facebook
Sign up using Email and Password
Sign up using Google
Sign up using Facebook
Sign up using Email and Password
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
Glancing at the source, when you pass a
Drawable
directly yourself, it looks likeImageSpan
does not explicitly set bounds on it, presumably leaving that up to the caller. Try doingicon.setBounds(0, 0, icon.getIntrinsicWidth(), icon.getIntrinsicHeight());
before passing it to theImageSpan
.– 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 theImageSpan
, 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