How to disable font scaling in React Native for IOS app? - ios

Enlargement of size of the device font will sometimes break (Styling wise).

Disabling font scaling can hurt the accessibility of your app, ideally if you want to limit scaling for Apps using React native 0.58.0 and above; use the maxFontSizeMultiplier prop on specific Text components.
However if you absolutely want to disable font scaling across your entire Application, you can do so by globally setting the allowFontScaling prop in the defaultProps of Text.
You should place these lines in your root entrypoint (normally index.js) before AppRegistry.registerComponent.
For React Native 0.56.0+
Text.defaultProps = Text.defaultProps || {};
Text.defaultProps.allowFontScaling = false;
For earlier versions of React Native you should only need the second line, but having both won't hurt. The first line just protects against the Text component not having defaultProps which is the case for React Native 0.56.0 and above.
Add the above lines in the entry point file of your React Native application (usually index.js, app.js or main.js) to apply this prop to all Text components in your application.
This prop will only affect Text components and you may want to apply the same changes to TextInput which can be done with a similar snippet:
TextInput.defaultProps = TextInput.defaultProps || {};
TextInput.defaultProps.allowFontScaling = false;
Also note that some components wont obey font scaling settings, for example: Alert, PickerIOS, DatePickerIOS, TabBarIOS, SegmentedControlIOS as these are all natively drawn and don't rely on the Text component.

For React native 0.58+
Preferable to keep font scaling but you can limit it by using Text new prop maxFontSizeMultiplier
For React native 0.56+ use Levi's answer
Text.defaultProps = Text.defaultProps || {};
Text.defaultProps.allowFontScaling = false;
For React native 0.55 and lower
Add Text.defaultProps.allowFontScaling=false at the beginning of the app (e.g. main.js or app.js etc ...) to apply this prop on all Text components through out the whole app.

When user increase full font size from setting
Enlargement of size of the device font will not break (Styling wise).
index.js file
import {AppRegistry} from 'react-native';
import App from './src/App';
import {name as appName} from './app.json';
import {Text, TextInput} from 'react-native';
AppRegistry.registerComponent(appName, () => App);
//ADD this
if (Text.defaultProps == null) {
Text.defaultProps = {};
Text.defaultProps.allowFontScaling = false;
}
if (TextInput.defaultProps == null) {
TextInput.defaultProps = {};
TextInput.defaultProps.allowFontScaling = false;
}
<CalendarStrip
shouldAllowFontScaling={false}
/>
Also note that some components wont obey font scaling settings, for example: Alert, PickerIOS, DatePickerIOS, TabBarIOS, SegmentedControlIOS as these are all natively drawn and don't rely on the Text component.

if (Text.defaultProps == null) {
Text.defaultProps = {};
Text.defaultProps.allowFontScaling = false;
}
I kept this piece of code inside the constructor of index.js.It really worked well. By the I am using react native version 0.59.9 FYI.

Create an <AppText> component and use it with your presets instead of the original one, with your own default, including font scaling false. This is better because you can enrich it with your own API.
For example, my AppText permit to do things like:
<AppText id="some.translation.key" color="primary" size="l" underline italic bold/>

In another file, import the actual Text component as ScaledText so as a backup, and then redefine Text, overriding the allowFontScaling prop.
export function Text(props) {
return <ScaledText {...props} allowFontScaling={false} />;
}
Then, import your locally defined Text component, instead of the built-in React Native Text. This is also useful if you want to elegantly disable font scaling on only certain parts of your app.

For webview we can use textZoom={100} props to handle font-size change if font size is changed from mobile setting.
if imported from react-native-webview
<WebView
textZoom={100}
source={}/>

I'm kinda late, but if anyone wants a answer with Typescript, here it is
interface TextWithDefaultProps extends Text {
defaultProps?: { allowFontScaling?: boolean };
}
(Text as unknown as TextWithDefaultProps).defaultProps = {
...((Text as unknown as TextWithDefaultProps).defaultProps || {}),
allowFontScaling: false,
};

Related

How to get the computed value of a CSS variable in Playwright?

I'm trying to use Playwright to test an Ionic React app.
Ionic makes extensive use of CSS variables.
My app allows users to change some of these colors, so I want to verify the color changes work properly.
I am trying to find a way to test the value of the CSS variable.
The Ionic CSS looks like this:
ion-header ion-toolbar {
--background: var(--ion-color-secondary);
}
How can I get the value of --background with Playwright?
This GitHub comment describes how to use getPropertyValue() to get the value of a CSS property. This will also return the computed result for CSS variables:
const navBar = await page.locator('ion-header ion-toolbar >> visible=true');
const color = await navBar.evaluate((element) =>
window.getComputedStyle(element).getPropertyValue('--background'),
);

