Titanium/ Alloy: Reapply styles on when screen is resized - titanium

I have some basic styles like:
"#foo": {
backgroundColor: '#ff0000', // red
}
"#foo[if=Alloy.Globals.isSmallHeight]": {
backgroundColor: '#0000ff', // blue
}
in alloy.js I have the following:
function pxToDp(px){
return px / (Titanium.Platform.displayCaps.dpi / 160);
}
var screenWidth;
var screenHeight;
if (Ti.Platform.name == "android") {
screenWidth = pxToDp(Ti.Platform.displayCaps.platformWidth);
screenHeight = pxToDp(Ti.Platform.displayCaps.platformHeight);
} else {
screenWidth = Ti.Platform.displayCaps.platformWidth;
screenHidth = Ti.Platform.displayCaps.platformHeight;
}
Alloy.Globals.isSmallHeight= screenHeight <= 545;
This basically means the background colour of #foo is blue if the screen height is less than or equal to 545dp, and red otherwise.
This usually works fine. However, there are times when the height of the screen can change during run-time. For example:
Screen Orientation Change
Multi window (on Android)
Adjusting the splitter position while in multi window mode (Android)
The issue with this is that the styles are not re-applied to take into account the new screen width and screen height.
For example, let's say there is a screen of size 600dp x 300dp in the portrait position. #foo will correctly have a background colour of red.
However, if the orientation changes, the screen size is now: 300dp x 600dp, but the #foo does not re-check the height a background colour, and thus is still red instead of blue.
A similar issue occurs when going into split screen.
Therefore my question is, how can I reapply styles when the screen dimensions changes?

Have a look at the dynamic styles section in the documentation
http://docs.appcelerator.com/platform/latest/#!/guide/Dynamic_Styling
http://docs.appcelerator.com/platform/latest/#!/guide/Dynamic_Styles
it will give you a basic idea on how to create style at runtime and apply them. You could do this inside the orientation change event

Related

React Native view scaling

So I'm developing a cross platform React Native app, the app is using allot of images as buttons as per design requirements that need to be given an initial height and width so that their aspect ratios are correct. From there I've built components that use these image buttons and then placed those components on the main screen. I can get things to look perfect on one screen by using tops and lefts/ rights to get the components positioned according to the design requirements that I've been given.
The problem I'm running into is now scaling this main screen for different screen sizes. I'm basically scaling the x and y via the transform property on the parent most view as such. transform: [{ scaleX: .8 }, { scaleY: .8 }] After writing a scaling function that accounts for a base height and current height this approach works for the actual size of things but my positioning is all screwy.
I know I'm going about this wrong and am starting to think that i need to rethink my approach but am stumped on how to get these components positioned correctly on each screen without having to hard code it.
Is there any way to position a view using tops and lefts/rights, lock that in place, then scale it more like an image?
First of all, try using flex as far as you can. Then when you need extra scaling for inner parts for example, you can use scale functions. I have been using a scale function based on the screen size and the pixel density, and works almost flawless so far.
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 screenSize = Math.sqrt(width * height) / 100;
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, screenSize };
Then you can import these and use in your components. There are different types of scales, you can try and see the best one for your components.Hope that helps.
I ended up going through each view and converting everything that was using a hard coded height and width pixel to setting the width and then using the property aspectRatio and giving that the hard coded height and widths. That along with implementing a scaling function that gave me a fraction of the largest view, so say .9, and then scaling the main view using transform. People arent kidding when they say this responsive ui stuff is tough.
2022 update -
I resolved this problem on my next app by using flex everywhere & a function called rem that I use everywhere that needs a fixed pixel count. With this I can set the width on an image and define an aspect ratio based on the images original dimensions and get an image that scales to the screen size, it's been super reliable.
static width = Dimensions.get("window").width;
static height = Dimensions.get("window").height;
static orientation = 'PORTRAIT';
static maxWidth = 428;
static rem = size => {
let divisor = window.lockedToPortrait || Styles.orientation === 'PORTRAIT' ? Styles.width : Styles.height;
return Math.floor(size * (divisor / Styles.maxWidth))
};
The maxWidth is a predefined value from the largest device I could find to simulate which was probably an iPhone max.

Hold Position of ScrollView when adding data

