読者です 読者をやめる 読者になる 読者になる

TitaniumMobile勉強記

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

049-エントリ一詳細ページのイベントハンドラの処理その2

Titanium Mobile javascript

Titanium Mobileで開発初めて、関連するエントリについては001から連番ふってきたけど、あと1つで50エントリ。

自分の当初見込みでは30エントリ位でとりあえず形になるものを作る予定だったけど、全然見積もりが甘かったなー

さて、ここから本題。

先月書いたエントリ一詳細ページのイベントハンドラの処理でエントリ詳細ページに画面遷移してからも、ナビゲーションバーに配置した次/前のエントリボタンによりスムーズに画面遷移出来るような機能の実装にとりかかっていることについて触れました。

その際に

エントリ情報の書き換えはTi.UI.createWebView()のhtmlプロパティに値を再度代入すればOKっていうことに気づいたのでこれは意外とか簡単にできましたが、同時にナビゲーションバーに配置したボタンも必要に応じてセットしなおすのがちょっと厄介そうですぐに思いつかなかった。

とナビゲーションバーのボタンの再設定について厄介そうと書いてたのでこれについてもう少し詳しくかいておこうと思います。

実装したい機能

エントリ一覧画面で仮に10エントリ分のタイトルが表示されているとします。

一番最新のエントリをクリックした時にはこういう感じで古いエントリに進むためのボタン(older)を表示したい
iOSシミュレータ
2番目から9番目のエントリをクリックした時には、古いエントリに進むためのボタンだけではなく新しいエントリに進むためのボタン(newer)も表示
iOSシミュレータ
最後のエントリをクリックしたときには、新しいエントリに進むためのボタンのみ表示
iOSシミュレータ

コードと比較しながらもう少し説明

初期化段階の処理:ここは意図したとおりに実装できている

エントリ詳細ページとして、EntrySummaryクラスを作成しており、new EntrySummary()した際に、init()というメソッドを実行してます

init()では

  init:function(){
    var view = this.setWebView(this.title,this.html_body);
    this.first_window.add(view);
    this.handlePage();
    Titanium.UI.currentTab.open(this.first_window,{animated:true});
  },
  handlePage:function(){
    if(this.current_page===1){
      this.firstPage();
    }else if(this.current_page===this.number_of_entry){
      this.lastPage();
    }else{
      this.middlePage();
    }
  }

という感じでsetWebView()という別メソッドを呼び出してWebViewの値をセットして、TI.UI.windowのadd()に渡す。
その後handlePageメソッドを呼び出してエントリ一覧の何番目のエントリがクリックされているか確認した上で表示すべきページを生成して最後に、currentTabに表示してます。

clickイベントでページ&ボタン書き換え処理:ここが一部思ったように動作してない
  • 一番最新のエントリをクリックした時に表示するべきページ→firstPageメソッド
  • 一番最後のエントリをクリックした時に表示するべきページ→lastPageメソッド
  • 2から9番目のエントリをクリックした時に表示するべきページ→middlePageメソッド

という感じで対応させており実際のソースはこんな感じになってます

  firstPage:function(){
    var self = this;
    var webview = null;
    self.button_bar.labels = ['older'];
    self.first_window.setTitleControl(this.button_bar);
    self.button_bar.addEventListener('click',function(e){
      self.handleNaviButton();
      webview = self.olderEntry();
      self.first_window.animate({
      	transition: Titanium.UI.iPhone.AnimationStyle.CURL_UP,
      	view:webview
      });
    });
  },
  lastPage:function(){
    var self = this;
    var webview = null;
    self.button_bar.labels = ['newer'];
    self.first_window.setTitleControl(this.button_bar);
    self.button_bar.addEventListener('click',function(e){
      self.handleNaviButton();
      webview = self.newerEntry();
      self.first_window.animate({
      	transition: Titanium.UI.iPhone.AnimationStyle.CURL_UP,
      	view:webview
      });
    });
  },
  middlePage:function(){
    var self = this;
    var webview = null;
    self.button_bar.labels = ['newer','older'];
    self.first_window.setTitleControl(this.button_bar);
    self.button_bar.addEventListener('click',function(e){
      self.handleNaviButton();
      if (e.index===0){
	webview = self.newerEntry();
      } else {
	webview = self.olderEntry();
      }
      self.first_window.animate({
      	transition: Titanium.UI.iPhone.AnimationStyle.CURL_UP,
      	view:webview
      });
    });
  },
  handleNaviButton:function(){
    if(this.current_page===1){
      this.button_bar.labels = ['older'];
    }else if(this.current_page===this.number_of_entry){
      this.button_bar.labels = ['newer'];
    }else{
      this.button_bar.labels = ['newer','older'];
    }
    this.first_window.setTitleControl(this.button_bar);
  }

