For a simple project which will be deployed to specific devices, I am wondering if it is possible to specify measurements using native pixels, hence ignoring the device dpi (which could be, for instance, overridden by the user in Windows at system level).
Currently, the only solution seems to divide any value for pixel ratio.
Is there a simpler hence more manageable way?
React Native comes with a PixelRatio module that has a method called get. You must manually divide all of your measurements by the pixel ratio.
Start with the number of physical pixels.
Divide it by the pixel ratio (PixelRatio.get()) to get the corresponding number of logical pixels.
Use the number of logical pixels in StyleSheet.create and other layout-related methods.
React Native and the underlying native UI frameworks will convert the logical pixels back to physical pixels.
You could write a helper method for this if it were to get tedious. This is an idea for an API:
StyleSheet.create({
box: {
width: physical(100),
height: physical(75),
},
});
Most of the time though you should work with logical pixels. It's only when you want to precisely control the hardware screen or are interacting with a system without a notion of screen scale (e.g. fetching a JPEG image) that you'd want to work with physical pixels.
Related
I'm working on a react native application in a company and my manager asked me what is the best image size in pexels to upload from API (dashboard) to fit the View in the application ?
And I'm using percentage units not numbers: (width: '80%', height: '50%') I don't know what is the best sized of images to fit or the aspect ratio of the image and react native is unitless!
What should we add 'Hint' for the client in the dashboard when he upload any image ?
Or how could I know the best image dimensions to fit all screens ?
In our organisation, we usually follow the following convensions to make an image fully responsive.
Get the dimentions of the image using: const {width, height} = Image.resolveAssetSource('path-to-your-image');
Get the ratio factor of width and height by using: const ratioFactor = height/width;
Whenever you set the width of your screen by 'n' digit, set the height to 'n*ratioFactor'
In this ways the image can never be stretched or compressed. It will be fully responsive according to it's dimensions.
Preferably use image with standard dimentions as 1024 x 768 pixels.
In case the app target both iOS and Android, there is a multitude of devices with various resolutions and pixel densities from high-end iPads to low-end androids devices with smaller resolutions.
The General rule of thumb is to find the average image size which will not pixelated (look blurry) on the high-end devices but does not have a large download size in case some users will have slow internet.
You should start with 1024 x 768 pixels which is a standard dimension for iPad
Consider using resizeMode prop of react native image. With resizeMode you can manage to render image based on available space in screen.
Check it here : https://reactnative.dev/docs/image#resizemode
Since React Native uses only pixels or percentages for units, how do we handle accessibility of larger text?
I know I can disable font scaling, but that is what I specifically do not want to do.
I am asking specifically for TextInput since there are other parts of the screen which won't change even if you scale up like the bottom nav bar. Because say we set a widget for time input on the browser we can say 5em to limit it to 5 character sizes regardless of the size of the text.
One way I can think of is to use * 16 in place of em but that does not work when you scale up the font since 16 is fixed.
Also I am looking for something that works in Expo. AccessibilityInfo does not appear to provide the size and I can't find any information on accessing the value of Dynamic Type
My crazy idea at the moment is to have a transparent Text that I has an onLayout and I obtain the size of the component and set it in a context that all my custom TextInput will use as a measurement that has a size based on number of characters.
react-native-elements is utilizing a helper function called normalize for font scaling which is implemented as follows.
import { moderateScale } from 'react-native-size-matters';
function normalize(number, factor = 0.25) {
return moderateScale(number, factor);
}
export default normalize
I'm currently using react-native-size-matters on developing UIs for multiple devices along with above font scaling by react-native-elements. Works fine in almost all the time.
Check out the react-native-size-matters repo is you have doubts on the implementation. Author has a good article written on explaining his approach as well.
PixelRatio.getFontScale() allows you to get the font scale that adjusts its number based on the user's choice of dynamic type.
The number you can use as a multiplier on the widths to increase or decrease depending on the font size if a dynamic font size is used.
One thing to note though, changing the size does not trigger a re-render unlike useColorScheme() since there's no context provided that has this information.
I am implementing a "ruler" feature to my app and it is critical that the ruler size/scale, in centimeters, is consistent across multiple devices. That is, 1 'tick' must be always equal to 1 centimenter. Howerver I have not found in any documentation a way to size components using real-world units (cm, inch) like you can do in CSS; Nor have I found a way to accurately get the screen size (in inches or cm) or DPI.
Is there a way to use cm/inches in React Native or get the REAL screen DPI?
1 inch = 160 dp (Always)
Note that 1 inch is ALWAYS 160dp, independent of screen size. A dp(density-independent pixels) is a physical distance of 1/160th of an inch.
React-Native uses dp(density-independent pixels) as the unit in styling.
So, if you write:
<View style={{ height: 160, width:160, backgroundColor: 'red }}>
</View>
This gives you a red block of 1 inch X 1 inch
Dimensions properties in react native are unitless, so those properties are not available in ReactNative. The best you can do is use PixelRatio's getPixelSizeForLayoutSize() which is documented here: https://reactnative.dev/docs/pixelratio#getpixelsizeforlayoutsize
You would need to also have the pixel density (dpi) for your solution, and the formula:
https://www.pixelto.net/px-to-cm-converter
You still might run into some weird situations where pixels are split in half and other rounding errors as you're trying to fit 1cm into tiny pixels on the screen that may not always equal to 1cm, due to physical limitations.
My game is in window mode which allows users to resize the game
window almost freely, which means the the ratio of the width/height,
and the size of the window can be arbitrary (though the window has
largest and smallest restrictions)
To make the render result be displayed nicely, a same size d3d
device would be preferred to create (thus the back-buffer pixel can
be matched with the screen pixel and we could get a ratio right and
clear image)
Though I can get the Caps and the supported enumerated resolution
list, I am not sure if a windowed resolution can be accepted by d3d
system. (e.g. we have 1024x768 /800x600 in the Caps, but we need to
create 1000x700 back-buffer)
My question is, how can I make sure if a certain resolution can be created and what's the practical way to handle the problem.
Thank you very much!
In windowed mode you can create any resolution swap chain (subject to some maximum size constraints which will be greater than any supported screen resolution). It's only in full screen mode that you are constrained to creating swap chains of sizes that are on the enumerated resolution list.
I just noticed an interesting thing while attempting to update my app for the new iPad Retina display, every coordinate in Interface Builder is still based on the original 1024x768 resolution.
What I mean by this is that if I have a 2048x1536 image to have it fit the entire screen on the display I need to set it's size to 1024x768 and not 2048x1536.
I am just curious is this intentional? Can I switch the coordinate system in Interface Builder to be specific for Retina? It is a little annoying since some of my graphics are not exactly 2x in either width or height from their originals. I can't seem to set 1/2 coordinate numbers such as 1.5 it can either be 1 or 2 inside of Interface Builder.
Should I just do my interface design in code at this point and forget interface builder? Keep my graphics exactly 2x in both directions? Or just live with it?
The interface on iOS is based on points, not pixels. The images HAVE to be 2x the size of the originals.
Points Versus Pixels In iOS there is a distinction between the coordinates you specify in your drawing code and the pixels of the
underlying device. When using native drawing technologies such as
Quartz, UIKit, and Core Animation, you specify coordinate values using
a logical coordinate space, which measures distances in points. This
logical coordinate system is decoupled from the device coordinate
space used by the system frameworks to manage the pixels on the
screen. The system automatically maps points in the logical coordinate
space to pixels in the device coordinate space, but this mapping is
not always one-to-one. This behavior leads to an important fact that
you should always remember:
One point does not necessarily correspond to one pixel on the screen.
The purpose of using points (and the logical coordinate system) is to
provide a consistent size of output that is device independent. The
actual size of a point is irrelevant. The goal of points is to provide
a relatively consistent scale that you can use in your code to specify
the size and position of views and rendered content. How points are
actually mapped to pixels is a detail that is handled by the system
frameworks. For example, on a device with a high-resolution screen, a
line that is one point wide may actually result in a line that is two
pixels wide on the screen. The result is that if you draw the same
content on two similar devices, with only one of them having a
high-resolution screen, the content appears to be about the same size
on both devices.
In your own drawing code, you use points most of the time, but there
are times when you might need to know how points are mapped to pixels.
For example, on a high-resolution screen, you might want to use the
extra pixels to provide extra detail in your content, or you might
simply want to adjust the position or size of content in subtle ways.
In iOS 4 and later, the UIScreen, UIView, UIImage, and CALayer classes
expose a scale factor that tells you the relationship between points
and pixels for that particular object. Before iOS 4, this scale factor
was assumed to be 1.0, but in iOS 4 and later it may be either 1.0 or
2.0, depending on the resolution of the underlying device. In the future, other scale factors may also be possible.
From http://developer.apple.com/library/ios/#documentation/2DDrawing/Conceptual/DrawingPrintingiOS/GraphicsDrawingOverview/GraphicsDrawingOverview.html
This is intentional on Apple's part, to make your code relatively independent of the actual screen resolution when positioning controls and text. However, as you've noted, it can make displaying graphics at max resolution for the device a bit more complicated.
For iPhone, the screen is always 480 x 320 points. For iPad, it's 1024 x 768. If your graphics are properly scaled for the device, the impact is not difficult to deal with in code. I'm not a graphic designer, and it's proven a bit challenging to me to have to provide multiple sets of icons, launch images, etc. to account for hi-res.
Apple has naming standards for some image types that minimize the impact on your code:
https://developer.apple.com/library/ios/#DOCUMENTATION/UserExperience/Conceptual/MobileHIG/IconsImages/IconsImages.html
That doesn't help you when you're dealing with custom graphics inline, however.