在Android 5.1.x上使用本机日期/时间选择器时的布局挑战

时间:2016-04-08 15:55:42

标签: android datepicker scrollview timepicker appcelerator-titanium

我有一种"捕获22"这里的情况。

我正在使用Appcelerator Titatium SDK 5.1.2。在Android 5.1.x上,屏幕尺寸非常小,我无法找到使用本机选择器正确选择日期和时间的解决方案。我需要添加<ScrollView>以允许用户移动内容以使选择器完全可见。但是,在Android 5.1.x上执行此操作时,用户无法滚动回日期选择器中的前几个月....将其更改为<View>控件会使日期选择器按预期运行。但是,如果选择器的一部分位于可见区域之外,则用户无法从那里选择值...

我创建了一个简单的例子来说明这一点。使用相同的ID在<ScrollView>而不是<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>

样式:

".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)的运行API 22的Genymotion VM验证了上述应用程序。它很好地说明了问题: - )

有关如何为Android 5.1.x执行此操作的任何想法吗?

提前致谢!

/约翰

2 个答案:

答案 0 :(得分:0)

您是否尝试在ScrollView上设置canCancelEvents: false?默认情况下,ScrollView会对所有事件做出反应,甚至是其子事件。

答案 1 :(得分:0)

嵌套的可滚​​动UI组件是一个问题的处方。在这种情况下,您可能希望改为使用dialog