基本的にはこれで動作するのですが、例えばこんな時にエラーになってしまい自分が思ったような動きにならずにはまってます。

  1. 2番目から9番目の任意のエントリを表示
  2. newer もしくはolderボタンクリックで画面遷移させる
  3. 一番最初(もしくは最後)のエントリまでたどりついた時に、older(もしくはnewer)ボタンのみ表示される
  4. older(もしくはnewer)ボタンクリック。ここでエラーになる

newerとolderとボタン2つ表示した状態から1つのみの表示にする処理(もしくは1つのみから2つのボタン表示)の処理があやしいので、個々についてもう少し試行錯誤してみます

ソースコード

エントリ詳細情報を表示するクラスはこんな感じになりました。前回書いたやつよりも見通しが良くなったように思うのですが、new EntrySummary()の引数が多いのでここはどうにか出来そうな気がしてます。

EntrySummary = function(title,html_body,permalink,post_date,number_of_entry,current_page){
  this.title = title;
  this.html_body = html_body;
  this.permalink = permalink;
  this.post_date = post_date;
  this.number_of_entry = number_of_entry;
  this.current_page = current_page;
  this.button_bar = Titanium.UI.createButtonBar({
      style:Titanium.UI.iPhone.SystemButtonStyle.BAR
  });
  this.webView =  Ti.UI.createWebView();
  this.first_window = Titanium.UI.createWindow();
  this.init();
};
EntrySummary.prototype = {
  init:function(){
    var view = this.setWebView(this.title,this.html_body);
    this.first_window.add(view);
    this.handlePage();
    Titanium.UI.currentTab.open(this.first_window,{animated:true});
  },
  handlePage:function(){
    if(this.current_page===1){
      this.firstPage();
    }else if(this.current_page===this.number_of_entry){
      this.lastPage();
    }else{
      this.middlePage();
    }
  },
  firstPage:function(){
    var self = this;
    var webview = null;
    self.button_bar.labels = ['older'];
    self.first_window.setTitleControl(this.button_bar);
    self.button_bar.addEventListener('click',function(e){
      Titanium.API.info(e.index);
      self.handleNaviButton();
      webview = self.olderEntry();
      self.first_window.animate({
      	transition: Titanium.UI.iPhone.AnimationStyle.CURL_UP,
      	view:webview
      });
    });
  },
  lastPage:function(){
    var self = this;
    var webview = null;
    self.button_bar.labels = ['newer'];
    self.first_window.setTitleControl(this.button_bar);
    self.button_bar.addEventListener('click',function(e){
      Titanium.API.info(e.index);
      self.handleNaviButton();
      webview = self.newerEntry();
      self.first_window.animate({
      	transition: Titanium.UI.iPhone.AnimationStyle.CURL_UP,
      	view:webview
      });
    });
  },
  middlePage:function(){
    var self = this;
    var webview = null;
    self.button_bar.labels = ['newer','older'];
    self.first_window.setTitleControl(this.button_bar);
    self.button_bar.addEventListener('click',function(e){
      Titanium.API.info(e.index);
      self.handleNaviButton();
      if (e.index===0){
	webview = self.newerEntry();
      } else {
	webview = self.olderEntry();
      }
      self.first_window.animate({
      	transition: Titanium.UI.iPhone.AnimationStyle.CURL_UP,
      	view:webview
      });
    });
  },
  handleNaviButton:function(){
    Titanium.API.info('call handleNaviButton');
    if(this.current_page===1){
      this.button_bar.labels = ['older'];
    }else if(this.current_page===this.number_of_entry){
      this.button_bar.labels = ['newer'];
    }else{
      this.button_bar.labels = ['newer','older'];
    }
    this.first_window.setTitleControl(this.button_bar);
    return true;
  },
  olderEntry:function(){
    var entry = this.searchEntry('next');
    this.post_date = entry[0].post_date;
    this.current_page = this.current_page +1;
    var view = this.setWebView(entry[0].title,entry[0].html_body);
    return view;
  },
  newerEntry:function(){
    var entry = this.searchEntry('before');
    this.post_date = entry[0].post_date;
    this.current_page = this.current_page -1;
    var view = this.setWebView(entry[0].title,entry[0].html_body);
    return view;
  },
  searchEntry:function(param){
    var controller = new Controller('hibi');
    var entry = controller.findOneBy(this.post_date,param);
    return entry;
  },
  setWebView:function(title,html_body){
    var webview =  Ti.UI.createWebView();
    webview.html = '<html><head><title>'
      + title
      + '</title></head>'
      + '<body><h1>'
      + title
      + '</h1><hr />'
      + html_body
      + '</body></html>';
    return webview;
  }
};