How to use a native SwiftUI View in NativeScript 7

In my NativeScript (Angular) App i use a RadListView to create a list and each element has many different informations to display. It looks like that
Because of many hints at Stackoverflow and other sources i reduced the amount of nested layouts (StackLayout, GridLayout, ...) as much as possible to make the RadListView faster. On Android is the performance by using the list much better as on iOS. With an iPad Pro (2020) the rendering of the list at scrolling is not smooth. If the user change the orientation of the device the screen is freezing and have black bars at the side or bottom for a moment. The time of the freezing depends on the amount of elements to display in each row. The same row layout in a ListView is much faster but not the same as native (SwiftUI) and with missing features like swipe and pull to refresh.
Sorry for the lyric but i think a little background explains why i try the next step.
To improve the user experience i make a tiny native test app with SwiftUI and nearly the same row layout. The feeling is much better, fast first loading, smooth scrolling and no delay by orientation changes. My next idea is to create a native component in SwiftUI to show/render each row of the RadListView if possible
<RadListView [items]="items">
<ListViewLinearLayout tkListViewLayout></ListViewLinearLayout>
<ng-template tkListItemTemplate let-item="item" let-i="index" let-odd="odd">
<MyNativeSwiftUIComponentElement data="item.rowData"></MyNativeSwiftUIComponentElement>
</ng-template>
</RadListView>
or use the List from SwiftUI to show/render the whole list
<ActionBar title="Objects"></ActionBar>
<MyNativeSwiftUIListComponent data="items"></MyNativeSwiftUIListComponent>
Looking for docs and examples was difficult. I found this very short advise Adding Objective-C/Swift code and the linked tutorial there for Objective-C (Adding Objective-C Code to a NativeScript App) and some questions on Stackoverflow but there all about classes and not SwiftUI (with struct and views). One question was about SwiftUI: Is it possible to display a View written with SwiftUI with NativeScript the answer was unfortunately not helpful for me (btw. thank you #Manoj for your great support for NativeScript at Stackoverflow!).
How can i use a SwiftUI View as native component in my {N}app?
Have anyone a hint, a link to a tutorial or a link to a public repository for a app/plugin? Every tiny tip is welcome.
You might be able to use Nativescript's placeholder component (more info on that here
So you would have the Placeholder tag on your template, and use the creatingView event to add the native UIs
<Placeholder creatingView="creatingView"/>
import { CreateViewEventData } from "#nativescript/core";
export function creatingView(args: CreateViewEventData) {
let nativeView = new UILabel(); // where this would be your native UI
nativeView.text = "Native";
args.view = nativeView;
}
After a while i give up with my attempts to use directly SwiftUI in the project ({N}+Angular) and instead i try the <Placeholder> component which #William-Juan suggested. But it looks like, that the <Placeholder> not official supported in the Angular flavor - see github issue #283
To move on, i looked at the samples for NativeScript plugins and build a working solution. If anybody interested the full sample source code are in this repository: https://github.com/teha-at/sample-nativescript-native-ui-component
First, create a class which extends the #nativescript/core/View class and has an item to get the data which will be to display.
// object-list-item.d.ts
// [...]
export class ObjectListItem extends View {
item: ObjectModel;
}
export const itemProperty: Property<ObjectListItem, string>;
Than create a abstract base class which also extends the #nativescript/core/View class and this creates the base for Android and iOS
// object-list-item.common.ts
// [...]
export const itemProperty = new Property<ObjectListItemBase, string>({
name: 'item',
defaultValue: null,
affectsLayout: isIOS,
});
export abstract class ObjectListItemBase extends View {
item: PortalObjectModel;
}
// defines 'item' property on the ObjectListItemBase class
itemProperty.register(ObjectListItemBase);
ObjectListItemBase.prototype.recycleNativeView = 'auto';
Because i was only looking for a component for iOS the object-list-item.android.ts are very simple:
// object-list-item.android.ts
import { ObjectListItemBase } from './object-list-item.common';
export class ObjectListItem extends ObjectListItemBase {}
For iOS there are much more lines, for the complete file content look at the github repo please.
/// object-list-item.ios.ts
// [...]
export class ObjectListItem extends ObjectListItemBase {
// added for TypeScript intellisense.
nativeView: UIView;
// [...]
/**
* Creates new native button.
*/
public createNativeView(): Object {
const mainUiStackView = UIStackView.new();
// [...]
}
/**
* Initializes properties/listeners of the native view.
*/
initNativeView(): void {
// Attach the owner to nativeView.
// When nativeView is tapped we get the owning JS object through this field.
(<any>this.nativeView).owner = this;
super.initNativeView();
}
/**
* Clean up references to the native view and resets nativeView to its original state.
* If you have changed nativeView in some other way except through setNative callbacks
* you have a chance here to revert it back to its original state
* so that it could be reused later.
*/
disposeNativeView(): void {
// Remove reference from native listener to this instance.
(<any>this.nativeView).owner = null;
// If you want to recycle nativeView and have modified the nativeView
// without using Property or CssProperty (e.g. outside our property system - 'setNative' callbacks)
// you have to reset it to its initial state here.
super.disposeNativeView();
}
[itemProperty.setNative](item: ObjectModel) {
this.item = item;
// [...]
}
}
Add an Angular directive
// object-list-item.directives.ts
#Directive({
selector: 'ObjectListItem',
})
export class ObjectListItemDirective {
}
export const ObjectListItemDirectives = [ObjectListItemDirective];
At least register the component in an Angular module.
// object-list-item.module.ts
// [...]
#NgModule({
imports: [],
declarations: [
ObjectListItemDirectives,
],
schemas: [NO_ERRORS_SCHEMA],
exports: [
ObjectListItemDirectives,
],
entryComponents: [],
})
export class ObjectListItemModule {
}
registerElement('ObjectListItem', () => ObjectListItem);
After all this steps call the new component in the template
<!-- [...] -->
<RadListView #myListView [items]="items$ | async">
<ng-template tkListItemTemplate let-item="item">
<StackLayout margin="0" padding="0" class="-separator m-y-5" height="90">
<android>
<!-- [...] -->
</android>
<ios>
<ObjectListItem [item]="item"></ObjectListItem>
</ios>
</StackLayout>
</ng-template>
</RadListView>
<!-- [...] -->
All this work is well spent. The UI is much faster and it feels more like a native app. At the mean time i build a prototype as a native iOS App in Swift and SwiftUI, of course this pure native app are a little bit more smoother, but at the moment i work with my {N}-App and the native component. Hope this sample will be useful for someone.

