Use SFPro font in Flutter rather than default SF UI - ios

Flutter's Cupertino Text Theme uses the older versions of Apple's San Francisco Font known as .SF Pro Display and .SF Pro Text. It then adds custom tracking (letter spacing) to a few default styles.
https://github.com/flutter/flutter/blob/master/packages/flutter/lib/src/cupertino/text_theme.dart
This presumably will only approximate native iOS behaviour and requires each font size to be effectively hard coded with the correct letter spacing values.
There is no official support for the actual SF Pro font that is available from Apple for download. Apple also provides a guide on its tracking values.
https://developer.apple.com/design/human-interface-guidelines/foundations/typography/
Is there a way to use the actual SF Pro library and is there a reason why Flutter does not?
For example SF Pro could be presumably be implemented like this
pubspec.yaml
fonts:
- family: SF-Pro
fonts:
- asset: fonts/SF-Pro.ttf
Then the font values could be hard coded:
class SFTextStyles {
static const _font = 'SF-Pro';
static const TextStyle body = TextStyle(
fontFamily: _font,
fontSize: 17,
letterSpacing: -0.43,
);
static const TextStyle callout = TextStyle(
fontFamily: _font,
fontSize: 16,
letterSpacing: -0.31,
);
static const TextStyle caption = TextStyle(
fontFamily: _font,
fontSize: 12,
letterSpacing: 0,
);
}
or even calculated:
extension SFTextStylesTracking on TextStyle {
tracking(double fontSize){
return merge(
TextStyle(letterSpacing: _Tracking[fontSize]);
}
}
// source of values: https://developer.apple.com/design/human-interface-guidelines/foundations/typography/
class _Tracking {
static const Map<int, double> tracking = {
6: 0.24,
7: 0.23,
8: 0.21,
9: 0.17,
10: 0.12,
11: 0.06,
12: 0,
13: -0.08,
etc..
}
}
Is there a reason why this is not done / not a good idea?

Related

Changing the color and styling of the Button in Flutter

I have migrated to Flutter 2.0 which is just the new release now. In my project I have used Flat Buttons but it got deprecated now in Flutter 2.0 and the suggestion pop up to use Text Button instead of Flat Buttons.
Now the problem is in Flat Buttons there are option directly to set the properties of button such as color, padding etc. but when I replaced it with Text Button there is error in using this properties. I have checked the documentation and found that there is the property of style: ButtonStyle(backgroundcolor: ____________). But when I have put Colors.blue in the backgroundcolor property it gives me error.
So I want to know that how is the behaviour of Buttons in Flutter 2.0 and how we can style the Buttons?
My snippet of code is here in which I want to style the button.
Container(
width: 200.0,
child: TextButton(
style: ButtonStyle(), // I want to style this.
onPressed: () => Navigator.pushNamed(context, SignupPage.id),
/*color: Colors.blue,
padding: const EdgeInsets.all(10.0),*/ //Commented code is deprecated in Flutter 2.0
child: Text(
'Create Account',
style: TextStyle(color: Colors.white, fontSize: 16.0),
),
The style argument with a backgroundcolor is the way to do it, but does not take a Color object, its type is MaterialStateProperty<Color?>? so you should provide an object of that type.
documentation is here https://api.flutter.dev/flutter/material/TextButton-class.html
and here https://api.flutter.dev/flutter/material/ButtonStyle-class.html
Buttons now have a state, so you have to define the colors for each state:
you can define one color for all the states.
ButtonStyle(
backgroundColor: MaterialStateProperty.all(Colors.green),
you can define a different color for each state.
ButtonStyle(
backgroundColor: MaterialStateProperty.resolveWith(
(Set states) {
if (states.contains(MaterialState.pressed))
return Theme.of(context).colorScheme.primary.withOpacity(0.5);
return null; // Use the component's default.
},
),
),

How to customize numberpicker in Flutter?

I implemented numberpicker in my app.
I would like to modify the size of the numbers and the color of both highlighted value and those who are not. I managed to modify the highlighted ones wrapping it in the Theme widget and modifing the accentcolor, but don't know how I can do the other customizations?
Theme(
data: Theme.of(context).copyWith(
accentColor: Colors.red,
),
child: NumberPicker.integer(
initialValue: _currentPickerValue,
minValue: 0,
maxValue: 100,
onChanged: (newValue) =>
setState(() => _currentPickerValue = newValue)))
I digged into the code and here is something that I found
selectedStyle = themeData.textTheme.headline.copyWith(color: themeData.accentColor);
defaultStyle = themeData.textTheme.body1; This is ones which are not highlighted
to change the size or color or any other style attribute modifiy those style.
here is an example code:
final theme = Theme.of(context);
Theme(
data: theme.copyWith(
accentColor: Colors.black,// highlted color
textTheme: theme.textTheme.copyWith(
headline5: theme.textTheme.headline5.copyWith(..), //other highlighted style
bodyText2: theme.textTheme.headline5.copyWith(...), //not highlighted styles
)),
child: NumberPicker.integer(...),
);
Update your number picker package to the latest version.
new NumberPicker.integer(
...,
selectedTextStyle: TextStyle(...),
textStyle: TextStyle(...), //styles of the default text
)
Visit NumberPickec class for study properties.

React Native Responsive Font Size

I would like to ask how react native handle or do the responsive font. For example in iphone 4s i Have fontSize: 14, while in iphone 6 I have fontSize: 18.
You can use PixelRatio
For example:
var React = require('react-native');
var {StyleSheet, PixelRatio} = React;
var FONT_BACK_LABEL = 18;
if (PixelRatio.get() <= 2) {
FONT_BACK_LABEL = 14;
}
var styles = StyleSheet.create({
label: {
fontSize: FONT_BACK_LABEL
}
});
Edit:
Another example:
import { Dimensions, Platform, PixelRatio } from 'react-native';
const {
width: SCREEN_WIDTH,
height: SCREEN_HEIGHT,
} = Dimensions.get('window');
// based on iphone 5s's scale
const scale = SCREEN_WIDTH / 320;
export function normalize(size) {
const newSize = size * scale
if (Platform.OS === 'ios') {
return Math.round(PixelRatio.roundToNearestPixel(newSize))
} else {
return Math.round(PixelRatio.roundToNearestPixel(newSize)) - 2
}
}
Usage:
fontSize: normalize(24)
You can go one step further by allowing sizes to be used on every <Text /> components by pre-defined sized.
Example:
const styles = {
mini: {
fontSize: normalize(12),
},
small: {
fontSize: normalize(15),
},
medium: {
fontSize: normalize(17),
},
large: {
fontSize: normalize(20),
},
xlarge: {
fontSize: normalize(24),
},
};
We use a simple, straight-forward, scaling utils functions we wrote:
import { Dimensions } from 'react-native';
const { width, height } = Dimensions.get('window');
//Guideline sizes are based on standard ~5" screen mobile device
const guidelineBaseWidth = 350;
const guidelineBaseHeight = 680;
const scale = size => width / guidelineBaseWidth * size;
const verticalScale = size => height / guidelineBaseHeight * size;
const moderateScale = (size, factor = 0.5) => size + ( scale(size) - size ) * factor;
export {scale, verticalScale, moderateScale};
Saves you some time doing many ifs. You can read more about it on my blog post.
Edit: I thought it might be helpful to extract these functions to their own npm package, I also included ScaledSheet in the package, which is an automatically scaled version of StyleSheet.
You can find it here: react-native-size-matters.
adjustsFontSizeToFit and numberOfLines works for me. They adjust long email into 1 line.
<View>
<Text
numberOfLines={1}
adjustsFontSizeToFit
style={{textAlign:'center',fontSize:30}}
>
{this.props.email}
</Text>
</View>
Because responsive units aren't available in react-native at the moment, I would say your best bet would be to detect the screen size and then use that to infer the device type and set the fontSize conditionally.
You could write a module like:
function fontSizer (screenWidth) {
if(screenWidth > 400){
return 18;
}else if(screenWidth > 250){
return 14;
}else {
return 12;
}
}
You'll just need to look up what the default width and height are for each device. If width and height are flipped when the device changes orientation you might be able to use aspect ratio instead or just figure out the lesser of the two dimensions to figure out width.
This module or this one can help you find device dimensions or device type.
I managed to overcome this by doing the following.
Pick the font size you like for the current view you have (Make sure
it looks good for the current device you are using in the
simulator).
import { Dimensions } from 'react-native' and define the width
outside of the component like so: let width = Dimensions.get('window').width;
Now console.log(width) and write it down. If your good looking font
size is 15 and your width is 360 for example, then take 360 and
divide by 15 ( = 24). This is going to be the important value that
is going to adjust to different sizes.
Use this number in your styles object like so: textFontSize: { fontSize = width / 24 },...
Now you have a responsive fontSize.
import { Dimensions } from 'react-native';
const { width, fontScale } = Dimensions.get("window");
const styles = StyleSheet.create({
fontSize: idleFontSize / fontScale,
});
fontScale get scale as per your device.
Take a look at the library I wrote: https://github.com/tachyons-css/react-native-style-tachyons
It allows you to specify a root-fontSize (rem) upon start, which you can make dependent of your PixelRatio or other device-characteristics.
Then you get styles relative to your rem, not only fontSize, but paddings etc. as well:
<Text style={[s.f5, s.pa2, s.tc]}>
Something
</Text>
Expanation:
f5is always your base-fontsize
pa2 gives you padding relative to your base-fontsize.
I simply use the ratio of the screen size, which works fine for me.
const { width, height } = Dimensions.get('window');
// Use iPhone6 as base size which is 375 x 667
const baseWidth = 375;
const baseHeight = 667;
const scaleWidth = width / baseWidth;
const scaleHeight = height / baseHeight;
const scale = Math.min(scaleWidth, scaleHeight);
export const scaledSize =
(size) => Math.ceil((size * scale));
Test
const size = {
small: scaledSize(25),
oneThird: scaledSize(125),
fullScreen: scaledSize(375),
};
console.log(size);
// iPhone 5s
{small: 22, oneThird: 107, fullScreen: 320}
// iPhone 6s
{small: 25, oneThird: 125, fullScreen: 375}
// iPhone 6s Plus
{small: 28, oneThird: 138, fullScreen: 414}
We can use flex layout and use adjustsFontSizeToFit={true} for responsive font sizes.And the text would adjust according to the size of the container.
<Text
adjustsFontSizeToFit
style={styles.valueField}>{value}
</Text>
But in styles you need to put a fontsize as well only then will adjustsFontSizeToFit work.
valueField: {
flex: 3,
fontSize: 48,
marginBottom: 5,
color: '#00A398',
},
Why not using PixelRatio.getPixelSizeForLayoutSize(/* size in dp */);, it's just the same as pd units in Android.
I'm usually using this :
import React from 'react';
import { View, Text, StyleSheet, Dimensions } from 'react-native';
var heightY = Dimensions.get("window").height;
export default function App() {
return (
<View style={styles.container}>
<Text style={styles.textStyle}>fontSize {heightY * 0.014}</Text>
</View>
)
}
const styles = StyleSheet.create({
container: {
flex: 1,
backgroundColor: '#fff',
alignItems: 'center',
justifyContent: 'center',
},
textStyle: {
fontSize: heightY * 0.014,
}
})
The idea is to get the fontSize depending on height of your screen. Example calculation:
// Height 785,.. -> fontSize = 11
// Height 1000 -> fontSize = 14
// Height 1285,.. -> fontSize = 18
You can also try using this if you want it to depend on your screen width:
var widthX = Dimensions.get("window").width;
I recently ran into this problem and ended up using react-native-extended-stylesheet
You can set you rem value and additional size conditions based on screen size. As per the docs:
// component
const styles = EStyleSheet.create({
text: {
fontSize: '1.5rem',
marginHorizontal: '2rem'
}
});
// app entry
let {height, width} = Dimensions.get('window');
EStyleSheet.build({
$rem: width > 340 ? 18 : 16
});
Need to use this way I have used this one and it's working fine.
react-native-responsive-screen
npm install react-native-responsive-screen --save
Just like I have a device 1080x1920
The vertical number we calculate from height **hp**
height:200
200/1920*100 = 10.41% - height:hp("10.41%")
The Horizontal number we calculate from width **wp**
width:200
200/1080*100 = 18.51% - Width:wp("18.51%")
It's working for all device
A slightly different approach worked for me :-
const normalize = (size: number): number => {
const scale = screenWidth / 320;
const newSize = size * scale;
let calculatedSize = Math.round(PixelRatio.roundToNearestPixel(newSize))
if (PixelRatio.get() < 3)
return calculatedSize - 0.5
return calculatedSize
};
Do refer Pixel Ratio as this allows you to better set up the function based on the device density.
You can use something like this.
var {height, width} = Dimensions.get('window');
var textFontSize = width * 0.03;
inputText: {
color : TEXT_COLOR_PRIMARY,
width: '80%',
fontSize: textFontSize
}
Hope this helps without installing any third party libraries.

Adding text to uiwebview using javascript function at specific location in ios

Blockquote
in my app I want to add text in specific location I tried to change the top and left property of text in js code but still it injecting text at 0,0.
Thanks in advance
objective-c code
NSString *stringToAddToCanvas=[NSString stringWithFormat:#"addText('%#')",m_textToAdd];
[canvas stringByEvaluatingJavaScriptFromString:stringToAddToCanvas];
js code
function addText(text)
{ canvas.isDrawingMode = false;
var objectVar = new fabric.Text(text, {
fontFamily: 'Arial',
fontSize: 90,
left: 0,
top: 0,
textAlign: "center",
fontWeight: 'bold',
borderColor :drawingColor,
fill:fillColor
});
canvas.add(objectVar);
objectsArray.push(objectVar);
objectsTimeDurationArray.push(0);
}
Got the solution it is very strange but to reflect changes in my .js file I need to delete my app from device then install it, all the changes made in .js file working perfectly

Autofit labels in blackberry cascades using qml

I have a list view that stretch to device width that shows a list of names, I need to make the label fit the total width, just like autofit. So if its a short name it should have max font to fit to view width or if its a long name the font size should decrease to fit the view width. Blackberry 10.2 has a autofit property on label that does this but I need it to support from 10.0. So is there any other alternative to do this?
This is my current definition of the label
Label {
id: myLabel
horizontalAlignment: HorizontalAlignment.Fill
verticalAlignment: VerticalAlignment.Center
textStyle {
base: tsLabel.style
}
TextStyleDefinition {
id: tsLabel
base: SystemDefaults.TextStyles.BodyText
fontSize: FontSize.PointValue
fontSizeValue:14
color: Color.White
fontWeight: FontWeight.Bold
}

Resources