In my Cardboard app for Android, I want to display an overlay in each eye that centers. Simply creating a LinearLayout with two centered views is fairly easy and works for most phones as the eyes are drawn to best fit:
When that's not the case, getting something to center in each eye becomes a problem. It's most clearly illustrated when using a tablet:
I'm trying to get the message "Buffering, 0%..." centered inside each eye view.
The size of the render boxes for the eyes has a fixed dimension (of course, because the distance between human eyes has a fairly fixed size). Unfortunately, CardboardView doesn't appear to provide information about the exact size and/or position of the eyes.
I've looked into obtaining the left and right Eye through cardboardView.getCurrentEyeParams() (oddly undocumented), for which each Eye contains a Viewport. This appears to give a size and position, but its values don't appear to have an immediate relation with the size and placement on the screen.
On a LG G2 with a screen resolution of 1920×1080, the Viewports are:
Viewport left: {
x: 0,
y: 0,
width: 1150,
height: 1177,
}
Viewport right: {
x: 1150,
y: 0,
width: 1150,
height: 1177,
}
On a Nexus 9 with a screen resolution of 2048×1536, the Viewports are:
Viewport left: {
x: 0,
y: 0,
width: 802,
height: 802,
}
Viewport right: {
x: 802,
y: 0,
width: 802,
height: 802,
}
Both of these dimensions (if they're in pixels) are much larger than the actual image displayed, and in the case of the LG G2, the width and height indeed larger than the screen size of 1080px.
Looking into some decompiled code of the Cardboard SDK, it appears that the vignetted square around the eyes is drawn through an internal class called DistortionMesh, and is rendered through some somewhat complex code. (Note that some logic appears to be missing through decompilation, such as lines 195 and 199.)
The creation of the Viewport suggests that the values are indeed pixels (offset in meters, multiplied by pixels per meter). Perhaps that DistortionMesh or the EyeView matrix is applied to the Viewport before rendering? In any case, I get the feeling I'm not looking in the right place.
I've also taken a look at obtaining the ScreenParams, as it provides a width and height as well. Unfortunately, this returns the entire screen size on both devices and also doesn't appear to be relevant.
My current approach overlay is a custom ViewGroup that centers two children through calling child.layout() using the ScreenParams' height and half of its width.
How can I figure out how large the Eyes are drawn into StereoRenderer? Can I find a different way to center a different view in the eyes?
Related
I was wondering if there is a conscious intention of using even numbers for measurement units when building Android layouts. For example in the Android desgin guidelines there are always multiple of 2 being used as I could see, at least I don't remember Google ever using 3, 5 or so for padding/margin, is there an official reference talking about this somewhere so I could strongly argument that using uneven numbers is wrong?
It is just a coincidence that material design has even numbers for their dp measurements. As you can see here it is not a rule, just a coincidence. Typography has some examples of odd measurements:
Subheading
English: Regular 16sp (device), 15sp (desktop)
Dense: Regular 17sp (device), 16sp (desktop)
Tall: Regular 17sp (device), 16sp (desktop)
Generally, sizes are increased exponentially rather than linearly. Or atleast differences between subsequent sizes increases. (Because human brains think logarithmically instead of linearly: Why In Our Brains The Midpoint Of 1 And 9 Might Be 3)
Like 2dp, 4dp, 8dp, or 160, 240, 320, 480, 640(Image scaling)
So if you start with a 2, you'll get all even numbers but if you start with a 1 or 5, you'll get odd numbers as well.
It could just as well have been 5, 10, 25, 50.
Boostrap has some odd measurements:
#padding-small-vertical: 5px;
#padding-small-horizontal: 10px;
#padding-xs-vertical: 1px;
#padding-xs-horizontal: 5px;
But even here the exponential growth is visible.
I made a website completely with vh and vw scaling. Now, for big screens this makes it sufficiently responsive, but now I want to make it responsive for mobile screens. In my website all content is within the middle 60% of the screen. There are shapes, images and text. If I make the screen too small I cannot read the text anymore but there still is 40% of the screen that is almost blank (only a background). Now, when the screen is too narrow, I want the margins left and right (the blank parts of the screen) to get smaller, and the content to not get smaller. Can you do this still using vw and vh or do I have to change everything in pixels?
I tried this already by for example making the body 200vw when the screen was narrower than 500px, but with no luck.
Can anyone help me? It would really suck If I had to make it all over again in pixels as the positions of my elements are all quiet complex.
Thanks!
There are three solutions that came to my mind:
Using breakpoints
Using min-width & width combination
Fluid layout
1. Breakpoints:
So, you want to set the width of your main container element to be 60%, if the document width is larger than 768px (for example, max mobile resolution). The code will be:
.container {
margin: 0 auto; // horizontally centering element
background-color: pink; // just to see where the element is
}
// targeting mobile screen size:
#media only screen
and (max-width: 768px)
and (-webkit-min-device-pixel-ratio: 2) {
width: calc(100% - 30px);
}
// targeting larger screens
#media only screen
and (min-width: 769px)
and (-webkit-min-device-pixel-ratio: 2) {
width: 60vw;
}
2. Min-width: is maybe an easier solution, but not that good if you also have other elements child elements styled with viewport units, where you just need to determinate what is the minimum container width that looks alright and set it as a value of min-width property.
.container {
margin: 0 auto; // horizontally centering element
background-color: pink; // just to see where the element is
width: 60vw;
min-width: 320px;
}
Maybe third, the most advanced technique that can help you, if none of above can, is this Fluid technique, explained in a detail in this Smashing magazine's post, which is actually the most interesting in typography cases, because the most common technique for the layout is the one that I explained first.
Hope I managed to help.
I am contributing to an Open Source Project where I am developing Material design for React Native. I am blocked at work,I am unable to make some UI level enhancements w.r.t. padding, alignment etc.,
This is the Official Spec of Material Design for Drawer-
In the above image, the UNIT of measurement is dp.
But, in my React Native code, I see there is no such units mentioned. Considering it is "react native" I am confused whether it is px or dp.
I even went over the Official Docs of React Native for Style component. I don't see a mention anywhere.
My Code looks like-
const styles = {
touchable: {
paddingHorizontal: 16,
marginVertical: 8,
height: 48
},
item: {
flex: 1,
flexDirection: 'row',
alignItems: 'center',
},
icon: {
position: 'relative',
},
value: {
flex: 1,
paddingLeft: 34,
top: 2
},
label: {
top: 2
}
},
Please can you tell me, if this is pixels or dp? And also, is 1px = 1dp?
From the docs:
All dimensions in React Native are unitless, and represent
density-independent pixels. Setting dimensions this way is common for components that should always render at exactly the same size, regardless of screen dimensions.
So yes, units in React Native are in dp. If you want to convert them to pixels, use PixelRatio.getPixelSizeForLayoutSize()
I share your confusion somewhat, not being able to actively inspect with a developer console as we are used to in the browser.
I am not familiar with the 'dp' unit, but from what I gather width: 1 renders differently on each device depending on the pixel density of the screen (see link). The information in the react-native docs say that 1 would render thicker on screens with high pixel density. Which then sounds logical as you have more precision on high density screens than you would have on low density screens and react-native aims at being universal so it would not assume high dpi.
It is my understanding that you can use the below linked PixelRatio API to calculate sizes for detail elements (think borders, icons, etc), that way you can dynamically adjust the rendered size according to the device's screen density.
https://facebook.github.io/react-native/docs/pixelratio.html#content
It is the pixel ratio that you have to consider. pixel represents an absolute value. pixel ratio is a relative value. to make app screen and components responsive you have to use pixel ratio.
i have been using in multiple apps already. and i think that is how you have to do it. hope this answers your question.
From what I know, the javascript styling that we use in react js or react native uses pixels. Pixel ratio is only needed to support different size of mobile device screens.
I have added a view to my app defined as follows:
Ti.UI.createView({
top: 0,
left: 0,
width: '50%'
height: '460dp',
backgroundColor: 'red'
});
What I want to find out is whether the above view fits on the screen. I.e. whether the user's screen is tall enough to totally display my entire view. I tried it in the following way:
function getPixels(dp) {
return (dp + (Ti.Platform.displayCaps.dpi / 160));
}
alert(460); // 920
alert(Ti.Platform.displayCaps.platformHeight); // 1136
Which seems about right on the iphone simulator. However when running that exact same code on my android device I get the result:
screenheight: 1200
height of the view: 690
Which doesn't seem correct, because the view with the red background takes almost as much space on the iphone simulator as on my android device.
Is there any way to get consistent results on all devices (ios and android). Or is there some other way to solve my problem?
If you are trying to support all sizes, why don't you set your height to a % value as well?
In answer to your question, the main thing you need to consider is thatTi.Platform.displayCaps.platformHeight returns values in platform-specific units; so pixels on Android and density-independent pixels (dip) on iOS. Since you are setting your view height with density independent pixels, you instead want to convert these platform units to density independent and platform independent units.
I usually just use the measurement library provided by Titanium and Alloy.
var measurement = require('alloy/measurement');
var dpHeight = measurement.pxToDP(Ti.Platform.displayCaps.platformHeight);
if(460 < dpHeight) {
alert('Fits');
} else {
alert("does not fit');
}
But really I find it much easier to just use relative layouts with percentage values.
Another way to figure out if the view is in bounds (after the fact) is to just add a postlayout event listener, when this event is fired it means layout bounds have been calculated in system units and are now accesible:
view.addEventListener('postlayout', function(e) {
if(view.rect.height + view.rect.y > Ti.Platform.displayCaps.platformHeight) {
alert('Does not fit")
}
});
To get constant results of width and height properties between platforms you have to add
<property name="ti.ui.defaultunit" type="string">dip</property>
to tiapp.xml and provide sizes as plain numbers:
Ti.UI.createView({
top: 0,
left: 0,
width: 50,
height: 460,
});
(I've seen this already; I do not believe this is a duplicate: Are the decimal places in a CSS width respected?)
I set the size of an object as follows:
.foo {
height: 10.5px;
width: 10.5px;
}
Normally, that rounds down; you can't use half a pixel.
That said, the latest Nexus 7 has 320dpi, and a CSS pixel on an Android device is defined as 160dpi. A 10px by 10px image is drawn on the Nexus 7 using 400 pixels, not 100.
So on high-pixel density devices - those where window.devicePixelRatio > 1.0 - are fractional pixels useful, or just discarded anyways?
(Thanks!)
Edit, for a somewhat real-world example.
I have a MacBook Retina. I have a image file that's 21x21 px. I want this to display on my retina without rescaling in any way; I want each pixel in the file to correspond to one pixel on the screen. CSS pixels aren't linked to hardware pixels, and 1 px in CSS corresponds to 4px (2 wide, 2 high) on a Retina display or Nexus 7/10.
I want to be able to specify the exact size of the image, so that it's not rescaled, and so that the page doesn't reflow once the image is loaded. I can do this by putting the image into an div that's set to 11x11, and having the image display as 100%, but that's adding an extra div, and I'm a touch OCD about page size.
They are discarded.
I think I get what you are trying to achieve with the fractional pixels, but really the route you need to go is using higher resolution images for the higher density displays. That should do what you want, no?
I can't think of any reason you would ever need the fractional pixel, or anything similar to it.
That being said, fractional pixels don't work, but fractional percentages do.
.foo {
height: 10.5%;
width: 10.5%;
}
This will work and should do whatever you would need fractional pixels for (you would need to change the percentage obviously from the example).