FontAwesome in Xamarin forms UWP - xamarin.forms

I have a Custom renderer working in Android with Fontawesome.
I was following this guide using font awesome in UWP
With a custom Label type to try to get Fontawesome working in UWP.
public class FontAwesomeLabel: Xamarin.Forms.Label {
public FontAwesomeLabel() {
switch (Device.RuntimePlatform)
{
case Device.UWP:
FontFamily = #"/Assets/FontAwesome.otf#FontAwesome";
break;
}
}
}
The fonts
were loaded as both ttf and otf. I have tried both types.
They Assest fonts have build action "Content"
mainView.Children.Add( new FontAwesomeLabel()
{Text = FaConstPool.FASearch ,FontSize = 40});
public static string FASearch = "\uf002";
Only works on Android and not in UWP
I see a strange box and not the expected Fontawesome icon as for Android.
Any ideas what i have done wrong ?

The solution to the problem turned out to be in UWP, use the correct font family name.
Font Awesome 5 Free Solid
and not just "FontAwesome"
// FontFamily = #"/Assets/FontAwesome.otf#FontAwesome"; // incorrect font family name
FontFamily = #"/Assets/Fonts/FontAwesome.otf#Font Awesome 5 Free Solid";
For anyone interested in details:
I downloaded a font editor to check the internal font name and font family name. I made the mistake of code copying blog posts that used values from similar/older fonts. See image for actual content.
There are 2 types of solution I got to work:
1) A custom control in shared code /.netStandard Common project.
2) a custom renderer
Solution 1: Custom Label
public class FontAwesomeLabel: Xamarin.Forms.Label
{
public FontAwesomeLabel()
{
switch (Device.RuntimePlatform)
{
case Device.UWP:
// make sure the correct font family name is used. Check in a font editor
this.FontFamily = #"/Assets/Fonts/FontAwesome.otf#Font Awesome 5 Free Solid";
break;
}
}
}
Solution 2: Customer renderer on Standard Control
[assembly: ExportRenderer(typeof(Label), typeof(FontAwesomeLabelRenderer))]
namespace Oxando.UWP.CustomRenderers
{
public class FontAwesomeLabelRenderer : LabelRenderer
{
protected override void OnElementChanged(ElementChangedEventArgs<Label> e)
{
base.OnElementChanged(e);
if (Control != null)
{
// on UWP be sure use the Font Family name.
// get a font editor and check the name, if it doesnt match UWP wont load it
if (FontAwesomeUtil.CheckIsFA(e.NewElement.Text))
{
Control.FontFamily = new FontFamily("/Assets/Fonts/FontAwesome.otf#Font Awesome 5 Free Solid");
}
}
}
}
internal static class FontAwesomeUtil
{
public static bool CheckIsFA(string text)
{
if (text.Length == 0) return false;
if (text.Length > 1 || text[0] < 0xf000) return false;
return true;
}
}
}
Actual internal names as shown in Font editor

The correct path to add a font on UWP is /Assets/Fonts/FontAwesome.ttf#FontAwesome it seems you have to add the Fonts folder.
Like this:
Additionally you can use Iconize plugin and check this answer:
How can I display a font awesome glyph in XAML/C#

Related

Matching a font style exactly with QML

