I am having a problem with changing the font style (non English - Unicode) of the custom keys of android custom keyboard.
I have followed something similar to the answer of this link
and it seems working fine for single character buttons. It will change the font of entire app to the new font including single character keys of the keyboard.
If I wanna change the size of the key text I can use below two entries
android:keyTextSize="25sp" // for single character keys
android:labelTextSize="20sp" // for multiple character keys
But unfortunately method in above link only works for single character keys only. Is there any way to set the font of multiple character keys.
See below image for example:
First button has some default system font while second and third buttons have the correct font.
EDIT:
After reading Bhavita Lalwani answer it got me thinking.
if (label != null) {
// For characters, use large font. For labels like "Done", use small font.
if (label.length() > 1 && key.codes.length < 2) {
paint.setTextSize(mLabelTextSize);
paint.setTypeface(Typeface.DEFAULT_BOLD);
} else {
paint.setTextSize(mKeyTextSize);
paint.setTypeface(Typeface.DEFAULT);
}
}
here it says
if (label.length() > 1 && key.codes.length < 2)
so it uses BOLD fonts for multiple characters only if they have single code.
eg. I think Android Engs thinking about these things. ???
Keyboard.KEYCODE_DONE
Keyboard.KEYCODE_DELETE
So the ugly workaround will be to add multiple codes and only use first code when needed.
<Key android:codes="5001,1" android:keyLabel="AB" android:keyWidth="12%p" />
Now every key with multiple codes also user DEFAULT typeface.
This works for now, (Until I find a proper solution :))
I was having a similar issue in creating Hindi custom keyboard.(Non English-Unicode)
So let's find your culprit why this variation happens.
KeyboardView.java in Android Source code
lines 701-709
if (label != null) {
// For characters, use large font. For labels like "Done", use small font.
if (label.length() > 1 && key.codes.length < 2) {
paint.setTextSize(mLabelTextSize);
paint.setTypeface(Typeface.DEFAULT_BOLD);
} else {
paint.setTextSize(mKeyTextSize);
paint.setTypeface(Typeface.DEFAULT);
}
}
This means it makes multi character labels to Bold and different size.
And single char labels stay as it is.
Solution
Create a CustomKeyboardView class which extends this KeyboardView class
public class CustomKeyboardView extends KeyboardView {
public CustomKeyboardView(Context context, AttributeSet attrs) {
super(context, attrs);
}
Now in this CustomKeyboardView class, override onDraw method. This method would be called when drawing the keyboard and keys on the canvas
#Override
public void onDraw(Canvas canvas) {
super.onDraw(canvas);
Paint mpaint = new Paint();
mpaint.setTypeface(Typeface.DEFAULT_BOLD); //to make all Bold. Choose Default to make all normal font
mpaint.setTextSize(24); // in px
List<Key> keys = getKeyboard().getKeys();
for (Keyboard.Key key : keys) {
if (key.label != null) {
String keyLabel = key.label.toString();
canvas.drawText(keyLabel, key.x + key.width, key.y + key.height, mpaint);
} else if (key.icon != null) {
key.icon.setBounds(key.x, key.y, key.x + key.width, key.y + key.height);
key.icon.draw(canvas);
}
}
}
You can use this cheatcode to use sp for setTextSize method
<?xml version="1.0" encoding="utf-8"?>
<resources>
<dimen name="custom_text_size">25sp</dimen>
</resources>
and
mpaint.setTextSize(getResources().getDimensionPixelSize(R.dimen.custom_text_size));
Finally just as we used to create the Keyboard,
KeyboardView kv = (CustomKeyboardView) getLayoutInflater().inflate(R.layout.mainkeyboard, null); //mainkeyboard
Keyboard keyboard = new Keyboard(this, R.xml.hindi); //Your Keyboard Layout
kv.setKeyboard(keyboard); //Set the keyboard
And you are good to go.
Hope it helps :D
Related
I am writing an app that generates Maths worksheets for school students. It will, for example, generate 2 to 5 pages of simple Maths questions and 1 to 2 pages of answers. The PDF can be saved to file and loaded again later. Then it has a print function that can print all the pages. I want to make it skip printing the answer pages.
Is it possible to automatically identify which pages are the answer pages? I can only think of a workaround by making those answer pages have special height or width but not even sure if this works. Are there any better ways to do this?
Ok, I continued the project and used the following method: when constructing the PDF, I put the word "Answer on the top left corner with a gray rectangle surrounding it drawn with drawRect(). Then before the actual printing, I used the following code inside the PrintDocumentAdapter() class to check whether the color of the pixel 0,0 is gray or not.
#Override
public void onStart() {
if (parcelFileDescriptor != null) {
try {
pdfRenderer = new PdfRenderer(parcelFileDescriptor);
} catch (IOException e) {
e.printStackTrace();
}
}
int tempTotal = pdfRenderer.getPageCount();
Bitmap[] tempBitmap = new Bitmap[tempTotal];
finalTotal = tempTotal;
for (int pageNum = 0; pageNum < tempTotal; pageNum++) {
PdfRenderer.Page tempPage = pdfRenderer.openPage(pageNum);
tempBitmap[pageNum] = Bitmap.createBitmap(WS_WIDTH, WS_HEIGHT, Bitmap.Config.ARGB_8888);
tempPage.render(tempBitmap[pageNum], null, null, PdfRenderer.Page.RENDER_MODE_FOR_PRINT);
if (tempBitmap[pageNum].getPixel(0, 0) == Color.GRAY) {
finalTotal--;
}
tempPage.close();
}
}
It works fine. At least should cause no problem if the users only attempt to print PDF files constructed with my app. :P
Please tell me if you know a better way to do this. Thanks!
i am trying to learn android keyboard api.
Using the softKeyboard example, i am trying to change the key icon, i can change everything, but the icon never change.
i am doing it in the LatinKeyboardView, at the onLongPress method, using this line:
copia.icon = getResources().getDrawable(R.drawable.tecladir);
but the icon doesn't change.
Even after using
this.invalidateAllKeys();
to force redraw of the keys, the icon is still unchanged.
Complete code of onLongPress as following:
#Override
protected boolean onLongPress(Key key) {
key.icon = getResources().getDrawable(R.drawable.tecladir);
//tecladir is one image i have
key.text = "batata";
key.label = "batata";
this.invalidateAllKeys();
//default code of method
if (key.codes[0] == Keyboard.KEYCODE_CANCEL) {
getOnKeyboardActionListener().onKey(KEYCODE_OPTIONS, null);
return true;
} else {
return super.onLongPress(key);
}
}
Am i missing something?
Ok, found the solution.
before assign a new icon, the label must be null, otherwise the icon doesn't change, the correct way is:
key.label = null;
key.icon = getResources().getDrawable(R.drawable.tecladir);
I am trying to build an SWT Tree that has icons at the top level but not at the next level.
Is there any way to avoid the blank space which seems to have been left for the image which I'm not using? I tried using the following code snippets but neither did what I wanted.
SWT.MeasureItem:
tree.addListener(SWT.MeasureItem, new Listener()
{
#Override
public void handleEvent(Event event)
{
TreeItem item = (TreeItem)event.item;
Image image = item.getImage();
if (image == null)
{
event.x -= 40;
}
}
});
SWT.PaintItem:
tree.addListener(SWT.PaintItem, new Listener()
{
#Override
public void handleEvent(Event event) {
TreeItem item = (TreeItem)event.item;
Image image = item.getImage();
if (image == null)
{
event.x -= 40;
}
}
});
In both cases I was just hoping that the text could be drawn a bit further to the left.
This behavior comes from the native controls and is OS-specific (AFAIR, on Macs you won't see this problem). Alas, no easy fix but add some generic icon (or not adding icons at all).
I have done some more investigation myself. As per Eugene's answer this seems to be native behaviour. There are a couple of things worth noting.
If no items in the Tree have an icon then no space is left for icons. However, even a single item with an icon will cause all items to leave space for icons.
A hacky solution can be implemented as follows:
Use no icons so that the native control leaves no icon space
For items where you want an icon prefix some spaces to the text e.g. " " + text
Add a PaintItem listener that draws the icon you want into the space left by the text
This probably doesn't work well across platforms and across system fonts so I've just decided to live with having icons.
(source: google.com)
Recently, I realize the Chinese Character displayed are rather ugly in my application.
I thought I should make them to "anti-alias". But, how can I do that in Java?
FYI, I didn't explicitly choose the font I want to use in my GUI application. I solely let the system decide their own during startup. I however, do explicitly set the locale, before show up the GUI.
Locale.setDefault(locale);
The system will always choose
javax.swing.plaf.FontUIResource[family=Tahoma,name=Tahoma,style=plain,size=11]
no matter I am in English or Chinese locale.
Anti-aliasing considered harmful: http://www.joelonsoftware.com/articles/fog0000000041.html
The point is, that beauty of characters is not necessarily the user interface goal. It is not everything. What you should look for, is readability of text. When your Chinese characters look not smooth, it may be exactly what helps human eye's control loop to know that it is in focus and stop blaming the eye muscules for blurriness. Really, don't fall in this pitfal.
Here's a method to read a truetype font from the classpath and register it with the graphics environment:
private static Font readFont(String name) {
InputStream in = Fonts.class.getResourceAsStream(name + ".ttf");
if (in == null) {
throw new IllegalArgumentException(name);
}
try {
Font retval = Font.createFont(Font.TRUETYPE_FONT, in);
GraphicsEnvironment.getLocalGraphicsEnvironment().registerFont(retval);
return retval;
} catch (Exception e) {
throw new RuntimeException(e);
}
}
You can then use this font object to derive characters of different sizes, or you could try applying this font using Swing CSS. In this case, the value you would put in the "font-family" attribute is the value returned by Font.getName().
For example:
static {
Font font = readFont("VeraMono");
if (font != null) {
font = font.deriveFont(14f);
} else {
throw new IllegalStateException();
}
MONOSPACED_TEXT_FONT = font;
MONOSPACED_TEXT_FONT_STYLE = "font-family: " + font.getName() + "; font-size: 14pt; font-weight: normal;";
}
How do I get a JLabel displaying a HTML string to appear greyed out (which is the behaviour of JLabels that don't display HTML text)? Is there another way than actually changing the colour myself by modifying the foreground property?
JLabel label1 = new JLabel("Normal text");
JLabel label2 = new JLabel("<html>HTML <b>text</b>");
// Both labels are now black in colour
label1.setEnabled(false);
label2.setEnabled(false);
// label1 is greyed out, label2 is still black in colour
Thank you very much for all of your responses. From what I gather, it seems that Java doesn't support automatic greying out of JLabels when they use HTML text. Suraj's solution has come closest to the fix considering the limitations.
I have however, tried a different out-of-the box approach, where I have put the HTML text JLabels inside of an inner JPanel and did this:
mInnerPanel.setEnabled(shouldShow); //shouldShow is a boolean value
Which hasn't worked. Any suggestions for this way?
EDIT: Added implemented solution.
If text is HTML, the text wont be grayed out because of the following code in BasicLabelUI#paint()
View v = (View) c.getClientProperty(BasicHTML.propertyKey);
if (v != null) {
v.paint(g, paintTextR);
}
As you can see if the text is html, then the View is used to paint and it is not checked wheter the label is enabled or not.
Hence we need to do it explictly as shown below:
label2.addPropertyChangeListener(new PropertyChangeListener() {
public void propertyChange(PropertyChangeEvent evt) {
if (!evt.getPropertyName().equals("enabled"))
return;
if (evt.getNewValue().equals(Boolean.FALSE))
label2.setText("<html><font color=gray>HTML <b>text</b></html>");
else
label2.setText("<html><font color=black>HTML <b>text</b></html>");
}
});
Implemented solution:
Color foreground = (shouldShow) ? SystemColor.textText : SystemColor.textInactiveText;
for (Component comp : mInnerPanel.getComponents())
{
comp.setForeground(foreground);
}
Caved in and used setForeground in the end, as it appears that Java seems to explicitly ignore the enabled property when painting JLabels so long as it contains HTML text. See also #Suraj's answer, for "pure" solution.
I would suggest the following, which is combination of two solutions provided here:
public class HtmlLabel extends JLabel{
public void setEnabled(boolean enabled){
if(getClientProperty(BasicHTML.propertyKey) != null ){
Color foreground = (enabled) ? SystemColor.textText : SystemColor.textInactiveText;
setForeground(foreground);
}
super.setEnabled(enabled);
}
}
You can specify the font color in the HTML.
Override the paint method in the UI, set the client property BasicHTML.propertyKey to null if it is disabled and call super...