I am trying to make it so whenever something new is rendered into a scroll view, the scroll view will stay put and not bump up and down. Right now if a new component is rendered in, the scrollview appears to be reset to 0.
Is there a way to stop this behavior, and hold position?
Right now for the scrollview I am using:
handleScrollt(event){
this.scroll = event.nativeEvent.contentOffset.y
}
handleSizet(width, height){
if (this.scroll) {
const position = this.scroll + height - this.height
this.refs.sv.scrollTo({x: 0, y: position, animated: false})
}
this.height = height
}
<ScrollView
ref="sv"
scrollEventThrottle={16}
onScroll={this.handleScrollt.bind(this)}
onContentSizeChange={this.handleSizet.bind(this)}
The issue with this is the scrollview will render briefly, before then scrolling to the correct offset. So it seems like theres a brief splash of the top of the screen
you have to define a height for the scrollview.
If the scrollview is supposed to cover an entire View you can get the view's height by:
<View style={styles.contactView} onLayout={(event) => {
var contactViewY = event.nativeEvent.layout.y;
this.setState({contactViewY: contactViewY})
}}>
and then give it to the scrollview
<ScrollView style={[styles.contactScroller, {height: this.state.contactViewY}]}>
Bear in mind that the onLayout method is called immediately once the layout has been calculated, so if the view's height changes later, this two lines of code alone won't update it.
You should try maintainVisibleContentPosition.
Example:
<ScrollView
{...props}
maintainVisibleContentPosition={{
minIndexForVisible: 0,
}}
/>
From the docs:
maintainVisibleContentPosition
When set, the scroll view will adjust the scroll position so that the
first child that is currently visible and at or beyond
minIndexForVisible will not change position. This is useful for lists
that are loading content in both directions, e.g. a chat thread, where
new messages coming in might otherwise cause the scroll position to
jump. A value of 0 is common, but other values such as 1 can be used
to skip loading spinners or other content that should not maintain
position.

Setting UI Button width and height in cocos2d js android application

In my Cocos2d js android app i have a UI button as
var button=new ccui.Button();
button.loadTextures(res.play_png,res.play_png);
button.setAnchorPoint(cc.p(0,0));
button.x=size.width/2;
button.y=size.height/2;
this.addChild(button);
The button loads and i am able to set it at any position on the screen.
But i am unable to change its width and height to specified number of pixels.
I want something like
button.width=100;
button.height=100;
I did not find any method to do that...
Any help how to accomplish this would be greatful.
Thanks.
The buttons i use are options like play,how to play,share etc..
So i have to position them in such a way that they dont overlap or get distorted for various screen resolutions...
How can i use the setScale method in this context???
We can make a call to a function that can scale the size of the UIButton by performing an action. In this case, the following code might help:
performScaleAction : function()
{
var duration = 0; // duration in seconds for performing this action
var scaleX = 0.5; // scale factor for X-axis
var scaleY = 0.5; // scale factor for Y-axis
var scaleAction = new cc.ScaleTo(duration , scaleX , scaleY );
this.runAction(scaleAction);
}
Now, call the above function in the following way:
this.performScaleAction();
this.addChild(button);
So, if the actual height of the image used for creating the UIButton is h, in this case, the new size as displayed on the screen would be h times scaleX . Same for the width of the UIButton.
Hope this helps!

Magnific Popup - taller mfp-bottom-bar causes max image height issue

