【问题标题】:Is there a 'native' cross platform calendar GUI view example available for Titanium?是否有适用于 Titanium 的“本机”跨平台日历 GUI 视图示例?
【发布时间】:2026-01-04 13:55:02
【问题描述】:

像往常一样,Appcelerator 的开发者网站的问答部分对这个问题没有太大帮助(除非我失明了)。似乎这个问题在很大程度上被问到但从未得到回答。

是否有可以同时部署到 iOS Android 的日历视图(GUI - 例如日、周和月视图)的示例?集成到内置日历(或事件)中不是必须的(现在不需要,但将来可能需要)。

我已经看到 stelfordsmontgomerie's 用于 iOS 的模块和 pec1985's 网络视图之一,但是,我正在寻找一个会导致本机(取消 pec1985 的)GUI 对象的模块,以便残疾辅助技术已启用。

【问题讨论】:

    标签: user-interface mobile calendar cross-platform titanium


    【解决方案1】:

    为了在我的 Titanium 应用程序中显示月视图/日历视图,我在 Google 上进行了很多操作,但无法找到适用于 iPhone 和 Android(几乎所有屏幕)两者的功能。

    之后我尝试自己实现它并得到了很好的实现。

    为此,创建支持 Android 和 iPhone 的项目。 打开 app.js 并将以下代码替换为现有代码,然后按 Command + Shift + F 格式化代码。

    // Taking Screen Width
    var screenWidth = 322;
    var needToChangeSize = false;
    
    var screenWidthActual = Ti.Platform.displayCaps.platformWidth;
    
    if (Ti.Platform.osname === 'android') {
    if (screenWidthActual >= 641) {
    screenWidth = screenWidthActual;
    needToChangeSize = true;
    }
    }
    
    // Main Window of the Month View.
    var win = Ti.UI.createWindow({
    backgroundColor : '#FF000000',
    navBarHidden : true
    });
    
    // Button at the buttom side
    var backButton = Ti.UI.createButton({
    bottom : '20dp',
    height : '40dp',
    width : '200dp'
    });
    
    // Previous Button - Tool Bar
    var prevMonth = Ti.UI.createButton({
    left : '15dp',
    width : 'auto',
    height : 'auto',
    title : '<'
    });
    
    // Next Button - Tool Bar
    var nextMonth = Ti.UI.createButton({
    right : '15dp',
    width : 'auto',
    height : 'auto',
    title : '>'
    });
    
    // Month Title - Tool Bar
    var monthTitle = Ti.UI.createLabel({
    width : '200dp',
    height : '24dp',
    textAlign : 'center',
    color : '#3a4756',
    font : {
    fontSize : 20,
    fontWeight : 'bold'
    }
    });
    
    // Tool Bar
    var toolBar = Ti.UI.createView({
    top : '0dp',
    width : '322dp',
    height : '50dp',
    backgroundColor : '#FFFFD800',
    layout : 'vertical'
    });
    
    // Tool Bar - View which contain Title Prev. & Next Button
    var toolBarTitle = Ti.UI.createView({
    top : '3dp',
    width : '322dp',
    height : '24dp'
    });
    
    toolBarTitle.add(prevMonth);
    toolBarTitle.add(monthTitle);
    toolBarTitle.add(nextMonth);
    
    // Tool Bar - Day's
    var toolBarDays = Ti.UI.createView({
    top : '2dp',
    width : '322dp',
    height : '22dp',
    layout : 'horizontal',
    left : '-1dp'
    });
    
    toolBarDays.sunday = Ti.UI.createLabel({
    left : '0dp',
    height : '20dp',
    text : 'Sun',
    width : '46dp',
    textAlign : 'center',
    font : {
    fontSize : 12,
    fontWeight : 'bold'
    },
    color : '#3a4756'
    });
    
    toolBarDays.monday = Ti.UI.createLabel({
    left : '0dp',
    height : '20dp',
    text : 'Mon',
    width : '46dp',
    textAlign : 'center',
    font : {
    fontSize : 12,
    fontWeight : 'bold'
    },
    color : '#3a4756'
    });
    
    toolBarDays.tuesday = Ti.UI.createLabel({
    left : '0dp',
    height : '20dp',
    text : 'Tue',
    width : '46dp',
    textAlign : 'center',
    font : {
    fontSize : 12,
    fontWeight : 'bold'
    },
    color : '#3a4756'
    });
    
    toolBarDays.wednesday = Ti.UI.createLabel({
    left : '0dp',
    height : '20dp',
    text : 'Wed',
    width : '46dp',
    textAlign : 'center',
    font : {
    fontSize : 12,
    fontWeight : 'bold'
    },
    color : '#3a4756'
    });
    
    toolBarDays.thursday = Ti.UI.createLabel({
    left : '0dp',
    height : '20dp',
    text : 'Thu',
    width : '46dp',
    textAlign : 'center',
    font : {
    fontSize : 12,
    fontWeight : 'bold'
    },
    color : '#3a4756'
    });
    
    toolBarDays.friday = Ti.UI.createLabel({
    left : '0dp',
    height : '20dp',
    text : 'Fri',
    width : '46dp',
    textAlign : 'center',
    font : {
    fontSize : 12,
    fontWeight : 'bold'
    },
    color : '#3a4756'
    });
    
    toolBarDays.saturday = Ti.UI.createLabel({
    left : '0dp',
    height : '20dp',
    text : 'Sat',
    width : '46dp',
    textAlign : 'center',
    font : {
    fontSize : 12,
    fontWeight : 'bold'
    },
    color : '#3a4756'
    });
    
    toolBarDays.add(toolBarDays.sunday);
    toolBarDays.add(toolBarDays.monday);
    toolBarDays.add(toolBarDays.tuesday);
    toolBarDays.add(toolBarDays.wednesday);
    toolBarDays.add(toolBarDays.thursday);
    toolBarDays.add(toolBarDays.friday);
    toolBarDays.add(toolBarDays.saturday);
    
    // Adding Tool Bar Title View & Tool Bar Days View
    toolBar.add(toolBarTitle);
    toolBar.add(toolBarDays);
    
    // Function which create day view template
    dayView = function(e) {
    var label = Ti.UI.createLabel({
    current : e.current,
    width : '46dp',
    height : '44dp',
    backgroundColor : '#FFDCDCDF',
    text : e.day,
    textAlign : 'center',
    color : e.color,
    font : {
    fontSize : 20,
    fontWeight : 'bold'
    }
    });
    return label;
    };
    
    monthName = function(e) {
    switch(e) {
    case 0:
    e = 'January';
    break;
    case 1:
    e = 'February';
    break;
    case 2:
    e = 'March';
    break;
    case 3:
    e = 'April';
    break;
    case 4:
    e = 'May';
    break;
    case 5:
    e = 'June';
    break;
    case 6:
    e = 'July';
    break;
    case 7:
    e = 'August';
    break;
    case 8:
    e = 'September';
    break;
    case 9:
    e = 'October';
    break;
    case 10:
    e = 'November';
    break;
    case 11:
    e = 'December';
    break;
    };
    return e;
    };
    
    // Calendar Main Function
    var calView = function(a, b, c) {
    var nameOfMonth = monthName(b);
    
    //create main calendar view
    var mainView = Ti.UI.createView({
    layout : 'horizontal',
    width : '322dp',
    height : 'auto',
    top : '50dp'
    });
    
    //set the time
    var daysInMonth = 32 - new Date(a, b, 32).getDate();
    var dayOfMonth = new Date(a, b, c).getDate();
    var dayOfWeek = new Date(a, b, 1).getDay();
    var daysInLastMonth = 32 - new Date(a, b - 1, 32).getDate();
    var daysInNextMonth = (new Date(a, b, daysInMonth).getDay()) - 6;
    
    //set initial day number
    var dayNumber = daysInLastMonth - dayOfWeek + 1;
    
    //get last month's days
    for ( i = 0; i < dayOfWeek; i++) {
    mainView.add(new dayView({
    day : dayNumber,
    color : '#8e959f',
    current : 'no',
    dayOfMonth : ''
    }));
    dayNumber++;
    };
    
    // reset day number for current month
    dayNumber = 1;
    
    //get this month's days
    for ( i = 0; i < daysInMonth; i++) {
    var newDay = new dayView({
    day : dayNumber,
    color : '#3a4756',
    current : 'yes',
    dayOfMonth : dayOfMonth
    });
    mainView.add(newDay);
    if (newDay.text == dayOfMonth) {
    newDay.color = 'white';
    // newDay.backgroundImage='../libraries/calendar/pngs/monthdaytiletoday_selected.png';
    newDay.backgroundColor = '#FFFFF000';
    var oldDay = newDay;
    }
    dayNumber++;
    };
    dayNumber = 1;
    
    //get remaining month's days
    for ( i = 0; i > daysInNextMonth; i--) {
    mainView.add(new dayView({
    day : dayNumber,
    color : '#8e959f',
    current : 'no',
    dayOfMonth : ''
    }));
    dayNumber++;
    };
    
    // this is the new "clicker" function, although it doesn't have a name anymore, it just is.
    mainView.addEventListener('click', function(e) {
    if (e.source.current == 'yes') {
    
    // reset last day selected
    if (oldDay.text == dayOfMonth) {
    oldDay.color = 'white';
    // oldDay.backgroundImage='../libraries/calendar/pngs/monthdaytiletoday.png';
    oldDay.backgroundColor = '#FFFFF000';
    } else {
    oldDay.color = '#3a4756';
    // oldDay.backgroundImage='../libraries/calendar/pngs/monthdaytile-Decoded.png';
    oldDay.backgroundColor = '#FFDCDCDF'
    }
    oldDay.backgroundPaddingLeft = '0dp';
    oldDay.backgroundPaddingBottom = '0dp';
    
    // set window title with day selected, for testing purposes only
    backButton.title = nameOfMonth + ' ' + e.source.text + ', ' + a;
    
    // set characteristic of the day selected
    if (e.source.text == dayOfMonth) {
    // e.source.backgroundImage='../libraries/calendar/pngs/monthdaytiletoday_selected.png';
    e.source.backgroundColor = '#FFFF00FF';
    } else {
    // e.source.backgroundImage='../libraries/calendar/pngs/monthdaytile_selected.png';
    e.source.backgroundColor = '#FFFF0000';
    }
    e.source.backgroundPaddingLeft = '1dp';
    e.source.backgroundPaddingBottom = '1dp';
    e.source.color = 'white';
    //this day becomes old :(
    oldDay = e.source;
    }
    });
    
    return mainView;
    };
    
    // what's today's date?
    var setDate = new Date();
    a = setDate.getFullYear();
    b = setDate.getMonth();
    c = setDate.getDate();
    
    // add the three calendar views to the window for changing calendars with animation later
    
    var prevCalendarView = null;
    if (b == 0) {
    prevCalendarView = calView(a - 1, 11, c);
    } else {
    prevCalendarView = calView(a, b - 1, c);
    }
    prevCalendarView.left = (screenWidth * -1) + 'dp';
    
    var nextCalendarView = null;
    if (b == 0) {
    nextCalendarView = calView(a + 1, 0, c);
    } else {
    nextCalendarView = calView(a, b + 1, c);
    }
    nextCalendarView.left = screenWidth + 'dp';
    
    var thisCalendarView = calView(a, b, c);
    if (needToChangeSize == false) {
    thisCalendarView.left = '-1dp';
    }
    
    monthTitle.text = monthName(b) + ' ' + a;
    
    backButton.title = monthName(b) + ' ' + c + ', ' + a;
    
    // add everything to the window
    win.add(toolBar);
    win.add(thisCalendarView);
    win.add(nextCalendarView);
    win.add(prevCalendarView);
    win.add(backButton);
    
    // yeah, open the window, why not?
    win.open({
    modal : true
    });
    
    var slideNext = Titanium.UI.createAnimation({
    // left : '-322',
    duration : 500
    });
    
    slideNext.left = (screenWidth * -1);
    
    var slideReset = Titanium.UI.createAnimation({
    // left : '-1',
    duration : 500
    });
    
    if (needToChangeSize == false) {
    slideReset.left = '-1';
    } else {
    slideReset.left = ((screenWidth - 644) / 2);
    }
    
    var slidePrev = Titanium.UI.createAnimation({
    // left : '322',
    duration : 500
    });
    
    slidePrev.left = screenWidth;
    
    // Next Month Click Event
    nextMonth.addEventListener('click', function() {
    if (b == 11) {
    b = 0;
    a++;
    } else {
    b++;
    }
    
    thisCalendarView.animate(slideNext);
    nextCalendarView.animate(slideReset);
    
    setTimeout(function() {
    thisCalendarView.left = (screenWidth * -1) + 'dp';
    if (needToChangeSize == false) {
    nextCalendarView.left = '-1dp';
    } else {
    nextCalendarView.left = ((screenWidth - 644) / 2);
    }
    prevCalendarView = thisCalendarView;
    thisCalendarView = nextCalendarView;
    if (b == 11) {
    nextCalendarView = calView(a + 1, 0, c);
    } else {
    nextCalendarView = calView(a, b + 1, c);
    }
    monthTitle.text = monthName(b) + ' ' + a;
    nextCalendarView.left = screenWidth + 'dp';
    win.add(nextCalendarView);
    }, 500);
    });
    
    // Previous Month Click Event
    prevMonth.addEventListener('click', function() {
    if (b == 0) {
    b = 11;
    a--;
    } else {
    b--;
    }
    thisCalendarView.animate(slidePrev);
    prevCalendarView.animate(slideReset);
    setTimeout(function() {
    thisCalendarView.left = screenWidth + 'dp';
    if (needToChangeSize == false) {
    prevCalendarView.left = '-1dp';
    } else {
    prevCalendarView.left = ((screenWidth - 644) / 2);
    }
    nextCalendarView = thisCalendarView;
    thisCalendarView = prevCalendarView;
    if (b == 0) {
    prevCalendarView = calView(a - 1, 11, c);
    } else {
    prevCalendarView = calView(a, b - 1, c);
    }
    monthTitle.text = monthName(b) + ' ' + a;
    prevCalendarView.left = (screenWidth * -1) + 'dp';
    win.add(prevCalendarView);
    }, 500);
    });
    

    测试环境
    钛工作室 - 2.1.2.201208301612
    钛金 SDK - 2.1.0.GA
    Android - 2.2 模拟器
    iOS 版本 - 5.0

    参考 - http://titaniumexplorers.blogspot.in/2012/09/titanium-calendar-month-view.html

    【讨论】:

    • @AvtarSingh backButton.title = a+'-'+selelectedmonthidentifier + '-' + e.source.text;在这里我需要选择任何日期意味着转到下一个窗口?我该怎么办?
    【解决方案2】:

    没有。

    这两个平台上的日历 UI 实现非常不同和复杂,因此找到一种实现来满足您所有要求的可能性极小。

    您不会失明,您的要求非常具体。

    【讨论】:

    • 我不会认为我的要求非常具体......我只是在一些示例代码之后,有人在 Android/uiOS 上成功部署了日历视图(使用多个视图或其他) .不过,感谢您的回答(我认识您和您在 Titanium 社区中的地位)。
    • 亚伦确实是正确的。我在任何地方都找不到任何例子。我能够使用在 iOS 和 Android 中显示的视图在大约 2-3 小时内完成一个快速的日历概念证明。我将在我的应用程序中使用它作为我的日历的基础。
    • 您能分享一下您的方法吗?您是否完全从头开始滚动自己的日历?还是您在 iOS 上使用了现成的组件,而在 Android 上使用了其他组件?
    • @DanPorts 我完全是自己从头开始编写的。基本上,我创建了一个视图网格,其中包含一些关于应该有多少列/行的简单计算,然后用标签绘制视图。花了一些时间才弄好,但在 Android 和 iOS 上都很好用。
    • 好吧,这就是我的猜测。谢谢。如果您决定出售它或将其作为开源发布,我猜您会对此感兴趣,从我在该主题上看到的各种问题来看。