I am using FlatList component of ReactNative and it is working perfectly. Now i want to scroll it to bottom whenever user enters new element/comment.
<FlatList style={styles.commentList}
data={commentList}
keyExtractor={(item, index) => index}
renderItem={this.renderRow.bind(this)}
/>
Now whenever user enters new comment, commentList will be updated and FlatList also gets refresh, but i want to be scroll to the bottom so that user can read latest comment posted.
Check this out:
Its not my solution, but i got working using this method.
https://exp.host/#xavieramoros/snack-SyN4FJikz
source code:
https://github.com/xavieramoros/flatlist-initialScrollIndexIssue/blob/master/App.js
Expo 22 - RN 0.49
A great thanks to https://expo.io/#xavieramoros
Edited: If you just want to scroll to bottom then scrollToEnd (https://facebook.github.io/react-native/docs/flatlist.html#scrolltoend) is available in new RN.
use it like
<FlatList
ref={ (ref) => { this.flatList = ref; }}
data={this.data}
renderItem={ this.renderItem }
keyExtractor={ this.keyExtractor}
onScroll={ this.scrollToEnd}
/>
......
and in your method
scrollToEnd = () => {
const wait = new Promise((resolve) => setTimeout(resolve, 0));
wait.then( () => {
this.flatList.scrollToEnd({ animated: true });
});
}
Try FlatList with inverted prop as true. (might as well reverse the data array)
Since flatlist is inverted, the new data is added on the first position, and because of this update flatlist automatically scrolls to first position, which in your case is the bottom location
Related
I am having a problem with the picker (only in android). In the iPhone, I don't have any problem.
When I select an item, in android doesn’t update the text in the Combobox (but the object is selected ok).
I attach the code:
<View style={[Styles.PickerSelect, { width: “70%” }]}>
<Picker
headerBackButtonText="Atras"
iosHeader="Seleccionar"
selectedValue={this.state.articulo}
placeholder={this.state.articulo}
onValueChange={this.getDatosLineas.bind(this)>
{this.state.articulos && this.state.articulos.map((item, i) => {
return (
<Picker.Item
key={i}
value={i}
label={item.nom_articulo}/>
);
})}
</Picker>
</View>
I attach the photo of the example:
In 1- When I enter to the section, I have the picker with this text and value.
In 2- I select the picker, and I select another item (for example “ORUJO DE UVAS BLANCAS”)
In 3- In android, the text isn’t be updated. But the object is the selected…
I repeat, in ios, I don't have this problem.
Expo SDK: 36.0.0
Thanks!
You need to set selected value in articulo variable with setState() method in onValueChange() callback inside picker tag.
<View style={[Styles.PickerSelect, { width: “70%” }]}>
<Picker
headerBackButtonText="Atras"
iosHeader="Seleccionar"
selectedValue={this.state.articulo}
placeholder={this.state.articulo}
onValueChange={(itemValue, itemPosition) =>
this.setState({articulo: itemValue, choosenIndex: itemPosition})}>
{this.state.articulos && this.state.articulos.map((item, i) => {
return (
<Picker.Item
key={i}
value={i}
label={item.nom_articulo}/>
);
})}
I have a case where I have a bottom tab navigator in my app. The first bottom tab is a stack navigator consisting of the main home screen and a siteDetail Screen . The user can navigate from the main home screen to the SiteDetail screen. Likewise, there are other elements in the bottom tab as well.
Whenever the user presses backbutton when he is in the SiteDetail screen, he is directed back to the main home page(that's obvious). But before that I need to update the reducer. So I implemented a BackHandler listener as:
constructor(props){
super(props);
//.........
this.handleBackButtonClick = this.handleBackButtonClick.bind(this);
}
componentDidMount() {
this.fetchSiteDetail();
BackHandler.addEventListener('hardwareBackPress', this.handleBackButtonClick);
}
handleBackButtonClick() {
if (this.props.isRestroDetailPage) {// doesn't work of course
this.props.unselectSite();
}
}
componentWillUnmount() {
BackHandler.removeEventListener('hardwareBackPress');
}
The backhandler words well as intended. But, it also works when I traverse to other bottom tabs and press back button. I easily customized the soft back button but for the hard one, the listener listens to presses from all over the bottom tabs.
I do understand this behaviour, but how can I make the program to apply the this.props.unselectSite() only when I press the backbutton when I am at SiteDetail screen.
I am using react navigation v5, if that is in anyway helpful.
You can use a conditional before execute the action, the react-native have a props to verify if the screen is select.
A example:
handleBackButtonPressAndroid = () => {
let { navigation } = this.props;
if (navigation.isFocused()) {
//execute what you want.
};
}
In your case:
handleBackButtonClick() {
let { navigation } = this.props;
if(navigation.isFocused()) {
if (this.props.isRestroDetailPage) {// doesn't work of course
this.props.unselectSite();
}
}
}
Docs: https://reactnavigation.org/docs/navigation-prop/
React-Navigation just added a new method that should help you out here, beforeRemove.
Something like this:
React.useEffect(
() =>
navigation.addListener('beforeRemove', (e) => {
if (!props.isRestroDetailPage) {
// If we don't have unsaved changes, then we don't need to do anything
return;
}
// Prevent default behavior of leaving the screen
e.preventDefault();
this.props.unselectSite();
navigation.dispatch(e.data.action)
}),
[navigation, props.isRestroDetailPage]
);
Im working on my mobile app, and trying to code it with nativescript,
but Im having a problem I want to animate view of item, in listView ...
Here is my code so far:
let page = args.object;
const radList = page.getViewById('myList');
const item = radList.getItemAtIndex(0);
const itemView = radList.getViewForItem(item);
But my itemView is always undefined, also I tried with getChildAt() method but it doesnt work...
I dont want to use, itemDeleteAnimation because I want to use my own animation
I think you are hitting a timing issue, which can be resolved by using setTimeout. Another possibility (if applicable) is to use the itemLoading event to get a reference to the view via ListViewEventData
Here is an example of both:
TypeScript
export function onRadLoaded(args) {
const radList = <RadListView>args.object;
setTimeout(() => {
const item = radList.getItemAtIndex(0);
const view = radList.getViewForItem(item);
console.log(view);
}, 300);
}
export function onItemLoading(args: ListViewEventData) {
console.log("args.view: ", args.view);
console.log("args.data: ", args.data);
console.log("args.index: ", args.index);
}
view xml(List view template)
<Alloy>
<ItemTemplate id="test">
<View onTouchstart="touch" width="Ti.UI.SIZE" height="Ti.UI.SIZE">
<Label>test</Label>
</View>
</ItemTemplate>
</Alloy>
controller js
function touch(e){
Ti.API.debug('touch!!');
};
not fire only android..(iOS is good)
and under don't use ListView code, no problem android(and iOS).
<Alloy>
<Window class="container">
<View onTouchstart="touch" width="Ti.UI.SIZE" height="Ti.UI.SIZE">
<Label>test</Label>
</View>
</Window>
</Alloy>
I do not know anyone solution?
There are no 'touchstart' method for ListViews, you could use 'dragstart' and 'scrollstart' as alternative.
Check out the available events:
http://docs.appcelerator.com/platform/latest/#!/api/Titanium.UI.ListView
I've tried once to add the 'change' event to a TextField inside the ItemTemplace, but I've to create an workaround:
Change event on TextField inside ListView Template
If it's not possible, you have to use the 'itemclick' and get the selected row:
$.list.addEventListener('itemclick',function(list) {
var row = $.list.sections[0].getItemAt(list.itemIndex);
if(row && row.title) {
row.title.text = 'hello world';
//when you click the View with 'cancel' bindId
if(list.bindId == 'cancel') yourCancelAction();
//when you click the View with 'save' bindId
//(if you need to pass the row index to the function,
//in order to update something on the clicked row with a external function)
if(list.bindId == 'save') yourSaveAction(list.itemIndex);
$.list.sections[0].updateItemAt(list.itemIndex,row);
}
list = row = null;
});
I am trying to update the background color of a Label inside a TableViewRow. I am using a View/Controller for the rows, creating them in code and appending them as an array to the TableView. Using onClick of the TableViewRow and Label.setBackgroundColor() inside the TableViewRow controller.
ExampleRow.xml
<TableViewRow id="exampleRow" class="exampleClass" onClick="exampleClick">
<Label id="exampleLabel" text="test" />
</TableViewRow>
ExampleRow.js
var test = 1;
function exampleClick(e) {
if(test == 1) {
$.exampleLabel.setBackgroundColor('#0f0');
test = 0;
} else {
$.exampleLabel.setBackgroundColor('#fff');
test = 1;
}
}
ExamplePage.xml
<TableView id="exampleTable" />
ExamplePage.js
var tableViewRows = [];
for(var i = 0; i < 5; i++) {
tableViewRows.push(
Alloy.createController('exampleRow', {}).getView()
);
}
$.exampleTable.setData(tableViewRows);
The problem is this does not work on the first page as soon as the app loads. If I scroll the TableViewRows outside of the screen and back in, the background color change works. If an alert box is popped up the background change works. But after first app load, the background color will not change. It also works if we use appendRow for each row, but this is substantially slower.
appendRow fix example:
for(var i = 0; i < 5; i++) {
$.exampleTable.appendRow(
Alloy.createController('exampleRow', {}).getView()
);
}
appending the rows individually sometimes fixes the bug (not every row), but for our list takes 5-8 seconds to display the table, rather than <1second using setData*
Example of the real app not working:
Example of the real app working:
This occurs after having an alert box displayed or scrolling the rows out and back in to the screen, or using appendRow for each row
Methods I have attempted to fix (did not fix):
using animations
removing the label then recreating and adding a new label in code
removing class from the TableViewRow
I am using Titanium SDK 5.0.2.GA and compiling on android 5.1.1.
Try to use click event of tableView instead of tableViewRow :
<TableView onClick="yourTableViewClickEvent"></TableView>
and then define what logic will be executed inside this function callback :
function yourTableViewClickEvent(e){
// access selected row
var currentSelectedRow = e.row;
// current selected Label we assume here that the row contain a label as first child (exactly what you have in your row definition
var currentLabel = currentSelectedRow.children[0]
// change label background color
currentSelectedRow.backgroundColor = "#0f0"
// You can even (i know it is no good to do that :)) test if the color is white or #0f0 like so
if(currentSelectedRow.backgroundColor == "#fff")
currentSelectedRow.backgroundColor = "#0f0"
else
currentSelectedRow.backgroundColor = "#fff"
}