I have a QML app that's using a font family that has 5 weights—Light/Regular/Medium/Bold/Black—and 3 styles: Normal, Italic, and Condensed.
When I load both a 'normal' and 'condensed' style of the same weight they share the same family name; whichever style was loaded first is what is used:
FontLoader { source:"qrc:/fonts/DINPro-CondRegular.otf"; id:cond }
FontLoader { source:"qrc:/fonts/DINPro-Regular.otf"; id:norm }
Timer { running:true; onTriggered:console.log(id:norm.name==cond.name) } // outputs `true`
// This ends up using the condensed flavor
Text { text:'hi mom'; font { family:'DINPro' } }
Is there some way to tell a Text object to use a specific font file or FontLoader instance? There's an italic property for italic style, but no property for the 'condensed' flavor.
How can I use both normal and condensed styles of the font in the same document, and specify which to use for different Text?
I've found that for this particular font I can use the styleName property to control the various flavors. I just kept trying various style strings until I found ones that worked.
FontLoader { source:"qrc:/fonts/DINPro-Regular.otf" }
FontLoader { source:"qrc:/fonts/DINPro-CondRegular.otf" }
FontLoader { source:"qrc:/fonts/DINPro-CondMedium.otf" }
Text { text:'norm'; font { family:'DINPro'; styleName:'Regular' } }
Text { text:'bold'; font { family:'DINPro'; weight:Font.Bold; styleName:'Regular' } }
Text { text:'blak'; font { family:'DINPro'; weight:Font.Black; styleName:'Regular' } }
Text { text:'cond norm'; font { family:'DINPro'; styleName:'CondRegular' } }
Text { text:'cond bold'; font { family:'DINPro'; styleName:'CondBold' } }
Text { text:'cond blak'; font { family:'DINPro'; styleName:'CondBlack' } }
It feels like it's held together with tape and string, but it's working. If someone has a more robust way to handle this—especially to know exactly what strings will work for the styleName—I'll happily accept that answer instead of this one.

GWT ListBox rendering different across browsers

So, I have a custom implementation of ListBox for a GWT application
Its xml code looks like this:
<g:FlowPanel addStyleNames="{style.yearRangePanel}">
<g:FlowPanel addStyleNames="{style.rangeSeparator} {style.paddingTop}">
<g:Label addStyleNames="{style.horizontalAlign}" ui:field="integerRangeDropdownLabel">Filter studies by range of enroled patients: </g:Label>
<g:Label addStyleNames="{style.prefixSpace} {style.horizontalAlign}" ui:field="startSampleSizeLabel"/>
</g:FlowPanel>
<g:FlowPanel ui:field="integerRangeDropdownFilterPanel" addStyleNames="{style.yearRangeSliderPanel} {style.paddingTop}">
<g:ListBox ui:field ="integerRangeDropdownListBox" styleName="{style.customListBox}"/>
</g:FlowPanel>
</g:FlowPanel>
And its main java code looks like:
#UiConstructor
public IntegerRangeDropdownFilterComposite (String fieldName, String labelText){
this.initWidget(uiBinder.createAndBindUi(this));
filterChangedEvent = new FilterChangedEvent(fieldName);
FilterConfig filterConfig = clientFactory.getApplicationContext().getConfig(FilterConfig.class);
List<FilterSetting> filterSettings = filterConfig.getFilterConfigBy(fieldName);
FilterSetting filterSetting = filterSettings.get(0);
filterByIntegerRangeSettings = (FilterConfig.FilterByIntegerRangeSettings) filterSetting;
this.increment = Integer.toString(filterByIntegerRangeSettings.getIncrement());
this.minSampleSize = Integer.toString(filterByIntegerRangeSettings.getInitialValue());
this.maxSampleSize = Integer.toString(filterByIntegerRangeSettings.getEnd());
this.setupConfig(fieldName);
}
private void setupConfig(String fieldName){
setupRange(fieldName);
}
#Override
protected void onLoad() {
super.onLoad();
integerRangeDropdownFilterPanel.add((Widget) integerRangeDropdownListBox);
}
public void resetIntegerRangeDropdownFilter() {
filterChangedEvent.resetField();
}
#UiHandler("integerRangeDropdownListBox")
public void clickEnroled(ChangeEvent changeEvent){
if(integerRangeDropdownListBox.getSelectedIndex()!=0) {
String selectedItem = integerRangeDropdownListBox.getSelectedItemText();
minSampleSize = selectedItem.substring(0, (selectedItem.indexOf('-'))).trim();
maxSampleSize = selectedItem.substring((selectedItem.indexOf('-') + 1)).trim();
}
else{
minSampleSize="0";
maxSampleSize="100000";
}
resetIntegerRangeDropdownFilter();
filterChangedEvent.addFilter(Integer.parseInt(minSampleSize), Integer.parseInt(maxSampleSize));
clientFactory.getEventBus().fireEvent(filterChangedEvent);
}
Now, as for the style, I've tried "bootstrapping" it with this line:
<g:ListBox ui:field ="integerRangeDropdownListBox" styleName="btn btn-primary dropdown-toggle"/>
And I've tried customizing it with CSS like this:
.customListBox{
background-color: dodgerblue !important;
color: white;
padding: 5px;
}
<g:ListBox ui:field ="integerRangeDropdownListBox" styleName="{style.customListBox}"/>
Whichever way I do it, it will not render equally across browsers, it only looks "nice" on Google Chrome, while in Safari and Firefox it will have an "uglee" arrow for the dropdown and different scroll bar.
Any ideas as for why this may be happening? Needless to say I've tried google and the forum, but searching for GWT related topics is pretty much useless
First, you should use addStyleNames instead of styleName, because styleName removes all existing style names and replaces them with the style name you provided.
Second, this is not a GWT problem. Browsers render various elements differently. If you want a more uniform look, you need to search for CSS suggestions.
It is exactly as you described your question: The standard GWT ListBox is rendering different across browsers.
The main reason is that it is using a native browser control under the hood.
It creates a HTML select control element here.
You can try that basic HTML control yourself in different browsers here.
So there is not much you can do about that.
On some browser you might be able to style it, but not consistently.