I am customizing the title of the Magnific popup/lightbox to include more than one row of content by using the 'change' callback, and modifying the content of
this.content
within the callback. It is working correctly, except for the fact that if the image within the popup is very tall, or the window re-sizes to a smaller height, the calculation that Magnific is doing to adjust the 'max-height' of the image seems to only take into account a single row of text for the title.
Does anyone know what is needed to adjust the max-height calculation of the image to take into account a taller title box?
Thank you
** Edit
A quick hack to jquery.magnific-popup.js around line 461 in the "updateSize:" callback has allowed me to get around this problem. It seems reasonable to for this popup/lightbox to accept a max height in percentage so that it doesn't fill the screen.
Here's my change, I'd appreciate some feedback if possible. Thanks!
updateSize: function(winHeight) {
if(mfp.isIOS) {
// fixes iOS nav bars https://github.com/dimsemenov/Magnific-Popup/issues/2
var zoomLevel = document.documentElement.clientWidth / window.innerWidth;
var height = window.innerHeight * zoomLevel;
mfp.wrap.css('height', height);
mfp.wH = height;
} else {
mfp.wH = winHeight || _window.height();
// ########################################
// CHANGE IS RIGHT HERE TO FORCE 80% height
// ########################################
mfp.wH *= 0.8;
}
// Fixes #84: popup incorrectly positioned with position:relative on body
if(!mfp.fixedContentPos) {
mfp.wrap.css('height', mfp.wH);
}
_mfpTrigger('Resize');
},
You can limit the max height of the image in the resize callback, which will allow more room for the title:
$('a.magnific').magnificPopup({
type: 'image',
callbacks: {
resize: function() {
var img = this.content.find('img');
img.css('max-height', parseFloat(img.css('max-height')) * 0.95);
}
}
});
I'd like to add my contribution. As I wanted to include both titles and descriptions to images. This meant that I couldn't fit all this information in the viewport space. The description was cut off and I was left with a scrollbar.
#alexantd - I tried your callback addition which only works when the window is being resized.
#ajhuddy - Your solution worked perfectly for me. I was able to fit the text in fine. Though the image was considerably small with a lot of space at the top.
I adjusted the padding as to regain 40px space to display a slightly larger image. Here's my CSS to do so. The CSS below allowed me to reduce images to 0.85 (85%).
.mfp-img {
padding: 0px 0px 40px !important;
}
.mfp-close {
margin-top: -40px;
}
else b.wH=a||v.height()**,b.wH*=.9**;b.fixedContentPos

QML:Transparency for an rectangle is not working

How to set transparency of an rectangle/screen.
I have Following code:
// main.cpp
void main(int argc, char*[] argv)
{
QApplication::setGraphicsSystem("raster");
QApplication app(argc, argv);
QDeclerativeView view;
view.setSource(QUrl::fromLocalFile("loaderTest.qml"));
view.setResizeMode(QDeclarativeView::SizeRootObjectToView);
view.showFullScreen();
//QRegion mask(10, 10, 100, 100);
//view.setMask();
view.show();
app.exec();
}
And QML file is:
//loaderTest.qml
Rectangle
{
id: mainRectangle
width: 1000
height: 700
color: "transparent"
//color: "#00000000"
Image
{
id: image1;
width: 348;
height: 155;
anchors.horizontalCenter: parent.horizontalCenter;
anchors.verticalCenter: parent.verticalCenter;
source: "test.png"
}
Loader
{
id: mainLoader
anchors.fill: parent;
source: "";
focus: true;
}
}
I have one loader and one image in this screen and background color is transparent.
When i run this application it should display transparent background with image in the center (as i have not set loader source).
but what i am getting is image in center with white background filled in the screen, I don’t know who is filling in this white background color as i have mentioned transparent color as background.
I am using QT.4.7.0 and Linux.
I have two planes on my target system one is Video plane and another is graphics plane, when i run GUI with transparent background (set transparency at video place) it should display video on Video place in above example it is showing background as white, as it should have displayed video playing on Video plane.
By default the QDeclarativeView paints a background. Maybe that's the problem in your case.
From http://doc.qt.nokia.com/4.7/qdeclarativeperformance.html
You can also prevent QDeclarativeView from painting its window background if you will provide the background of your application using QML, e.g.
QDeclarativeView window;
window.setAttribute(Qt::WA_OpaquePaintEvent);
window.setAttribute(Qt::WA_NoSystemBackground);
window.viewport()->setAttribute(Qt::WA_OpaquePaintEvent);
window.viewport()->setAttribute(Qt::WA_NoSystemBackground);
My first guess is that the background is white and your rectangle is indeed fully transparent.
What type is LoaderScreen, I guess it is some sort of QDecalarativeView, please forgive any technical misses have not coded Qt/QML for almost a year now. As I remember it the default background of the view was white and what kind of transparency are you hoping to achive anyways?
If you only set a background-color on a QPushButton, the background may not appear unless you set the border property to some value. This is because, by default, the QPushButton draws a native border which completely overlaps the background-color.
This might show a black rectangular box around QPushButton. You will face this issue especially on Linux machines. In order to avoid this you can set the border property to none
widget->setStyleSheet("border:none");