问题描述
我在这里有一种"抓住22"的情况.
我正在使用Appcelerator TitaTium SDK 5.1.2.在Android 5.1.x中具有非常小的屏幕尺寸,我无法找到解决方案来使用本机选择器正确选择日期和时间.我需要添加一个<ScrollView>以允许用户移动内容以使选择器完全可见.但是,在Android 5.1.x上执行此操作时,用户无法在日期选择器中滚动到上个月.将其更改为<View>控制使得日期选择器按预期行为.但是,如果选择器的一部分位于可见区域之外,用户没有机会从那里选择值...
我创建了一个简单的例子来说明这个.评论<ScrollView>而不是<View>,具有相同的ID,以查看差异:
视图:
<Alloy> <Window class="container"> <View id="form" onClick="clickHandler"> <!-- <ScrollView id="form" onClick="clickHandler"> --> <View id="formRow"> <Label id="title">Picker demo</Label> </View> <View id="formRow"> <Label id="label">Date</Label> <TextField id="startDate" bubbleParent="true" editable="false"></TextField> </View> <View id="formRow"> <Label id="label">Time</Label> <TextField id="startTime" bubbleParent="true" editable="false"></TextField> </View> <!-- </ScrollView> --> </View> </Window> </Alloy>
style:
".container": { top: 20, backgroundColor:"#fa0", orientationModes: [Ti.UI.PORTRAIT] } "Label": { width: Ti.UI.SIZE, height: Ti.UI.SIZE, backgroundColor: 'transparent', left:10, color: "#000" } "#title": { top:15, font: { fontSize: '25dp', fontStyle: 'bold' } } "#label": { top:0, font: { fontSize: '18dp', fontStyle: 'bold' } } "TextField": { font: { fontSize: '18dp', fontStyle: 'normal' }, backgroundColor:'orange' } "#formRow":{ top:7, height:Ti.UI.SIZE, width:Ti.UI.FILL } "#startDate":{ top:0, width:150, right:10, } "#startTime":{ top:0, width:70, right:10 } "#form":{ showVerticalScrollIndicator:"true", layout:"vertical" }
控制器:
var Moment = require('alloy/moment'); function clickHandler(e){ if(e && e.source){ console.log("clickHandler. id="+e.source.id); if(e.source.id === 'startDate'){ openDatePicker(e); } else if(e.source.id === 'startTime'){ openTimePicker(e); } } } // Date/time utils: function getAsDate(date) { // Return as Date object var dt = null; if(typeof date === 'number') { dt = new Date(date); } else if(date instanceof Date) { dt = date; } return dt; }; function getDMY(date) { var dt = getAsDate(date); if(dt) { return Moment(dt).format('DD-MM-YYYY'); } return null; } function getHMM(date) { // Returns format: H:mm var dt = getAsDate(date); if(dt) { return Moment(dt).format('H:mm'); } return null; } function fromDMY(dt){ var date = Moment(dt, "DD-MM-YYYY"); if(date){ date = new Date(date); } return date; } function fromHMM(time){ var datetime = Moment(time, "H:mm"); if(datetime) { return new Date(datetime); } return null; } function openDatePicker(){ // Inner helper class to clean up and remove picker items function cleanup(){ console.log("openDatePicker.cleanup..."); pickerOpen = null; $.startDate.value = getDMY(picker.value); $.formRow.remove(picker); $.startDate.bubbleParent = true; $.form.removeEventListener('click',cleanup); } var v = $.startDate.value; if(v && fromDMY(v)) { v = fromDMY(v); console.debug("startDate.value=" + $.startDate.value + " --> v=" + v + " - type: " + typeof v); }else{ v = new Date(); } var picker = Ti.UI.createPicker({ type:Ti.UI.PICKER_TYPE_DATE, maxDate:new Date(), top:35, value:v }); $.formRow.add(picker); $.startDate.bubbleParent = false; $.form.addEventListener('click',cleanup); } function openTimePicker(){ // Inner helper class to clean up and remove picker items function cleanup(){ console.log("openTimePicker.cleanup..."); pickerOpen = null; $.startTime.value = getHMM(picker.value); $.formRow.remove(picker); $.startTime.bubbleParent = true; $.form.removeEventListener('click',cleanup); } var v = $.startTime.value; if(v && fromHMM(v)) { v = fromHMM(v); console.debug("startTime.value=" + $.startTime.value + " --> v=" + v + " - type: " + typeof v); }else{ v = new Date(); } var picker = Ti.UI.createPicker({ type:Ti.UI.PICKER_TYPE_TIME, format24:true, minuteInterval:5, top:35, value:v }); $.formRow.add(picker); $.startTime.bubbleParent = false; $.form.addEventListener('click',cleanup); } $.index.open();
抱歉冗长的代码(无法真正使它更短) - 但它是一个工作示例.
在其他版本的Android中,<ScrollView>不优先于本机日期选择器 - 因此允许用户轻松重新定位整个内容以查看选择器,然后选择日期.
我已经使用480 x 800(240 dpi)的屏幕尺寸验证了在Genymotion VM运行API 22中的上述应用程序.它表明问题吻合得很好: - )
如何为android 5.1.x执行此操作?
提前感谢!
/john
推荐答案
嵌套可滚动的ui组件是一个问题的配方.在这种情况下,您可能希望使用对话框而不是.
其他推荐答案
您是否尝试在滚动视图上设置canCancelEvents: false?在其默认情况下,滚动视图即使是孩子的所有事件也会反应.
问题描述
I have a kind of "catch 22" situation here.
I am using Appcelerator Titatium SDK 5.1.2. On Android 5.1.x with a very small screen size I cannot find a solution to correctly select date and time using the native pickers. I need to add a <ScrollView> to allow the user to move the contents to make the picker entirely visible. However, when doing this on Android 5.1.x the user cannot scroll back to previous months in the date picker.... Changing it to a <View> control makes the date picker behave as expected. However, if part of the picker is outside of the visible area the user has no chance to select values from there...
I have created a simple example to illustrate this. Comment in <ScrollView> instead of <View> with same id to see difference:
View:
<Alloy> <Window class="container"> <View id="form" onClick="clickHandler"> <!-- <ScrollView id="form" onClick="clickHandler"> --> <View id="formRow"> <Label id="title">Picker demo</Label> </View> <View id="formRow"> <Label id="label">Date</Label> <TextField id="startDate" bubbleParent="true" editable="false"></TextField> </View> <View id="formRow"> <Label id="label">Time</Label> <TextField id="startTime" bubbleParent="true" editable="false"></TextField> </View> <!-- </ScrollView> --> </View> </Window> </Alloy>
Style:
".container": { top: 20, backgroundColor:"#fa0", orientationModes: [Ti.UI.PORTRAIT] } "Label": { width: Ti.UI.SIZE, height: Ti.UI.SIZE, backgroundColor: 'transparent', left:10, color: "#000" } "#title": { top:15, font: { fontSize: '25dp', fontStyle: 'bold' } } "#label": { top:0, font: { fontSize: '18dp', fontStyle: 'bold' } } "TextField": { font: { fontSize: '18dp', fontStyle: 'normal' }, backgroundColor:'orange' } "#formRow":{ top:7, height:Ti.UI.SIZE, width:Ti.UI.FILL } "#startDate":{ top:0, width:150, right:10, } "#startTime":{ top:0, width:70, right:10 } "#form":{ showVerticalScrollIndicator:"true", layout:"vertical" }
Controller:
var Moment = require('alloy/moment'); function clickHandler(e){ if(e && e.source){ console.log("clickHandler. id="+e.source.id); if(e.source.id === 'startDate'){ openDatePicker(e); } else if(e.source.id === 'startTime'){ openTimePicker(e); } } } // Date/time utils: function getAsDate(date) { // Return as Date object var dt = null; if(typeof date === 'number') { dt = new Date(date); } else if(date instanceof Date) { dt = date; } return dt; }; function getDMY(date) { var dt = getAsDate(date); if(dt) { return Moment(dt).format('DD-MM-YYYY'); } return null; } function getHMM(date) { // Returns format: H:mm var dt = getAsDate(date); if(dt) { return Moment(dt).format('H:mm'); } return null; } function fromDMY(dt){ var date = Moment(dt, "DD-MM-YYYY"); if(date){ date = new Date(date); } return date; } function fromHMM(time){ var datetime = Moment(time, "H:mm"); if(datetime) { return new Date(datetime); } return null; } function openDatePicker(){ // Inner helper class to clean up and remove picker items function cleanup(){ console.log("openDatePicker.cleanup..."); pickerOpen = null; $.startDate.value = getDMY(picker.value); $.formRow.remove(picker); $.startDate.bubbleParent = true; $.form.removeEventListener('click',cleanup); } var v = $.startDate.value; if(v && fromDMY(v)) { v = fromDMY(v); console.debug("startDate.value=" + $.startDate.value + " --> v=" + v + " - type: " + typeof v); }else{ v = new Date(); } var picker = Ti.UI.createPicker({ type:Ti.UI.PICKER_TYPE_DATE, maxDate:new Date(), top:35, value:v }); $.formRow.add(picker); $.startDate.bubbleParent = false; $.form.addEventListener('click',cleanup); } function openTimePicker(){ // Inner helper class to clean up and remove picker items function cleanup(){ console.log("openTimePicker.cleanup..."); pickerOpen = null; $.startTime.value = getHMM(picker.value); $.formRow.remove(picker); $.startTime.bubbleParent = true; $.form.removeEventListener('click',cleanup); } var v = $.startTime.value; if(v && fromHMM(v)) { v = fromHMM(v); console.debug("startTime.value=" + $.startTime.value + " --> v=" + v + " - type: " + typeof v); }else{ v = new Date(); } var picker = Ti.UI.createPicker({ type:Ti.UI.PICKER_TYPE_TIME, format24:true, minuteInterval:5, top:35, value:v }); $.formRow.add(picker); $.startTime.bubbleParent = false; $.form.addEventListener('click',cleanup); } $.index.open();
Sorry for the lengthy code (couldn't really make it shorter) - but it is a working example.
On other versions of Android the <ScrollView> does not take precedence over the native date picker - and thus allows the user to easily reposition the entire contents to see the picker and then select the dates.
I have verified the above app in a Genymotion VM running API 22 using a screen size of 480 x 800 (240 dpi). It illustrates the problem quite well :-)
Any ideas how to do this for Android 5.1.x?
Thanks in advance!
/John
推荐答案
Nested scrollable UI components is a recipe for problems. In this case you might want to use the dialog instead.
其他推荐答案
Have you tried setting canCancelEvents: false on the ScrollView? At its default of true, the ScrollView reacts to all events even those of its children.