TitaniumMobile勉強記

Web系エンジニア向けのキャリアアドバイザーやってましたが現在はフリーランスで開発含めて色々やってます。技術ネタとしてはRuby/RailsとJavaScript関連(Node.js、Titanium)あたり

ListViewに配置した特定のラベルの値を更新するやり方

やりたいことの整理

こういうUIがあったとします

f:id:h5y1m141:20131128181313p:plain

任意のセル、仮に上から2番めの「投票する」ボタンをタッチすると、投票用のダイアログが表示されるので、スライダーを任意の値(この場合では7)に設定して投票するボタンをタッチします

f:id:h5y1m141:20131128181409p:plain

すると、こんな感じに上から2番めのスコアーが0だったものが7になる

f:id:h5y1m141:20131128181433p:plain

言うのは簡単なのですが、「ListViewのItemに配置されているLabelの情報ってどうやって更新するんだろ??」という状態をここ数日過ごしていました。

選択されたセクションに対して、updateItemAt()を呼び出してあげればよいみたいで、今後また同じことでハマリりそうなので、自分用のメモとして簡単にでまとめました

実現方法

  • ListViewのitemclickイベントが発火した際に、タッチしたセクション(仮に変数currentSection)とインデックス(仮に変数index)の値を保持しておく。
  • 上記で保持されたセクション箇所をとしますが、item = currentSection.getItemAt(index)としてあげることで、選択された箇所のListItemの情報を変数itemに格納することが出来ます
  • item.xxxx.text = 7 としてあげることで、値が更新されます。なお、xxxxは、ListItemのbindId名を指定します
  • 仕上げに、currentSection.updateItemAt(currentIndex,item)としてあげることで、上記で7というスコアーが反映されたitemで、該当のListItemが更新されます

サンプルソース

作りかけのアプリのソースで、一部コメントアウトとか混じっててあまりよいものではないですが、晒しておきます