IE9 ignores font sometimes

My web application uses Arial as default font. But in a single place, the font family is ignored:
As you can see the labels on the left use Arial but in the popup DIV, it uses a serif font (probably New Roman Times, I'm not sure.)
I've styled the td directly and the content of the td is just an empty span plus the text.
When I toggle the checkboxes on the right, eventually IE9 will recalculate the styles and apply them properly.
Does anyone have any idea why IE ignores the CSS here?
Details: IE 9.0.29, Windows 7, ZK 6.5 as UI framework.
I've found these solutions but I don't know why they work when inheritance didn't:
.z-comboitem-text {
font-family: Arial !important;
}
or
tr td.z-comboitem-text {
font-family: Arial;
}
or using an inline style. If you use ZK 6, then use this code:
if( ZKUtils.isIE( 9 ) ) {
item.setWidgetListener( "onBind", "jq(this).find('.z-comboitem-text').css('font-family', 'Arial')" );
}
public static boolean isIE( int version ) {
Execution zkEnv = Executions.getCurrent();
if( ! "ie".equals( zkEnv.getBrowser() ) ) {
return false;
}
int actualVersion = zkEnv.getBrowser( "ie" ).intValue();
return version == actualVersion;
}

For PlayN, can someone provide a simple code example showing how to load a font file?

I'm looking for a simple example that loads a ttf file (in my case, Inconsolata.ttf) and creates a text layer.
Is it possible to do this in a platform-agnostic way? From this response here, I get the impression it is not.
I am working on a simple proof-of-concept using the TextDemo sample from the playn-samples showcase as a reference.
I'm presently a little confused on how to register the ttf file. Here's my code:
private void testCustomFont() {
// text
String text = "Hello, Cleveland!";
// load font
String fontName = "Inconsolata";
Font.Style fontStyle = Font.Style.BOLD;
Float fontSize = 24f;
Font myFont = graphics().createFont(fontName, fontStyle, fontSize);
// format text
Integer fontColor = Color.rgb(0, 0, 255);
TextFormat textFormat = new TextFormat().withFont(myFont).withTextColor(fontColor);
// create font image layer
ImageLayer textLayer = graphics().createImageLayer();
TextLayout textLayout = graphics().layoutText(text, textFormat);
CanvasImage textImage = graphics().createImage((int)Math.ceil(textLayout.width()),
(int)Math.ceil(textLayout.height()));
textImage.canvas().drawText(textLayout, 0, 0);
textLayer.setImage(textImage);
// position text layer and add to root layer
textLayer.setTranslation(20, 20);
graphics().rootLayer().add(textLayer);
}
The projects is laid out like so:
/project
├── core
│   └── MyProject.java
└── resources
   └── fonts
└── Inconsolata.ttf
This displays the text but, as expected, not in the desired typeface.
Ideally, I would have like font-loading to have worked like image-loading with the asset manager:
String fontPath = "fonts/Inconsolata.ttf";
Font.Style fontStyle = Font.Style.BOLD;
Float fontSize = 24f;
Font myFont = assetManager().getFont(fontPath, fontStyle, fontSize);
That wasn't possible, so I looked into doing something like this:
private void registerFont() {
if (platformType().equals(Platform.Type.JAVA)) {
Platform platform = Platform.getJavaPlatformApi();
platform.assets().setPathPrefix("com/klenwell/myproject/resources");
platform.graphics().registerFont("Inconsolata", "fonts/Inconsolata.ttf");
}
else if (platformType().equals(Platform.Type.ANDROID)) {
Platform platform = Platform.getAndroidPlatformApi();
platform.assets().setPathPrefix("com/klenwell/myproject/resources");
platform.graphics().registerFont("Inconsolata", "fonts/Inconsolata.ttf");
}
else if (platformType().equals(Platform.Type.HTML)) {
// rely on CSS setting in HTML host file
}
}
But there is no method like getJavaPlatformApi in the core Platform class. So as noted here, "you have to register the font manually on each backend that you intend to use."
Following the example of the TextDemo sample, this is how I would load the font in my example above for the Java and HTML platforms:
Java Platform
Update game class in Java dir:
public class MyProjectJava {
public static void main(String[] args) {
JavaPlatform platform = JavaPlatform.register();
platform.assets().setPathPrefix("com/klenwell/myproject/resources");
platform.graphics().registerFont("Inconsolata", "fonts/Inconsolata.ttf");
PlayN.run(new MyProject());
}
}
HTML Platform
Edit the HTML host file under HTML snapshot directory:
<!DOCTYPE html>
<html>
<head>
<title>MyProject Font Loading Example</title>
<style>
#font-face {
font-family: "Inconsolata";
src: url(myproject/resources/fonts/Inconsolata.ttf);
}
</style>
</head>
<body bgcolor="black">
<script src="myproject/myproject.nocache.js"></script>
</body>
</html>
Android Platform
To Be Announced
iOS Platform
To Be Announced
I haven't yet ventured into Android or iOS compilation yet, so I can't offer an example of those at present.
It seems like your question is covered on the PlayN wiki's custom fonts page.
PlayN supports the use of custom fonts, but such fonts need to be integrated specially for each of the different backends that you wish to use in your game. TrueType (.ttf) fonts are supported by all backends. OpenType (.otf) fonts are supported by some backends (iOS, HTML5, Android).
The main steps seem to be:
Add the font file as an asset.
Register the font separately for each back end using platform.graphics().registerFont().
Create a font object using PlayN.graphics().createFont(), and then use it as normal.

