アイコンやボタンをタッチした時にTableViewが奥に引っ込むようにアニメーションする方法

レイヤーが重ね合わって、奥行き感を感じさせるようなデザインがiOS7から主流になるっぽいことを考慮してアイコンやボタンをタッチした時にTableViewが奥に引っ込むようにアニメーションというのをTitanium Mobileで作ってみました。

動作イメージが言葉だけで伝わるかどうかわからないので、図にしてみました

![20130724072838.png](https://qiita-image-store.s3.amazonaws.com/0/10187/836232ae-2841-7446-37fc-a7d515ff1e64.png)



## 実装のポイント

自分が考える上では以下2つが実装時のポイントかなと思いました

- 「TableViewが奥に引っ込む」状態というのは、元々のサイズを縮小すれば割りとイメージした形になるかと思います。

- 奥に引っ込んだ状態なので、当然そのTableViewにタッチしても何も反応しないような状態を作りだす必要がある

## TableViewが奥に引っ込む状態を作るのにTitanium.UI.create2DMatrix()を活用する

元々のサイズを縮小させるには、Titanium.UI.create2DMatrix()のscale()メソッドを活用することで実現出来ます。

ソースコードとしてはこのような感じになるかと思います。（CoffeeScriptで書いてます）

```coffeescript:sample.coffee

tableView = Ti.UI.createTableView()
t  = Titanium.UI.create2DMatrix().scale(0.6)
animationForTableView = Titanium.UI.createAnimation()
animationForTableView.transform = t
animationForTableView.duration = 250

tableView.animate(animationForTableView)

```

## TableViewに触れても反応しないようにするために

これは、TableViewのtouchEnabled というプロパティを falseにすることで実現出来ます

ソースコードとしてはこのような感じになるかと思います。（CoffeeScriptで書いてます）

```coffeescript:sample.coffee
tableView = Ti.UI.createTableView()
memoBtn.addEventListener('click',(e)=>
  tableView.touchEnabled = false
)
```

##  ソースコード

今作ってるクラフトビールのアプリで上記の奥に引っ込む動作を実装しており、[GitHub上にソースコード全部あります](https://github.com/h5y1m141/CraftBeerFan)

ただ何処を見ていいのかわからないかと思うので、関連しそうな所を抜粋＆一部修正していかにまとめて見ました。

※  アイコン画像は、Ligature Symbolsというフォントを利用して実現しています。そのため [Titanium Mobileでカスタムフォントを使用する方法](http://blog.livedoor.jp/bsryo/archives/16210552.html)などを参考にして、カスタムフォント利用できるようにする必要あります

### app.coffee

```coffeescript:app.coffee
    tabGroup = Ti.UI.createTabGroup
      tabsBackgroundColor:"#f9f9f9"
      shadowImage:"ui/image/shadowimage.png"
      tabsBackgroundImage:"ui/image/tabbar.png"
      activeTabBackgroundImage:"ui/image/activetab.png"  
      activeTabIconTint:"#fffBD5"

    tabGroup.addEventListener('focus',(e) ->
      tabGroup._activeTab = e.tab
      tabGroup._activeTabIndex = e.index
      if tabGroup._activeTabIndex is -1
        return

      Ti.API._activeTab = tabGroup._activeTab;
      Ti.API.info tabGroup._activeTab
      return
    )
    ListWindow = require("favoriteWindow")
    listWindow = new ListWindow()
    listTab = Titanium.UI.createTab
      window:listWindow
      icon:"ui/image/light_list.png"
    tabGroup.addTab listTab
    tabGroup.open()    

```

### ウィンドウ生成するfavoriteWindow.coffeeのソースコード

```coffeescript:favoriteWindow.coffee
class favoriteWindow
  constructor:() ->
    keyColor = "#f9f9f9"
    @baseColor =
      barColor:keyColor
      backgroundColor:keyColor
    
        
    @favoriteWindow = Ti.UI.createWindow
      title:"お気に入り"
      barColor:@baseColor.barColor
      backgroundColor: @baseColor.backgroundColor
      tabBarHidden:false
      navBarHidden:false
      
    @_createNavbarElement()  
      
    @table = Ti.UI.createTableView
      backgroundColor: @baseColor.backgroundColor
      selectedBackgroundColor:@baseColor.backgroundColor
      style: Titanium.UI.iPhone.TableViewStyle.GROUPED
      width:'auto'
      height:'auto'
      top:0
      left:0


    userID = Ti.App.Properties.getString "currentUserId"
    items = [{"state":"北海道","shopFlg":false,"name":"EL MARQUEZ (エルマルケス）","phone_number":"011-280-0988","address":"札幌市中央区南四条西5","latitude":"43.05546","longitude":"141.351044"},{"state":"青森県","shopFlg":false,"name":"FUSION BAR 3","phone_number":"0178-44-0225","address":"八戸市長横町18","latitude":"40.508695","longitude":"141.492509"},{"state":"岩手県","shopFlg":false,"name":"自家焙煎珈琲＆Bar バロック","phone_number":"090-9842-0739","address":"盛岡市中ノ橋通1-10-5 さかしたビル2F","latitude":"39.699572","longitude":"141.156627"},{"state":"秋田県","shopFlg":false,"name":"Herbal Cafe PRANA","phone_number":"018-863-2286","address":"秋田市泉中央4-14-27","latitude":"39.734687","longitude":"140.116251"}]
    for item in items
      row = @_createShopDataRow(item)
      rows.push(row)
        
      @table.setData rows        

    @favoriteWindow.add @table
    
    # 詳細情報の画面に遷移する
    activeTab = Ti.API._activeTab
    return activeTab.open(@favoriteWindow)
    
  _createNavbarElement:() ->
    backButton = Titanium.UI.createButton
      backgroundImage:"ui/image/backButton.png"
      width:44
      height:44
      
    backButton.addEventListener('click',(e) =>
      return @favoriteWindow.close({animated:true})
    )
    
    @favoriteWindow.leftNavButton = backButton
      
    favoriteWindowTitle = Ti.UI.createLabel
      textAlign: 'center'
      color:'#333'
      font:
        fontSize:18
        fontFamily : 'Rounded M+ 1p'
        fontWeight:'bold'
      text:"お気に入り"
      
    if Ti.Platform.osname is 'iphone'  
      @favoriteWindow.setTitleControl favoriteWindowTitle
      
    return
    
  _createShopDataRow:(placeData) ->
    
    row = Ti.UI.createTableViewRow
      width:'auto'
      height:60
      borderWidth:0
      placeData:placeData
      className:'shopData'
      backgroundColor:@baseColor.barColor
      selectedBackgroundColor:@baseColor.backgroundColor

    titleLabel = Ti.UI.createLabel
      width:200
      height:20
      top:10
      left:50
      color:'#333'
      font:
        fontSize:16
        fontWeight:'bold'
        fontFamily : 'Rounded M+ 1p'
      text:"#{placeData.shopName}"

    row.add titleLabel
    moveNextWindowBtn = Ti.UI.createButton
      top:10
      right:5
      width:40
      height:40
      content:placeData
      selected:false
      backgroundImage:"NONE"
      borderWidth:0
      borderRadius:20
      color:'#bbb'
      font:
        fontSize: 24
        fontFamily:'LigatureSymbols'
      title:String.fromCharCode("0xe112")
      
    moveNextWindowBtn.addEventListener('click',(e) =>

      data =
        shopName:row.placeData.name
        shopAddress:row.placeData.address
        phoneNumber:row.placeData.phone_number
        latitude:row.placeData.latitude
        longitude:row.placeData.longitude
        
      ShopDataDetailWindow = require("ui/shopDataDetailWindow")
      new ShopDataDetailWindow(data)
    )
    row.add moveNextWindowBtn
    leftPostion = [50, 75, 100, 125, 150]
    for i in [0..placeData.rating]
      starIcon = Ti.UI.createButton
        top:30
        left:leftPostion[i]
        width:20
        height:20
        selected:false
        backgroundColor:@baseColor.barColor
        backgroundImage:"NONE"
        borderWidth:0
        borderRadius:5
        color:"#FFEE55"
        font:
          fontSize: 20
          fontFamily:'LigatureSymbols'
        title:String.fromCharCode("0xe121")
      row.add starIcon

    if typeof placeData.content is "undefined" or placeData.content is null
      content = ""
    else
      commentView = @_createCommentView(placeData)
      @favoriteWindow.add commentView
      memoBtn = Ti.UI.createButton
        top:5
        left:5
        width:40
        height:40
        content:placeData
        selected:false
        backgroundImage:"NONE"
        borderWidth:0
        borderRadius:0
        color:'#ccc'
        backgroundColor:@baseColor.barColor
        font:
          fontSize:28
          fontFamily:'LigatureSymbols'
        title:String.fromCharCode("0xe097")
        
      memoBtn.addEventListener('click',(e)=>
        # tableViewは奥の方に下がったように見せたいので少しだけアニメーション
        # させる
        @table.opacity = 0.5
        @table.touchEnabled = false
        t  = Titanium.UI.create2DMatrix().scale(0.6)
        animationForTableView = Titanium.UI.createAnimation()
        animationForTableView.transform = t
        animationForTableView.duration = 250
        @table.animate(animationForTableView)
        
        t1 = Titanium.UI.create2DMatrix()
        t1 = t1.scale(1.0)
        animation = Titanium.UI.createAnimation()
        animation.transform = t1
        animation.duration = 250
        commentView.animate(animation)

      )        
      
      row.add memoBtn


    return row

  _createCommentView:(placeData)->
    content = placeData.content
    t = Titanium.UI.create2DMatrix().scale(0.0)
    
    commentView = Titanium.UI.createScrollView
      width:240
      height:240
      top:20
      left:40
      zIndex:10
      contentWidth:'auto'
      contentHeight:'auto'
      showVerticalScrollIndicator:true
      showHorizontalScrollIndicator:true        
      transform:t
      backgroundColor:@baseColor.barColor
      borderRadius:10
      borderColor:"#ccc"
  
      
    closeBtn = Ti.UI.createButton
      top:5
      right:5
      width:40
      height:40
      content:placeData
      selected:false
      backgroundColor:@baseColor.barColor
      backgroundImage:"NONE"
      borderWidth:0
      borderRadius:5
      color:'#ccc'
      font:
        fontSize: 32
        fontFamily:'LigatureSymbols'
      title:String.fromCharCode("0xe10f")
      
    closeBtn.addEventListener('click',(e) =>
      # tableViewのレイアウトをもとに戻す
      @table.opacity = 1.0
      @table.touchEnabled = true
      t  = Titanium.UI.create2DMatrix().scale(1.0)
      animationForTableView = Titanium.UI.createAnimation()
      animationForTableView.transform = t
      animationForTableView.duration = 250
      @table.animate(animationForTableView)
      
      t2 = Titanium.UI.create2DMatrix()
      t2 = t2.scale(0.0)
      animation = Titanium.UI.createAnimation()
      animation.transform = t2
      animation.duration = 250
      commentView.animate(animation)
          
    )
    commentLabel = Ti.UI.createLabel
      font:
        fontSize:16
        fontFamily:'Rounded M+ 1p'
        fontWeight:'bold'
      text:content
      width:'auto'
      top:50
      left:5
      
    commentView.add commentLabel
    commentView.add closeBtn
    return commentView
module.exports = favoriteWindow  
```