class voteWindow
  constructor:() ->
    ActivityIndicator = require("ui/activityIndicator")
    @activityIndicator = new ActivityIndicator()
    
    @baseColor =
      barColor:"#f9f9f9"
      backgroundColor:"#f9f9f9"
      keyColor:"#44A5CB"
      textColor:"#333"      
    @voteWindow = Ti.UI.createWindow
      barColor:@baseColor.barColor
      backgroundColor: @baseColor.backgroundColor
      tabBarHidden:false
      navBarHidden:false
    @voteDialog = @_createVoteDialog()
    @voteWindow.add @voteDialog
    
    voteWindowTitle = Ti.UI.createLabel
      textAlign: 'center'
      color:'#333'
      font:
        fontSize:'18sp'
        fontWeight:'bold'
      text:"投票する"


    @voteWindow.setTitleControl voteWindowTitle
      
    myTemplate =
    childTemplates:[
    #   # teamName
    #   type: "Ti.UI.Label"
    #   bindId:"teamName"
    #   properties:
    #     color: @baseColor.titleColor
    #     font:
    #       fontSize:16
    #       fontWeight:'bold'
    #     width:240
    #     height:20
    #     left:5
    #     top:5
    # ,
    # 
      # title
      type: "Ti.UI.Label"
      bindId:"title"
      properties:
        color: @baseColor.titleColor
        font:
          fontSize:12
        width:150
        height:60
        left:70
        top:5

    ,
      # 投票するボタン
      type: "Ti.UI.Label"
      bindId:"registBtn"
      events:
        click: @_clickEvent
      properties:
        width:50
        height:50
        top:10
        left:10
        backgroundColor:"#4cda64"
        color:@baseColor.barColor
        borderRadius:10
        font:
          fontSize:16
        text:'投票\nする'
        textAlign:"center"
    ,
      # 実際に投票したスコアー
      type: "Ti.UI.Label"
      bindId:"scoreLabel"
      properties:
        width:50
        height:40
        bottom:20
        right:50
        color:"#222"
        font:
          fontSize:36
          fontWeight:"bold"
        textAlign:"right"
    ,
      # スコアー単位
      type: "Ti.UI.Label"
      bindId:"scoreUnit"
      properties:
        width:40
        height:15
        bottom:20
        right:5
        color:"#222"
        font:
          fontSize:12
        text:'/10点'
        textAlign:"left"
          
        
    ]
      
    @listView = Ti.UI.createListView
      top:0
      left:0
      zIndex:1
      templates:
        template: myTemplate
      defaultItemTemplate: "template"

    @listView.addEventListener("refreshstart",(e) =>
      @activityIndicator.show()
      mainController.findEvents((result) =>
        @refresData(result)
        @activityIndicator.hide()

      )

    )

    @listView.addEventListener('itemclick',(e) =>
      index = e.itemIndex
      eventID = e.section.items[index].properties.data.eventID
      currentSection = e.section
      
      # 選択されたアイテム上のスコアー表記をするラベルの値を更新する際に
      # 現在選択されたセクションとインデックスを保持しておかないと更新処理ができないため
      # 以下変数を更新する(初期値はnullを入れてる)

      @voteDialog.eventID = eventID
      @voteDialog.currentSection = currentSection
      @voteDialog.currentIndex = index
      
      Ti.API.info 'vote dialog show'
      @_showDialog(@voteDialog)

    )
    @activityIndicator.show()
    KloudService = require("model/kloudService")
    @kloudService = new KloudService()
    @kloudService.findEvents((result) =>
      @activityIndicator.hide()

      return @_refreshData(result)
    )
    @voteWindow.add @activityIndicator
    @voteWindow.add @listView


    
    return @voteWindow
    
  _refreshData: (data) =>
    sections = []
    teamEastsection = Ti.UI.createListSection
      headerTitle:'東日本チーム'
    teamWestsection = Ti.UI.createListSection
      headerTitle:'西日本チーム'
      
    eastData = []
    westData = []    
    for _items in data
      Ti.API.info _items.photo

      if _items.photo is null or typeof _items.photo is "undefined"
        iconPath = "ui/image/noimageSmall.jpg"
        pictPath = "ui/image/noimage.png"
      else
        iconPath = _items.photo.urls.square_75
        pictPath = _items.photo.urls.small_240
        # pictPath = _items.photo.urls.original
        
      _data =
        eventID   : _items.eventID
        title     : _items.name
        teamName  : _items.teamName
        startTime : _items.start_time
        details   : _items.details
        icon      : iconPath
        pict      : pictPath        
        
      layout =
        properties:
          height:80
          selectionStyle: Titanium.UI.iPhone.ListViewCellSelectionStyle.NONE
          data:_data
          
        title:
          text: _items.name
        teamName:
          text: _items.teamName
        startTime:
          text: _items.start_time
        details:
          text: _items.details
        icon:
          image:iconPath
        scoreLabel:
          text:0

      if _items.teamName is "east"
        eastData.push(layout)
      else if _items.teamName is "west"
        westData.push(layout)
  
    teamEastsection.setItems eastData
    teamWestsection.setItems westData
    # section.setItems dataSet
    # sections.push section

    sections.push teamEastsection
    sections.push teamWestsection

    @listView.setSections sections
    

    return
  _createVoteDialog:() ->
    that = @
    t = Titanium.UI.create2DMatrix().scale(0.0)
    _view = Ti.UI.createView
      width:300
      height:240
      top:0
      left:10
      borderRadius:10
      opacity:0.8
      backgroundColor:@baseColor.textColor
      zIndex:20
      transform:t
      
    registBtn = Ti.UI.createLabel
      width:120
      height:40
      right:20
      bottom:40
      borderRadius:5      
      color:@baseColor.barColor      
      backgroundColor:"#4cda64"
      font:
        fontSize:18
      text:'投票する'
      textAlign:"center"

    registBtn.addEventListener('click',(e) ->
      Ti.API.info "投票start eventID is: #{_view.eventID} score is #{confirmLabel.text}"
      eventID        = _view.eventID
      currentSection = _view.currentSection
      currentIndex   = _view.currentIndex
      score          = confirmLabel.text
      
      KloudService = require("model/kloudService")
      kloudService = new KloudService()
      that.activityIndicator.show()
      kloudService
      kloudService.voteToEvent(eventID,score,(result) ->
        Ti.API.info result
        that.activityIndicator.hide()
        that._hideDialog(that.voteDialog)
        that._refreshScoreLabel(currentSection,currentIndex,score)
        
      )

      

    )
    
    cancelleBtn = Ti.UI.createLabel
      width:120
      height:40
      left:20
      bottom:40
      borderRadius:5
      backgroundColor:"#d8514b"
      color:@baseColor.barColor
      font:
        fontSize:18
        fontFamily :'Rounded M+ 1p'
      text:'投票中止する'
      textAlign:"center"
      
    cancelleBtn.addEventListener('click',(e) ->
      that._hideDialog(_view,Ti.API.info "cancelleBtn hide")
      
    ) 
    confirmLabel = Ti.UI.createLabel
      top:20
      left:100
      textAlign:'center'
      width:100
      height:60
      font:
        fontSize:48
      text:"0"
      color:@baseColor.barColor
      backgroundColor:"#222"
      borderRadius:10
      
    _label = Ti.UI.createLabel
      top:40
      left:210
      textAlign:'left'
      width:100
      height:60
      font:
        fontSize:20
      color:@baseColor.barColor  
      text:"/10点"
      
    scoreSlider = Titanium.UI.createSlider(
      min: 0
      max: 10
      value: 1
      top:100
      width:250
      height: "auto"
    )
    
    scoreSlider.addEventListener("change", (e) ->

      Ti.API.info e.value
      # 小宇宙以下切り捨て
      score = Math.floor(e.value)
      confirmLabel.text = score
    )
    
    _view.add confirmLabel
    _view.add _label
    _view.add scoreSlider
    _view.add cancelleBtn
    _view.add registBtn
    _view.eventID = null
    _view.currentSection = null
    _view.currentIndex = null        
    
    return _view
  # 引数に取ったviewに対してせり出すようにするアニメーションを適用
  _showDialog:(_view) ->
    t1 = Titanium.UI.create2DMatrix()
    t1 = t1.scale(1.0)
    animation = Titanium.UI.createAnimation()
    animation.transform = t1
    animation.duration = 250
    Ti.API.info "_view.eventID: #{_view.eventID}"
    return _view.animate(animation)
    
  # 引数に取ったviewに対してズームインするようなアニメーションを適用
  # することで非表示のように見せる
  _hideDialog:(_view,callback) ->        
    t1 = Titanium.UI.create2DMatrix()
    t1 = t1.scale(0.0)
    animation = Titanium.UI.createAnimation()
    animation.transform = t1
    animation.duration = 250
    _view.animate(animation)
    
    animation.addEventListener('complete',(e) ->
      return callback
    )
  _refreshScoreLabel:(currentSection,currentIndex,score) ->
    Ti.API.info "voteWindow refresh data"
    item = currentSection.getItemAt(currentIndex)
    item.scoreLabel.text = score
    currentSection.updateItemAt(currentIndex,item)
    # @listView.sections[0].updateItemAt(3,item)

    
module.exports = voteWindow