CSS selector for custom Qt class

I created a "Slider" subclass of QWidget and would like to be able to style it with Qt's stylesheets. Is there a way to declare the widget to Qt application so that this setting in the application stylesheet is applied to all sliders ?
Slider { background-color:blue; }
Or if this is not possible, can I use a class like this ?
QWidget.slider { background-color:blue; }
The widgets have a "className()" method that is accessible via the meta object. In my case this is:
slider.metaObject()->className();
// ==> mimas::Slider
Since the "Slider" class is in a namespace, you have to use the fully qualified name for styling (replacing '::' with '--'):
mimas--Slider { background-color:blue; }
Another solution is to define a class property and use it with a leading dot:
.slider { background-color:blue; }
C++ Slider class:
Q_PROPERTY(QString class READ cssClass)
...
QString cssClass() { return QString("slider"); }
While on the subject, to draw the slider with colors and styles defined in CSS, this is how you get them (link text):
// background-color:
palette.color(QPalette::Window)
// color:
palette.color(QPalette::WindowText)
// border-width:
// not possible (too bad...). To make it work, you would need to copy paste
// some headers defined in qstylesheetstyle.cpp for QRenderRule class inside,
// get the private headers for QStyleSheetStyle and change them so you can call
// renderRule and then you could use the rule to get the width borders. But your
// code won't link because the symbol for QStyleSheetStyle are local in QtGui.
// The official and supported solution is to use property:
// qproperty-border:
border_width_ // or whatever stores the Q_PROPERTY border
And finally, a note on QPalette values from CSS:
color = QPalette::WindowText
background = QPalette::Window
alternate-background-color = QPalette::AlternateBase
selection-background-color = QPalette::Highlighted
selection-color = QPalette::HighlightedText

Resources