I have a scroll view in my alloy project and I need to add a few views when a button is pressed, but the content height, the scrollable area, is not changing, the bottom content goes away from the view.
This is my Alloy View (.xml) file
<Alloy>
<Window class="container">
<ScrollView id="MainView" >
<View id="innerContent" class="rowLayout">
<Label>Address 1</Label>
<TextField id="Address1" class="textArea"></TextField>
</View>
</ScrollView>
<View id="buttonView">
<Button id="button" onClick="doClick" title="Add New Address Input" top="10" width="100" height="50" />
</View>
</Window>
</Alloy>
My styling file (.tss), with all the styles:
".container": {
backgroundColor:"white",
height: Titanium.UI.FILL
}
"#MainView": {
width: Titanium.UI.FILL,
height: Titanium.UI.FILL,
scrollType: "vertical",
layout: "vertical",
bottom: "100dp",
top: "20dp",
borderColor: "#008000",
borderWidth: "1px",
left:"2dp",
right: "2dp"
}
"#buttonView" : {
height: "50dp",
width: Titanium.UI.FILL,
right: "10dp",
left: "10dp",
bottom: '8dp',
borderColor: "#000000",
borderWidth: "1px"
}
".rowLayout": {
layout: "vertical"
}
".textArea" : {
height: "70dp",
width: Titanium.UI.FILL,
borderColor: "#000000",
borderWidth: "1dp",
left: "8dp",
right: "8dp"
}
And my Controller (.js)
var counter=0;
function doClick() {
counter++;
var label = Ti.UI.createLabel({
text: "Address " + counter + " :"
});
var textField = Ti.UI.createTextField({
height: "70dp",
width: Titanium.UI.FILL,
borderColor: "#000000",
borderWidth: "1dp",
top: "5dp",
right: "8dp",
left: "8dp"
});
$.innerContent.add(label);
$.innerContent.add(textField);
}
$.index.open();
The scroll views does not scroll, or if I already set 3 or four inputs it scroll only to the point where the fourth input was
First thing to do is to move your styling from .xml to .tss to increase overview
Try to set your ScrollView height to Ti.UI.SIZE then set layout to vertical and after that on your click function you add the new view at top: '5%', bottom: '5%'
but remember... you have an button outside your ScrollView, it will goes off screen when your ScrollView increase height
Related
Today i want to do something like the picture below. I want to arrange the matches so that they form these numbers. But I'm not sure if the way I did it will be responsive on different phones? I don't think so ..
My code so far is
import { StatusBar } from "expo-status-bar";
import { Image, StyleSheet, View } from "react-native";
export default function App() {
return (
<View style={styles.container}>
<StatusBar style="auto" hidden={true} />
<Image
style={{
height: 80,
width: 80,
position: "absolute",
top: "61%",
left: "10%",
transform: [{ rotate: "90deg" }],
}}
source={require("./assets/match.png")}
/>
<Image
style={{
height: 80,
width: 80,
position: "absolute",
top: "56.8%",
left: "19.8%",
transform: [{ rotate: "180deg" }],
}}
source={require("./assets/match.png")}
/>
<Image
style={{
height: 80,
width: 80,
position: "absolute",
top: "52%",
left: "10%",
transform: [{ rotate: "90deg" }],
}}
source={require("./assets/match.png")}
/>
<Image
style={{
height: 80,
width: 80,
position: "absolute",
top: "44%",
left: "10%",
transform: [{ rotate: "90deg" }],
}}
source={require("./assets/match.png")}
/>
<Image
style={{
height: 80,
width: 80,
position: "absolute",
top: "48%",
left: "0%",
}}
source={require("./assets/match.png")}
/>
</View>
);
}
const styles = StyleSheet.create({
container: {
flex: 1,
backgroundColor: "#fff",
alignItems: "center",
justifyContent: "center",
},
});
So on my iPhone it looks like that -
But on Android it not looks good at all -
So I want to ask is there a way I can position the matches correctly or i should create image in photo editor and use it in app?
Sorry for my bad English!
I'm trying to create a dashboard layout from a react-native project. The idea is to keep most of the code similar for Android, iOS and Web only the layout or navigation style will change. But I find making this type of layout in web is easy but to make it responsive without re-rendering is difficult.
I have achieved this by manually calculating the windows heigh and width by following the code
Dimensions.get('window').width
Dimensions.get('window').height
and by eventListener keep updating the state so that it re-renders the whole page again and again.
Dimensions.addEventListener("change", this.updateScreen);
Is there a way I can simply use some % value to fill up the screen. Right now if I use % it squeezed to a child View size. I even tried flex:1 with alignSelf:stretch, alignItem:stretch, width:'100%' etc but no luck.
For a while, let's talk about center row (image attached) it contain 3 columns. I want left and right block (Menu & Call to Action) to be 300px each. Now if I'm on 1000px width monitor my Content block should be (1000 - (300+300)) 400px. if monitor is 1200px then Content block will be (1200 - (300+300)) 600px.
I hope this doesn't come too late.
<View style={{ flex: 1 }}>
<View style={{ height: 100, backgroundColor: 'red' }} />
<View style={{ flex: 1, backgroundColor: 'gray', flexDirection: 'row' }}>
<View style={{ width: 100, backgroundColor: 'green' }} />
<View style={{ flex: 1, backgroundColor: 'blue' }} />
<View style={{ width: 100, backgroundColor: 'green' }} />
</View>
<View style={{ height: 100, backgroundColor: 'red' }} />
</View>
This is the result from the above code.
You don't need to do percentage calculations at all; just structure it in 2 layers of flex layout.
For the components that should not stretch, state their width. For the rest, specify the flex value.
If you insist on using 1 layer to handle it all, then we shall discuss again.
Cheers.
I made this exactly for the same reasons:
https://www.npmjs.com/package/react-native-animated-layout
Demos:
Expo snack: https://snack.expo.dev/#mehmetkaplan/react-native-animated-layout
Web demo: https://mehmetkaplan.github.io/react-native-animated-layout/
It takes layouts as inputs and using the Width / Height ratio of the screen, decides which layout to use.
And within each layout, you define top, right, bottom, left of each screen using the coordinates between 0 and 1. (Because browser resizing changes the coordinates of each View and you want views to stay exact relative places.)
import React, { useState, useEffect } from 'react';
import { Text, View } from 'react-native';
import ReactNativeAnimatedLayout from 'react-native-animated-layout';
export default function App() {
const [rerender, setRerender] = useState(0);
const redView = <View style={{ backgroundColor: 'red', height: '100%', width: '100%', }}><Text>{"I am the red view"}</Text></View>;
const greenView = <View style={{ backgroundColor: 'green', height: '100%', width: '100%', overflow: 'hidden'}}>
<Text>{"I am the green view and my contents overflow. Because of the overflow prop, the over-flown content is hidden."}</Text><Text>{"0"}</Text><Text>{"1"}</Text><Text>{"2"}</Text><Text>{"3"}</Text><Text>{"4"}</Text><Text>{"5"}</Text><Text>{"6"}</Text><Text>{"7"}</Text><Text>{"8"}</Text><Text>{"9"}</Text><Text>{"10"}</Text><Text>{"11"}</Text><Text>{"12"}</Text><Text>{"13"}</Text><Text>{"14"}</Text><Text>{"15"}</Text><Text>{"16"}</Text><Text>{"17"}</Text><Text>{"18"}</Text><Text>{"19"}</Text><Text>{"20"}</Text><Text>{"21"}</Text><Text>{"22"}</Text><Text>{"23"}</Text><Text>{"24"}</Text><Text>{"25"}</Text><Text>{"26"}</Text><Text>{"27"}</Text><Text>{"28"}</Text><Text>{"29"}</Text>
</View>;
const blueView = <View style={{ backgroundColor: 'blue', height: '100%', width: '100%', }}><Text>{"I am the blue view"}</Text></View>;
const layouts = [
{
validAfterWHRatio: 0,
validBeforeWHRatio: 0.9,
views: [
{ top: 0, bottom: 0.5, left: 0, right: 1, children: redView },
{ top: 0.75, bottom: 1, left: 0, right: 1, children: blueView },
{ top: 0.5, bottom: 0.75, left: 0, right: 1, children: greenView },
]
},
{
validAfterWHRatio: 1 / 0.62,
validBeforeWHRatio: 999, // infinity
views: [
{ top: 0, bottom: 1, left: 0, right: 0.5, children: redView },
{ top: 0.5, bottom: 1, left: 0.5, right: 1, children: blueView },
{ top: 0, bottom: 0.5, left: 0.5, right: 1, children: greenView },
]
},
{
defaultFlag: true,
views: [
{ top: 0.16, bottom: 0.84, left: 0.16, right: 0.5, children: redView },
{ top: 0.50, bottom: 0.84, left: 0.5, right: 0.84, children: blueView },
{ top: 0.16, bottom: 0.50, left: 0.5, right: 0.84, children: greenView },
]
},
];
useEffect(() => {
let nextRerender = rerender + 1;
setRerender(nextRerender);
}, []); // when we want to re-render
return <ReactNativeAnimatedLayout
layouts={layouts}
rerender={rerender}
/>;
}
Note: This approach may be useful especially for PWAs. If you need to use scroll bars, they should be inside one of the views, probably "the" content view.
I am trying to achieve a layout similar to the second layout of this image I would like to have a background image take about 40% of the screen and then a view below it with my content but I would like my logo to float in between the two. Similar to how the "G" sits between the image and the content. I tried having two views and nesting the logo inside the first view and tried to position absolute but I am having trouble centering it horizontally, making it 10% of the width and having a perfect circle, because it seems you cant use flex attributes on an absolute positioned element.
Here is my attempt
https://snack.expo.io/HkV0wEptE
To centered the logo, you can just put it in a View that have screen width and sets the alignItems to 'center'. Below are a simple sample of how to do this layout:
render() {
return (
<View style={myStyle.container}>
<View style={myStyle.topBanner} />
<View style={myStyle.contentArea}>
<Text style={myStyle.contentTitle}>HERE LIES CONTENT</Text>
</View>
<View style={myStyle.midLogoRow}>
<Image style={myStyle.midLogo} source={require('../../images/profile_achive.png')} />
</View>
</View>
);
}
and the stylesheet is as below:
const sWidth = Dimensions.get('window').width;
const sHeight = Dimensions.get('window').height;
const myStyle = StyleSheet.create({
container: {
flex: 1,
width: sWidth,
backgroundColor: '#fff',
},
topBanner: {
width: sWidth,
height: sHeight * 0.4,
backgroundColor: '#c5c5c5',
},
midLogoRow: {
position: 'absolute',
top: sHeight * 0.3,
left: 0,
width: sWidth,
alignItems: 'center',
},
midLogo: {
width: sHeight * 0.18,
height: sHeight * 0.18,
},
contentArea: {
marginTop: sHeight * 0.09,
alignItems: 'center'
},
contentTitle: {
fontSize: 18,
color: '#333',
fontWeight: 'bold',
},
});
as you can see; the row where the your logo's in (in my case it's profile_achieve.png) is placed at the lowest part so that it will be render on top of everything else. The top margin for the contentArea is set at 0.09 of screen height, which is logo height divide by 2.
I want to create a rounded image with a border. If I add borderColor: 'green', borderWidth:1, border is visible only in top left part of the rounded image.
<TouchableHighlight
style={[styles.profileImgContainer, { borderColor: 'green', borderWidth:1 }]}
>
<Image source={{ uri:"https://www.t-nation.com/system/publishing/articles/10005529/original/6-Reasons-You-Should-Never-Open-a-Gym.png" }} style={styles.profileImg} />
</TouchableHighlight>
export default styles = StyleSheet.create({
profileImgContainer: {
marginLeft: 8,
height: 80,
width: 80,
borderRadius: 40,
},
profileImg: {
height: 80,
width: 80,
borderRadius: 40,
},
});
overflow: 'hidden' for images container solves this issue.
Use the following styling, it's work for me.
image: {
width: 150,
height: 150,
borderRadius: 150 / 2,
overflow: "hidden",
borderWidth: 3,
borderColor: "red"
}
Worth to mention for Android...
I had to specifically set resizeMode="cover" for the borderRadius to take effect.
<Image
style={styles.image}
source={source}
resizeMode={"cover"} // <- needs to be "cover" for borderRadius to take effect on Android
/>
const styles = StyleSheet.create({
image: {
width: 150,
height: 150,
borderColor: 'red,
borderWidth: 2,
borderRadius: 75
},
});
Border width adds up to the size of the component that you added to. This makes your image bigger than the size of your container component. To solve this issue you can add the border width to the component sizes.
Example
const styles = StyleSheet.create({
profileImgContainer: {
marginLeft: 8,
height: 82,
width: 82,
borderRadius: 40,
borderWidth: 1
},
profileImg: {
height: 80,
width: 80,
borderRadius: 40,
},
});
If you want to show the image with rounded corner and with resizeMode={'contain'} to show the full image then wrap the image inside a view and then give border radius to the view. it will work
<View style={styles.carImageHolder}>
<Image
source={{
uri: each?.usercar_details?.car_model?.sized_photo,
}}
resizeMode={'contain'}
style={styles.carImage}
/>
</View>
and the style part
carImage: {
width: '100%',
aspectRatio: 1 / 1,
},
carImageHolder: {
width: '28.3%',
aspectRatio: 1 / 1,
backgroundColor: '#d8d8d8',
borderRadius: 25,
overflow: 'hidden',
},
The answers given here, are nice, but, from my experience, it's better to use percentages of your available screen height, as the width and height dimensions of image. This will help a lot with responsiveness. Do it like this
import RN from 'react-native';
const SCREEN_HEIGHT = RN.Dimensions.get('window').height;
Then apply the following as the dimensions styling, to get a nice, responsive rounded image.
style={[
//... your other previous styles
{
resizeMode: 'cover',
width: SCREEN_HEIGHT * 0.15,
height: SCREEN_HEIGHT * 0.15,
borderRadius: (SCREEN_HEIGHT * 0.15)/2,
}
]}
The (*0.15 i.e 15% of screen height) is just my choice of sample dimensions, you can use higher or lower, depending on how big you want your image to be.
Hi am new to titanium and cant get how to create a fluid design with its TSS. How to place three views, one as header(20%), two as content holder(60%) and three as footer(20%) with all width full(Ti.UI.FILL). My code is,
index.xml
<Alloy>
<Window class="container">
<Require src="home" id="home"></Require>
</Window>
</Alloy>
home.xml
<Alloy>
<View id="header"></View>
<View id="content"></View>
<View id="footer"></View>
</Alloy>
home.tss
"#home": {
layout: 'vertical',
width: Ti.UI.FILL,
height: Ti.UI.FILL,
backgroundColor: '#000'
},
'#header':{
layout: 'horizontal',
height: '20%',
width: Ti.UI.FILL,
backgroundColor: '#fff'
},
'#content': {
layout: 'vertical',
height: '60%',
width: Ti.UI.FILL,
backgroundColor: '#ccc'
},
'#footer': {
layout: 'horizontal',
height: '20%',
width: Ti.UI.FILL,
backgroundColor: '#fff'
}
What am trying is to place a back button(left), title(middle) and a refresh button(right) as horizontal layout in header view and app content in content view and in footer view with some choice with scrolling(ie, we can scroll using slide event by placing options on it). If I run this code views are eventually divided as like this and 60% not affected on the content view. I have asked in appcelerator forum and dint get replied yet. Hope this helps.
Your object with the id of 'home' isn't actually a view, it's just a reference to the home class and so you can't attribute styles to it like that.
I would have relaid home.xml out like this:
<Alloy>
<View id="homeHolder">
<View id="header"></View>
<View id="content"></View>
<View id="footer"></View>
</View>
</Alloy>
and then this would have work as you would have expected
"#homeHolder": {
layout: 'vertical',
width: Ti.UI.FILL,
height: Ti.UI.FILL,
backgroundColor: '#000'
}
Put this:
"#home": {
layout: 'vertical',
width: Ti.UI.FILL,
height: Ti.UI.FILL,
backgroundColor: '#000'
},
Inside index.tss, there is no element with id home inside home.xml, but there is one inside index.xml.
home.xml
<Alloy>
<View id="home">
<View id="header" visible="true">
<Label>header</Label>
</View>
<ScrollView id="content" visible="true">
<Label>content</Label>
</ScrollView>
<View id="footer" visible="true">
<Label>footer</Label>
</View>
</View>
</Alloy>
home.tss
"#home": {
layout: 'vertical',
width: Ti.UI.FILL,
height: Ti.UI.FILL,
backgroundColor: '#000'
},
'#header':{
layout: 'horizontal',
height: '20%',
width: Ti.UI.FILL,
backgroundColor: 'white',
},
'#content': {
layout: 'vertical',
height: '60%',
width: Ti.UI.FILL,
backgroundColor: '#ccc'
},
'#footer': {
layout: 'horizontal',
height: '20%',
width: Ti.UI.FILL,
backgroundColor: 'green',
}
index.xml
<Alloy>
<Window class="container">
<Require src="home" id="home"></Require>
</Window>
</Alloy>
This works. Thanks to Martyn.