onTouchstart event not fire in Listview(Alloy) only Android - android

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;
});

Related

Problem with Picker in android (text of the selected item)

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}/>
);
})}

FlatList scroll after adding new element

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

NativeScript: Disable all controls while ActivityIndicator is shown

Lets say there is a login page with username\password TextFields and login Button. When the button is pressed a request is set to a server and ActivityIndicator is shown.
Currently I put StackLayout on top of all other controls not to give the user a possibility to click on them while processing the request. But in some cases TextField stays focused and the user can type there.
I'm already using a component to wrap all TextFields to show validation errors:
#Component({
selector: "field",
template: "<grid-layout><ng-content></ng-content>...</grid-layout>"
})
export class FieldComponent {
#ContentChild(NgModel) private input: NgModel;
...
}
My question is can I set isEnabled property to false on TextField inside ng-content from FieldComponent having NgModel or in some another way?
If it is impossible what is the best practices in this case to disable inputs when an app is busy?
Here is my solution for NativeScript+Angular:
setControlInteractionState() is recursive.
the TextField cursor is hidden (using native android API).
XML:
<GridLayout #mainGrid rows="*" columns="*">
<!-- Main page content here... -->
<GridLayout *ngIf="isBusy" rows="*" columns="*">
<GridLayout rows="*" columns="*" style="background-color: black; opacity: 0.35">
</GridLayout>
<ActivityIndicator width="60" height="60" busy="true">
</ActivityIndicator>
</GridLayout>
</GridLayout>
or
<GridLayout #mainGrid rows="*" columns="*">
<!-- Main page content here... -->
</GridLayout>
<GridLayout *ngIf="isBusy" rows="*" columns="*">
<GridLayout rows="*" columns="*" style="background-color: black; opacity: 0.35">
</GridLayout>
<ActivityIndicator width="60" height="60" busy="true">
</ActivityIndicator>
</GridLayout>
TypeScript:
import { Component, ViewChild, ElementRef } from "#angular/core";
import { View } from "ui/core/view";
import { LayoutBase } from "ui/layouts/layout-base";
import { isAndroid, isIOS } from "platform";
#Component({
templateUrl: "./SignIn.html"
})
export class SignInComponent {
#ViewChild("mainGrid")
MainGrid: ElementRef;
isBusy: boolean = false;
submit() : void {
try {
this.isBusy = true;
setControlInteractionState(<View>this.MainGrid.nativeElement, false);
//sign-in here...
}
finally {
this.isBusy = false;
setControlInteractionState(<View>this.MainGrid.nativeElement, true);
}
}
setControlInteractionState(view: View, isEnabled: boolean) : void {
view.isUserInteractionEnabled = isEnabled;
if (isAndroid) {
if (view.android instanceof android.widget.EditText) {
let control = <android.widget.EditText>view.android;
control.setCursorVisible(isEnabled);
}
}
if (view instanceof LayoutBase) {
let layoutBase = <LayoutBase>view;
for (let i = 0, length = layoutBase.getChildrenCount(); i < length; i++) {
let child = layoutBase.getChildAt(i);
setControlInteractionState(child, isEnabled);
}
}
}
}
NS 2.5.0
There are a couple way you can do this;
You can use a ngIf or binding on isEnabled to disable it based on a data bound value.
You can create a simple routine that you call (my preferred method).
require("nativescript-dom");
function screenEnabled(isEnabled) {
runAgainstTagNames('TextEdit', function(e) { e.isEnabled = isEnabled; });
runAgainstTagNames('Button', function(e) { e.isEnabled = isEnabled; });
}
The nativescript-dom plugin has the runAgainst*, or getElementBy* wrappers to talk to the native layer like you were talking to a html dom.
Full disclosure, I'm the author of nativescript-dom, it is one of the plugins that I use in almost every app/demo I do.
I found an easiest solution in Angular, so i am posting here for any future reference. First in app.component.html file i added a Grid and ScrollView like following:
<GridLayout>
<page-router-outlet></page-router-outlet>
<!-- hack to block UI -->
<ScrollView isUserInteractionEnabled="false" *ngIf="isLoading">
<ActivityIndicator busy="true"></ActivityIndicator>
</ScrollView>
</GridLayout>
Notice the page-router-outlet which is inside the Grid. By default it will be place at row="0". The next thing is ScrollView which has isUserInteractionEnabled set to false.
Now in your app.component.ts file add a a variable called isLoading and toggle it using some kind of events e.g RxJs Observable events
Expanding #KTCO's answer to get the size of the overlay exactly the same as the main grid:
import { Size, View } from "tns-core-modules/ui/core/view";
import { GridLayout } from "tns-core-modules/ui/layouts/grid-layout/grid-layout";
...
...
dialogSize: Size;
mainGrid: GridLayout;
...
submit() {
this.mainGrid = <GridLayout>this.MainGrid.nativeElement;
this.dialogSize = this.mainGrid.getActualSize();
.....
.....
<GridLayout *ngIf="isBusy" rows="auto" columns="auto">
<GridLayout rows="*" columns="*" [width]="dialogSize.width" [height]="dialogSize.height" style="background-color: black; opacity: 0.35">
</GridLayout>
<ActivityIndicator width="50" height="50" busy="true">
</ActivityIndicator>
</GridLayout>
I know this is a little old, but sometimes I just got to do things my way. If you want to accomplish this programmatically:
const excludedView = someViewToBeExcluded;
const enabler = (parentView:View, enable:boolean) => {
parentView.eachChildView(childView => {
if (childView != excludedView) {
enabler(childView, enable);
childView.isEnabled = enable;
}
return true;
});
};
enabler(page, false);
Note: This will not disable/enable the initial parentView (ie. the page in this example)

Unable to change backgroundColor of a label inside a TableViewRow onClick (android) - appcelerator titanium

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"
}

setting .prop() value programatically of select control in j-Query mobile radio button (Data-Native-Menu ="true") not updated in android 4.2.1

What happens when selected index is updated($('#idSelectControl').prop('selectedIndex', self.lastSelected);). Immediately the radio button is not getting refreshed, I need to close the select drop down when I reopen the control, it's showing the updated radio button checked with the current selected index.
Please find the code below.
HTML
<div id="idSelectCustomControl" data-bind="visible : searchVisibleFlag">
<select id="idSelectControl" class="float-left big-select" data-native-menu="true" data-corners="false" data-icon="search" data-iconpos="left" data-mini="true" data-bind="dataOptions: arrayList, optionsText : 'text', optionsValue : 'id'">
</select>
</div>
JS
// fired when user selects on drop down list
$(#idSelectControl).live("change", function (event) {
var selectedItem = $("#idSelectControl option:selected").val();
console.log("merchant subscription" + self.merchant());
self.lastSelected = $('#idSelectControl').prop('selectedIndex');
$('#idSelectControl').prop('selectedIndex', self.lastSelected);
//$("select").selectmenu("refresh");
var myselect = $("#idSelectControl");
myselect[0].selectedIndex =0;
myselect.selectmenu("refresh",true);
$('select').selectmenu('refresh', true);
$("select").selectmenu("close");
//$("#idSelectControl").val(selectedItem ).selectmenu("refresh");
if (selectedItem ) {
self.item((selectedItem);
}
else {
self.item("");
}
});
I have tried below also:
$("input[type='radio']").prop("checked",true).checkboxradio("refresh");
$('input[value='+$(this).find("HomeStatus").text()+']')
.attr('checked',true).checkboxradio('refresh');

Categories

Resources