Get the string from selected text/ highlighted text using JXA

I'm supper new here, either Javascript and JXA, so pardon me if I make some stupid questions. But I'm trying to figure out a way to get the string from the highlighted text using JXA - JavaScript for Automation, for Javascript can be recognized in Automator since Yosemite, I thought I can make something work with these:
window.getSelection in:
function getSelectedText() {
if (window.getSelection) {
txt = window.getSelection();
} else if (window.document.getSelection) {
txt =window.document.getSelection();
} else if (window.document.selection) {
txt = window.document.selection.createRange().text;
}
return txt;
}
This code is not mine, somebody posted this. But I've found out that I can't use window or document here in Automator to make change to Mac OS, so can someone show me how to convert this Javascript code into JXA which Automator can understand?
Thanks a lot!
In general, you can use the System Events app to copy and paste with any app.
'use strict';
//--- GET A REF TO CURRENT APP WITH STD ADDITONS ---
var app = Application.currentApplication()
app.includeStandardAdditions = true
var seApp = Application('System Events')
//--- Set the Clipboard so we can test for no selection ---
app.setTheClipboardTo("[NONE]")
//--- Activate the App to COPY the Selection ---
var safariApp = Application("Safari")
safariApp.activate()
delay(0.2) // adjust the delay as needed
//--- Issue the COPY Command ---
seApp.keystroke('c', { using: 'command down' }) // Press ⌘C
delay(0.2) // adjust the delay as needed
//--- Get the Text on the Clipboard ---
var clipStr = app.theClipboard()
console.log(clipStr)
//--- Display Alert if NO Selection was Made ---
if (clipStr === "[NONE]") {
var msgStr = "NO Selection was made"
console.log(msgStr)
app.activate()
app.displayAlert(msgStr)
}
For more info see:
Sending Keystrokes in JXA
JXA Resources
You need to mix JXA and Safari’s javaScript…
var Safari = Application("Safari") // get Safari
selection = Safari.doJavaScript("document.getSelection().toString()",{
in: Safari.windows[0].tabs[0] // assume frontmost window and tab
})
The script is in JXA, but the document.getSelection().toString() is Safari’s javaScript.
Of course you will need to enable apple events in Safari… http://osxdaily.com/2011/11/03/enable-the-develop-menu-in-safari/
If you want the selected text from another application, the code might be very different.
Don't do that, it's only applicable to JavaScript embedded inside a web browser. JXA is a standalone JS interpreter that has absolutely no understanding of web pages or DOM (and frankly doesn't have much clue about Mac application scripting either, btw).
Instead, use Automator to create an OS X Service as services can manipulate selected text in almost any OS X app; no application scripting required.

Is it possible to add buttons and control its event to toolbar of inappbrowser using javascript...?

I am developing a Hybrid App for iOS and Android using PhoneGap.Is it possible to add buttons and control its event to toolbar of inappbrowser using javascript.I know how to add it through ios native side but i cant use that process.I need to control the button event through a javascript method.
You have two options to do that.
The first option is, obviously, to patch the native plugin code, and that's it. Here you can find an example made for iOS, you will have to do the same to your Android Java code and for every other platform you want to support.
Another option is to hide the native toolbar and inject HTML and CSS to create a new one when the page is loaded.
Something like this:
// starting inappbrowser...
inAppWindow = window.open(URL_TO_LOAD, '_blank', 'location=no');
// Listen to the events, we need to know when the page is completely loaded
inAppWindow.addEventListener('loadstop', function () {
code = CustomHeader.html();
// Inject your JS code!
inAppWindow.executeScript({
code: code
}, function () {
console.log("injected (callback).");
});
// Inject CSS!
inAppWindow.insertCSS({
code: CustomHeader.css
}, function () {
console.log("CSS inserted!");
});
And you will have obviously to define the CustomHeader object, something like this:
var CustomHeader = {
css: '#customheader { your css here }',
html: function() {
var code = 'var div = document.createElement("div");\
div.id = "customheader";\
// Insert it just after the body tag
if (document.body.firstChild){ document.body.insertBefore(div, document.body.firstChild); } \
else { document.body.appendChild(div); }';
return code;
}
};
I had experience with this problem.
For my case, the second option was enough, not a critical task. Sometimes it takes a lot for the loadstop event to fire, and so you don't see the injected bar for >= 5 seconds.
And you have to pay attention even on the CSS of the loaded page, because obviously you can affect the original CSS, or the original CSS can affect the style of your toolbar.

iOS TextInput displayAsPassword doesn't displayAsPassword

I'm building an app to launch across Android, iOS, and desktop simultaneously. The app includes a login that is attached to a vBulletin system and I've run into a significant issue (that the client is adamant must be fixed). On iOS, if you are typing in a TextInput that has its displayAsPassword set to true, it will show plain text while typing. Once you click out of the TextInput, it displays properly.
Here is the code I am using within Flex
<s:TextInput id="inputField" width="100%" styleName="loginFields" text="Password" focusAlpha="0" focusEnabled="false" autoCorrect="false" />
I then attach focus events to the input field that run these functions.
private var defaultText:String = 'Password';
private var passwordDisplay:Boolean = true;
private function focusIn (e:FocusEvent = null):void {
if (this.inputField.text == this.defaultText){
this.inputField.text = '';
}
if (this.passwordDisplay){
this.inputField.displayAsPassword = true;
}
}
private function focusOut (e:FocusEvent = null):void {
if (this.inputField.text == ''){
this.inputField.text = this.defaultText;
if (this.passwordDisplay){
this.inputField.displayAsPassword = false;
}
}
}
There's a lot more code in the file, but this is the only relevant. Basically, on focus in, it checks if the text == the default text. If it does, it empties the field. It then sets displayAsPassword to true. On focus out, it checks if the field is empty. If it is, it resets the field to default and displayAsPassword to false. I know the default text is built in, but I needed more functionality than it offered.
Now, this issue (password displaying as plaintext while focus is on field) is present in iOS only and it doesn't occur in the emulator. It works perfectly and as expected on Android and desktop. I've tried recreating the functionality manually (possible but not ideal because caretIndex is not a TextInput property), I've tried hiding the TextInput and overlaying a field of '•' that match the length of the input (not possible because TextInput is StageText). I'm not sure what else I can try here. Any ideas?
Thanks in advance for any help here.
Specs:
Built and compiled using FlashBuilder 4.6 (but I also have 4.5.1 available to me)
Using Air 3.1
Compiled on OS X Lion
Tested on both 1st and 3rd gen iPads
Using Flex SDK 4.6.0

Resources